From b819572f5ef836fdbb08266509ffeee8f44d1d40 Mon Sep 17 00:00:00 2001 From: Gerhard Rieger Date: Sun, 27 Jan 2008 13:00:08 +0100 Subject: [PATCH] socat V1.6.0.0 (initial GIT commit) --- BUGREPORTS | 18 + CHANGES | 771 ++++ COPYING | 339 ++ COPYING.OpenSSL | 127 + Config/Makefile.AIX-5-1 | 171 + Config/Makefile.FreeBSD-6-1 | 177 + Config/Makefile.HP-UX-B-11-11 | 177 + Config/Makefile.Linux-2-6-16 | 177 + Config/Makefile.NetBSD-2-0-2 | 171 + Config/Makefile.OpenBSD-3-8 | 171 + Config/Makefile.SunOS-5-8 | 177 + Config/Makefile.Tru64-5-1B | 171 + Config/config.AIX-5-1.h | 450 ++ Config/config.FreeBSD-6-1.h | 485 ++ Config/config.HP-UX-B-11-11.h | 485 ++ Config/config.Linux-2-6-16.h | 485 ++ Config/config.NetBSD-2-0-2.h | 450 ++ Config/config.OpenBSD-3-8.h | 450 ++ Config/config.SunOS-5-8.h | 485 ++ Config/config.Tru64-5-1B.h | 450 ++ DEVELOPMENT | 205 + EXAMPLES | 326 ++ FAQ | 85 + FILES | 82 + Makefile.in | 177 + PORTING | 72 + README | 272 ++ README.FIPS | 67 + SECURITY | 41 + VERSION | 1 + compat.h | 640 +++ config.h.in | 484 ++ configure.in | 1459 ++++++ daemon.sh | 34 + dalan.c | 224 + dalan.h | 30 + doc/dest-unreach.css | 15 + doc/socat-multicast.html | 340 ++ doc/socat-openssltunnel.html | 192 + doc/socat-tun.html | 165 + doc/socat.1 | 2877 ++++++++++++ doc/socat.html | 2686 ++++++++++++ doc/socat.yo | 3026 +++++++++++++ doc/xio.help | 4959 +++++++++++++++++++++ error.c | 249 ++ error.h | 208 + fdname.c | 327 ++ filan.c | 918 ++++ filan.h | 38 + filan_main.c | 240 + ftp.sh | 158 + gatherinfo.sh | 172 + hostan.c | 82 + hostan.h | 10 + install-sh | 250 ++ mail.sh | 71 + mytypes.h | 17 + nestlex.c | 237 + nestlex.h | 23 + procan.c | 169 + procan.h | 10 + procan_main.c | 94 + proxy.sh | 76 + proxyecho.sh | 59 + readline-test.sh | 46 + readline.sh | 30 + socat.c | 1370 ++++++ socat.spec | 52 + socks4a-echo.sh | 114 + socks4echo.sh | 101 + sslcls.c | 318 ++ sslcls.h | 102 + sycls.c | 1503 +++++++ sycls.h | 270 ++ sysincludes.h | 161 + sysutils.c | 495 +++ sysutils.h | 98 + test.sh | 7790 +++++++++++++++++++++++++++++++++ testcert.conf | 9 + utils.c | 147 + utils.h | 68 + xio-ascii.c | 107 + xio-ascii.h | 20 + xio-creat.c | 79 + xio-creat.h | 10 + xio-exec.c | 137 + xio-exec.h | 12 + xio-ext2.c | 91 + xio-ext2.h | 21 + xio-fd.c | 77 + xio-fd.h | 41 + xio-fdnum.c | 78 + xio-fdnum.h | 12 + xio-file.c | 124 + xio-file.h | 31 + xio-gopen.c | 218 + xio-gopen.h | 10 + xio-ip.c | 510 +++ xio-ip.h | 48 + xio-ip4.c | 46 + xio-ip4.h | 13 + xio-ip6.c | 145 + xio-ip6.h | 22 + xio-ipapp.c | 298 ++ xio-ipapp.h | 48 + xio-listen.c | 333 ++ xio-listen.h | 21 + xio-named.c | 216 + xio-named.h | 26 + xio-openssl.c | 1155 +++++ xio-openssl.h | 52 + xio-pipe.c | 177 + xio-pipe.h | 12 + xio-process.c | 70 + xio-process.h | 31 + xio-progcall.c | 618 +++ xio-progcall.h | 28 + xio-proxy.c | 561 +++ xio-proxy.h | 30 + xio-pty.c | 212 + xio-pty.h | 16 + xio-rawip.c | 303 ++ xio-rawip.h | 21 + xio-readline.c | 244 ++ xio-readline.h | 17 + xio-socket.c | 1091 +++++ xio-socket.h | 90 + xio-socks.c | 430 ++ xio-socks.h | 37 + xio-stdio.c | 150 + xio-stdio.h | 17 + xio-system.c | 65 + xio-system.h | 10 + xio-tcp.c | 119 + xio-tcp.h | 42 + xio-tcpwrap.c | 165 + xio-tcpwrap.h | 22 + xio-termios.c | 326 ++ xio-termios.h | 147 + xio-tun.c | 209 + xio-tun.h | 33 + xio-udp.c | 608 +++ xio-udp.h | 32 + xio-unix.c | 738 ++++ xio-unix.h | 29 + xio.h | 404 ++ xioclose.c | 118 + xioconfig.h | 119 + xiodiag.c | 21 + xiodiag.h | 11 + xioexit.c | 21 + xiohelp.c | 168 + xiohelp.h | 12 + xioinitialize.c | 187 + xiolayer.c | 25 + xiolayer.h | 18 + xiolockfile.c | 118 + xiolockfile.h | 17 + xiomodes.h | 45 + xioopen.c | 533 +++ xioopen.h | 94 + xioopts.c | 3732 ++++++++++++++++ xioopts.h | 872 ++++ xioparam.c | 67 + xioread.c | 401 ++ xioshutdown.c | 134 + xiosigchld.c | 159 + xiosignal.c | 107 + xiosysincludes.h | 13 + xiowrite.c | 168 + 170 files changed, 59193 insertions(+) create mode 100644 BUGREPORTS create mode 100644 CHANGES create mode 100644 COPYING create mode 100644 COPYING.OpenSSL create mode 100644 Config/Makefile.AIX-5-1 create mode 100644 Config/Makefile.FreeBSD-6-1 create mode 100644 Config/Makefile.HP-UX-B-11-11 create mode 100644 Config/Makefile.Linux-2-6-16 create mode 100644 Config/Makefile.NetBSD-2-0-2 create mode 100644 Config/Makefile.OpenBSD-3-8 create mode 100644 Config/Makefile.SunOS-5-8 create mode 100644 Config/Makefile.Tru64-5-1B create mode 100644 Config/config.AIX-5-1.h create mode 100644 Config/config.FreeBSD-6-1.h create mode 100644 Config/config.HP-UX-B-11-11.h create mode 100644 Config/config.Linux-2-6-16.h create mode 100644 Config/config.NetBSD-2-0-2.h create mode 100644 Config/config.OpenBSD-3-8.h create mode 100644 Config/config.SunOS-5-8.h create mode 100644 Config/config.Tru64-5-1B.h create mode 100644 DEVELOPMENT create mode 100644 EXAMPLES create mode 100644 FAQ create mode 100644 FILES create mode 100644 Makefile.in create mode 100644 PORTING create mode 100644 README create mode 100644 README.FIPS create mode 100644 SECURITY create mode 100644 VERSION create mode 100644 compat.h create mode 100644 config.h.in create mode 100644 configure.in create mode 100755 daemon.sh create mode 100644 dalan.c create mode 100644 dalan.h create mode 100644 doc/dest-unreach.css create mode 100644 doc/socat-multicast.html create mode 100644 doc/socat-openssltunnel.html create mode 100644 doc/socat-tun.html create mode 100644 doc/socat.1 create mode 100644 doc/socat.html create mode 100644 doc/socat.yo create mode 100644 doc/xio.help create mode 100644 error.c create mode 100644 error.h create mode 100644 fdname.c create mode 100644 filan.c create mode 100644 filan.h create mode 100644 filan_main.c create mode 100755 ftp.sh create mode 100755 gatherinfo.sh create mode 100644 hostan.c create mode 100644 hostan.h create mode 100755 install-sh create mode 100755 mail.sh create mode 100644 mytypes.h create mode 100644 nestlex.c create mode 100644 nestlex.h create mode 100644 procan.c create mode 100644 procan.h create mode 100644 procan_main.c create mode 100755 proxy.sh create mode 100755 proxyecho.sh create mode 100755 readline-test.sh create mode 100755 readline.sh create mode 100644 socat.c create mode 100644 socat.spec create mode 100755 socks4a-echo.sh create mode 100755 socks4echo.sh create mode 100644 sslcls.c create mode 100644 sslcls.h create mode 100644 sycls.c create mode 100644 sycls.h create mode 100644 sysincludes.h create mode 100644 sysutils.c create mode 100644 sysutils.h create mode 100755 test.sh create mode 100644 testcert.conf create mode 100644 utils.c create mode 100644 utils.h create mode 100644 xio-ascii.c create mode 100644 xio-ascii.h create mode 100644 xio-creat.c create mode 100644 xio-creat.h create mode 100644 xio-exec.c create mode 100644 xio-exec.h create mode 100644 xio-ext2.c create mode 100644 xio-ext2.h create mode 100644 xio-fd.c create mode 100644 xio-fd.h create mode 100644 xio-fdnum.c create mode 100644 xio-fdnum.h create mode 100644 xio-file.c create mode 100644 xio-file.h create mode 100644 xio-gopen.c create mode 100644 xio-gopen.h create mode 100644 xio-ip.c create mode 100644 xio-ip.h create mode 100644 xio-ip4.c create mode 100644 xio-ip4.h create mode 100644 xio-ip6.c create mode 100644 xio-ip6.h create mode 100644 xio-ipapp.c create mode 100644 xio-ipapp.h create mode 100644 xio-listen.c create mode 100644 xio-listen.h create mode 100644 xio-named.c create mode 100644 xio-named.h create mode 100644 xio-openssl.c create mode 100644 xio-openssl.h create mode 100644 xio-pipe.c create mode 100644 xio-pipe.h create mode 100644 xio-process.c create mode 100644 xio-process.h create mode 100644 xio-progcall.c create mode 100644 xio-progcall.h create mode 100644 xio-proxy.c create mode 100644 xio-proxy.h create mode 100644 xio-pty.c create mode 100644 xio-pty.h create mode 100644 xio-rawip.c create mode 100644 xio-rawip.h create mode 100644 xio-readline.c create mode 100644 xio-readline.h create mode 100644 xio-socket.c create mode 100644 xio-socket.h create mode 100644 xio-socks.c create mode 100644 xio-socks.h create mode 100644 xio-stdio.c create mode 100644 xio-stdio.h create mode 100644 xio-system.c create mode 100644 xio-system.h create mode 100644 xio-tcp.c create mode 100644 xio-tcp.h create mode 100644 xio-tcpwrap.c create mode 100644 xio-tcpwrap.h create mode 100644 xio-termios.c create mode 100644 xio-termios.h create mode 100644 xio-tun.c create mode 100644 xio-tun.h create mode 100644 xio-udp.c create mode 100644 xio-udp.h create mode 100644 xio-unix.c create mode 100644 xio-unix.h create mode 100644 xio.h create mode 100644 xioclose.c create mode 100644 xioconfig.h create mode 100644 xiodiag.c create mode 100644 xiodiag.h create mode 100644 xioexit.c create mode 100644 xiohelp.c create mode 100644 xiohelp.h create mode 100644 xioinitialize.c create mode 100644 xiolayer.c create mode 100644 xiolayer.h create mode 100644 xiolockfile.c create mode 100644 xiolockfile.h create mode 100644 xiomodes.h create mode 100644 xioopen.c create mode 100644 xioopen.h create mode 100644 xioopts.c create mode 100644 xioopts.h create mode 100644 xioparam.c create mode 100644 xioread.c create mode 100644 xioshutdown.c create mode 100644 xiosigchld.c create mode 100644 xiosignal.c create mode 100644 xiosysincludes.h create mode 100644 xiowrite.c diff --git a/BUGREPORTS b/BUGREPORTS new file mode 100644 index 0000000..eaf9cf8 --- /dev/null +++ b/BUGREPORTS @@ -0,0 +1,18 @@ + +* If you have found a bug, i.e. socat SIGSEGV'ed, terminated abnormally without +error message, did not comply to the documentation, or behaves different from +your expectations, please send the following infos to socat@dest-unreach.org, +as available: +. output of "make info" in socat.out (you may remove the hostname in the first +line to keep your privacy) +. config.log +. run your example with "socat -d -d -d -d -D ..." options, and include the log +output +. describe what you've done, and why you think socat did wrong + +* If you fixed a bug: +Please do as described in the above paragraph, and include the modified files +(or a patch file) + +* If you have contributions, problems etc: send available info and a +description to the above address. diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..8148136 --- /dev/null +++ b/CHANGES @@ -0,0 +1,771 @@ + +####################### V 1.6.0.0: + +new features: + new addresses IP-DATAGRAM and UDP-DATAGRAM allow versatile broadcast + and multicast modes + + new option ip-add-membership for control of multicast group membership + + new address TUN for generation of Linux TUN/TAP pseudo network + interfaces (suggested by Mat Caughron); associated options tun-device, + tun-name, tun-type; iff-up, iff-promisc, iff-noarp, iff-no-pi etc. + + new addresses ABSTRACT-CONNECT, ABSTRACT-LISTEN, ABSTRACT-SENDTO, + ABSTRACT-RECV, and ABSTRACT-RECVFROM for abstract UNIX domain addresses + on Linux (requested by Zeeshan Ali); option unix-tightsocklen controls + socklen parameter on system calls. + + option end-close for control of connection closing allows FD sharing + by sub processes + + range option supports form address:mask with IPv4 + + changed behaviour of SSL-LISTEN to require and verify client + certificate per default + + options f-setlkw-rd, f-setlkw-wr, f-setlk-rd, f-setlk-wr allow finer + grained locking on regular files + + uninstall target in Makefile (lack reported by Zeeshan Ali) + +corrections: + fixed bug where only first tcpwrap option was applied; fixed bug where + tcpwrap IPv6 check always failed (thanks to Rudolf Cejka for reporting + and fixing this bug) + + filan (and socat -D) could hang when a socket was involved + + corrected PTYs on HP-UX (and maybe others) using STREAMS (inspired by + Roberto Mackun) + + correct bind with udp6-listen (thanks to Jan Horak for reporting this + bug) + + corrected filan.c peekbuff[0] which did not compile with Sun Studio Pro + (thanks to Leo Zhadanovsky for reporting this problem) + + corrected problem with read data buffered in OpenSSL layer (thanks to + Jon Nelson for reporting this bug) + + corrected problem with option readbytes when input stream stayed idle + after so many bytes + + fixed a bug where a datagram receiver with option fork could fork two + sub processes per packet + +further changes: + moved documentation to new doc/ subdir + + new documents (kind of mini tutorials) are provided in doc/ + +####################### V 1.5.0.0: + +new features: + new datagram modes for udp, rawip, unix domain sockets + + socat option -T specifies inactivity timeout + + rewrote lexical analysis to allow nested socat calls + + addresses tcp, udp, tcp-l, udp-l, and rawip now support IPv4 and IPv6 + + socat options -4, -6 and environment variables SOCAT_DEFAULT_LISTEN_IP, + SOCAT_PREFERRED_RESOLVE_IP for control of protocol selection + + addresses ssl, ssl-l, socks, proxy now support IPv4 and IPv6 + + option protocol-family (pf), esp. for openssl-listen + + range option supports IPv6 - syntax: range=[::1/128] + + option ipv6-v6only (ipv6only) + + new tcp-wrappers options allow-table, deny-table, tcpwrap-etc + + FIPS version of OpenSSL can be integrated - initial patch provided by + David Acker. See README.FIPS + + support for resolver options res-debug, aaonly, usevc, primary, igntc, + recurse, defnames, stayopen, dnsrch + + options for file attributes on advanced filesystems (ext2, ext3, + reiser): secrm, unrm, compr, ext2-sync, immutable, ext2-append, nodump, + ext2-noatime, journal-data etc. + + option cool-write controls severeness of write failure (EPIPE, + ECONNRESET) + + option o-noatime + + socat option -lh for hostname in log output + + traffic dumping provides packet headers + + configure.in became part of distribution + + socats unpack directory now has full version, e.g. socat-1.5.0.0/ + + corrected docu of option verify + +corrections: + fixed tcpwrappers integration - initial fix provided by Rudolf Cejka + + exec with pipes,stderr produced error + + setuid-early was ignored with many address types + + some minor corrections + +####################### V 1.4.3.1: + +corrections: + PROBLEM: UNIX socket listen accepted only one (or a few) connections. + FIX: do not remove listening UNIX socket in child process + + PROBLEM: SIGSEGV when TCP part of SSL connect failed + FIX: check ssl pointer before calling SSL_shutdown + + In debug mode, show connect client port even when connect fails + +####################### V 1.4.3.0: + +new features: + socat options -L, -W for application level locking + + options "lockfile", "waitlock" for address level locking + (Stefan Luethje) + + option "readbytes" limits read length (Adam Osuchowski) + + option "retry" for unix-connect, unix-listen, tcp6-listen (Dale Dude) + + pty symlink, unix listen socket, and named pipe are per default removed + after use; option unlink-close overrides this new behaviour and also + controls removal of other socat generated files (Stefan Luethje) + +corrections: + option "retry" did not work with tcp-listen + + EPIPE condition could result in a 100% CPU loop + +further changes: + support systems without SHUT_RD etc. + handle more size_t types + try to find makedepend options with gcc 3 (richard/OpenMacNews) + +####################### V 1.4.2.0: + +new features: + option "connect-timeout" limits wait time for connect operations + (requested by Giulio Orsero) + + option "dhparam" for explicit Diffie-Hellman parameter file + +corrections: + support for OpenSSL DSA certificates (Miika Komu) + + create install directories before copying files (Miika Komu) + + when exiting on signal, return status 128+signum instead of 1 + + on EPIPE and ECONNRESET, only issue a warning (Santiago Garcia + Mantinan) + + -lu could cause a core dump on long messages + +further changes: + modifications to simplify using socats features in applications + +####################### V 1.4.1.0: + +new features: + option "wait-slave" blocks open of pty master side until a client + connects, "pty-intervall" controls polling + + option -h as synonym to -? for help (contributed by Christian + Lademann) + + filan prints formatted time stamps and rdev (disable with -r) + + redirect filan's output, so stdout is not affected (contributed by + Luigi Iotti) + + filan option -L to follow symbolic links + + filan shows termios control characters + +corrections: + proxy address no longer performs unsolicited retries + + filan -f no longer needs read permission to analyze a file (but still + needs access permission to directory, of course) + +porting: + Option dsusp + FreeBSD options noopt, nopush, md5sig + OpenBSD options sack-disable, signature-enable + HP-UX, Solaris options abort-threshold, conn-abort-threshold + HP-UX options b900, b3600, b7200 + Tru64/OSF1 options keepinit, paws, sackena, tsoptena + +further corrections: + address pty now uses ptmx as default if openpty is also available + +####################### V 1.4.0.3: + +corrections: + fix to a syslog() based format string vulnerability that can lead to + remote code execution. See advisory socat-adv-1.txt + +####################### V 1.4.0.2: + +corrections: + exec'd write-only addresses get a chance to flush before being killed + + error handler: print notice on error-exit + + filan printed wrong file type information + +####################### V 1.4.0.1: + +corrections: + socks4a constructed invalid header. Problem found, reported, and fixed + by Thomas Themel, by Peter Palfrader, and by rik + + with nofork, don't forget to apply some process related options + (chroot, setsid, setpgid, ...) + +####################### V 1.4.0.0: + +new features: + simple openssl server (ssl-l), experimental openssl trust + + new options "cafile", "capath", "key", "cert", "egd", and "pseudo" for + openssl + + new options "retry", "forever", and "intervall" + + option "fork" for address TCP improves `gender changer´ + + options "sigint", "sigquit", and "sighup" control passing of signals to + sub process (thanks to David Shea who contributed to this issue) + + readline takes respect to the prompt issued by the peer address + + options "prompt" and "noprompt" allow to override readline's new + default behaviour + + readline supports invisible password with option "noecho" + + socat option -lp allows to set hostname in log output + + socat option -lu turns on microsecond resolution in log output + + +corrections: + before reading available data, check if writing on other channel is + possible + + tcp6, udp6: support hostname specification (not only IP address), and + map IP4 names to IP6 addresses + + openssl client checks server certificate per default + + support unidirectional communication with exec/system subprocess + + try to restore original terminal settings when terminating + + test.sh uses tmp dir /tmp/$USER/$$ instead of /tmp/$$ + + socks4 failed on platforms where long does not have 32 bits + (thanks to Peter Palfrader and Thomas Seyrat) + + hstrerror substitute wrote wrong messages (HP-UX, Solaris) + + proxy error message was truncated when answer contained multiple spaces + + +porting: + compiles with AIX xlc, HP-UX cc, Tru64 cc (but might not link) + +####################### V 1.3.2.2: + +corrections: + PROXY CONNECT failed when the status reply from the proxy server + contained more than one consecutive spaces. Problem reported by + Alexandre Bezroutchko + + do not SIGSEGV when proxy address fails to resolve server name + + udp-listen failed on systems where AF_INET != SOCK_DGRAM (e.g. SunOS). + Problem reported by Christoph Schittel + + test.sh only tests available features + + added missing IP and TCP options in filan analyzer + + do not apply stdio address options to both directions when in + unidirectional mode + + on systems lacking /dev/*random and egd, provide (weak) entropy from + libc random() + + +porting: + changes for HP-UX (VREPRINT, h_NETDB_INTERNAL) + + compiles on True64, FreeBSD (again), NetBSD, OpenBSD + + support for long long as st_ino type (Cygwin 1.5) + + compile on systems where pty can not be featured + +####################### V 1.3.2.1: + +corrections: + "final" solution for the ENOCHLD problem + + corrected "make strip" + + default gcc debug/opt is "-O" again + + check for /proc at runtime, even if configure found it + + src.rpm accidently supported SuSE instead of RedHat + +####################### V 1.3.2.0: + +new features: + option "nofork" connects an exec'd script or program directly + to the file descriptors of the other address, circumventing the socat + transfer engine + + support for files >2GB, using ftruncate64(), lseek64(), stat64() + + filan has new "simple" output style (filan -s) + + +porting: + options "binary" and "text" for controlling line termination on Cygwin + file system access (hint from Yang Wu-Zhou) + + fix by Yang Wu-Zhou for the Cygwin "No Children" problem + + improved support for OSR: _SVID3; no IS_SOCK, no F_GETOWN (thanks to + John DuBois) + + minor corrections to avoid warnings with gcc 3 + + +further corrections and minor improvements: + configure script is generated with autoconf 2.57 (no longer 2.52) + + configure passes CFLAGS to Makefile + + option -??? for complete list of address options and their short forms + + program name in syslog messages is derived from argv[0] + + SIGHUP now prints notice instead of error + + EIO during read of pty now gives Notice instead of Error, and + triggers EOF + + use of hstrerror() for printing resolver error messages + + setgrent() got required endgrent() + +####################### V 1.3.1.0: + +new features: + integration of Wietse Venema's tcpwrapper library (libwrap) + + with "proxy" address, option "resolve" controls if hostname or IP + address is sent in request + + option "lowport" establishes limited authorization for TCP and UDP + connections + + improvement of .spec file for RPM creation (thanks to Gerd v. Egidy) + An accompanying change in the numbering scheme results in an + incompatibility with earlier socat RPMs! + + +solved problems and bugs: + PROBLEM: socat daemon terminated when the address of a connecting + client did not match range option value instead of continue listening + SOLVED: in this case, print warning instead of error to keep daemon + active + + PROBLEM: tcp-listen with fork sometimes left excessive number of zombie + processes + SOLVED: dont assume that each exiting child process generates SIGCHLD + + when converting CRNL to CR, socat converted to NL + + +further corrections: + configure script now disables features that depend on missing files + making it more robust in "unsupported" environments + + server.pem permissions corrected to 600 + + "make install" now does not strip; use "make strip; make install" + if you like strip (suggested by Peter Bray) + +####################### V 1.3.0.1: + +solved problems and bugs: + PROBLEM: OPENSSL did not apply tcp, ip, and socket options + SOLVED: OPENSSL now correctly handles the options list + + PROBLEM: CRNL to NL and CRNL to CR conversions failed when CRNL crossed + block boundary + SOLVED: these conversions now simply strip all CR's or NL's from input + stream + + +porting: + SunOS ptys now work on x86, too (thanks to Peter Bray) + + configure looks for freeware libs in /pkgs/lib/ (thanks to Peter Bray) + + +further corrections: + added WITH_PROXY value to -V output + + added compile dependencies of WITH_PTY and WITH_PROXY + + -?? did not print option group of proxy options + + corrected syntax for bind option in docu + + corrected an issue with stdio in unidirectional mode + + options socksport and proxyport support service names + + ftp.sh script supports proxy address + + man page no longer installed with execute permissions (thanks to Peter + Bray) + + fixed a malloc call bug that could cause SIGSEGV or false "out of + memory" errors on EXEC and SYSTEM, depending on program name length and + libc. + +####################### V 1.3.0.0: + +new features: + proxy connect with optional proxy authentication + + combined hex and text dump mode, credits to Gregory Margo + + address pty applies options user, group, and perm to device + + +solved problems and bugs: + PROBLEM: option reuseport was not applied (BSD, AIX) + SOLVED: option reuseport now in phase PASTSOCKET instead of PREBIND, + credits to Jean-Baptiste Marchand + + PROBLEM: ignoreeof with stdio was ignored + SOLVED: ignoreeof now works correctly with address stdio + + PROBLEM: ftp.sh did not use user supplied password + SOLVED: ftp.sh now correctly passes password from command line + + PROBLEM: server.pem had expired + SOLVED: new server.pem valid for ten years + + PROBLEM: socks notice printed wrong port on some platforms + SOLVED: socks now uses correct byte-order for port number in notice + + +further corrections: + option name o_trunc corrected to o-trunc + + combined use of -u and -U is now detected and prevented + + made message system a little more robust against format string attacks + + +####################### V 1.2.0.0: + +new features: + address pty for putting socat behind a new pseudo terminal that may + fake a serial line, modem etc. + + experimental openssl integration + (it does not provide any trust between the peers because is does not + check certificates!) + + options flock-ex, flock-ex-nb, flock-sh, flock-sh-nb to control all + locking mechanism provided by flock() + + options setsid and setpgid now available with all address types + + option ctty (controlling terminal) now available for all TERMIOS + addresses + + option truncate (a hybrid of open(.., O_TRUNC) and ftruncate()) is + replaced by options o-trunc and ftruncate=offset + + option sourceport now available with TCP and UDP listen addresses to + restrict incoming client connections + + unidirectional mode right-to-left (-U) + + +solved problems and bugs: + PROBLEM: addresses without required parameters but an option containing + a '/' were incorrectly interpreted as implicit GOPEN address + SOLVED: if an address does not have ':' separator but contains '/', + check if the slash is before the first ',' before assuming + implicit GOPEN. + + +porting: + ptys under SunOS work now due to use of stream options + + +further corrections: + with -d -d -d -d -D, don't print debug info during file analysis + + +####################### V 1.1.0.1: + +new features: + .spec file for RPM generation + + +solved problems and bugs: + PROBLEM: GOPEN on socket did not apply option unlink-late + SOLUTION: GOPEN for socket now applies group NAMED, phase PASTOPEN + options + + PROBLEM: with unidirectional mode, an unnecessary close timeout was + applied + SOLUTION: in unidirectional mode, terminate without wait time + + PROBLEM: using GOPEN on a unix domain socket failed for datagram + sockets + SOLUTION: when connect() fails with EPROTOTYPE, use a datagram socket + + +further corrections: + + open() flag options had names starting with "o_", now corrected to "o-" + + in docu, *-listen addresses were called *_listen + + address unix now called unix-connect because it does not handle unix + datagram sockets + + in test.sh, apply global command line options with all tests + + +####################### V 1.1.0.0: + +new features: + regular man page and html doc - thanks to kromJx for prototype + + new address type "readline", utilizing GNU readline and history libs + + address option "history-file" for readline + + new option "dash" to "exec" address that allows to start login shells + + syslog facility can be set per command line option + + new address option "tcp-quickack", found in Linux 2.4 + + option -g prevents option group checking + + filan and procan can print usage + + procan prints rlimit infos + + +solved problems and bugs: + PROBLEM: raw IP socket SIGSEGV'ed when it had been shut down. + SOLVED: set eof flag of channel on shutdown. + + PROBLEM: if channel 2 uses a single non-socket FD in bidirectional mode + and has data available while channel 1 reaches EOF, the data is + lost. + SOLVED: during one loop run, first handle all data transfers and + _afterwards_ handle EOF. + + PROBLEM: despite to option NONBLOCK, the connect() call blocked + SOLVED: option NONBLOCK is now applied in phase FD instead of LATE + + PROBLEM: UNLINK options issued error when file did not exist, + terminating socat + SOLVED: failure of unlink() is only warning if errno==ENOENT + + PROBLEM: TCP6-LISTEN required numeric port specification + 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 + + PROBLEM: using address EXEC against an address with IGNOREEOF, socat + never terminated + SOLVED: corrected EOF handling of sigchld + + +porting: + MacOS and old AIX versions now have pty + + flock() now available on Linux (configure check was wrong) + + named pipe were generated using mknod(), which requires root under BSD + now they are generated using mkfifo + + +further corrections: + lots of address options that were "forgotten" at runtime are now + available + + option BINDTODEVICE now also called SO-BINDTODEVICE, IF + + "make install" now installs binaries with ownership 0:0 + + +####################### V 1.0.4.2: + +solved problems and bugs: + PROBLEM: EOF of one stream caused close of other stream, giving it no + chance to go down regularly + SOLVED: EOF of one stream now causes shutdown of write part of other + stream + + PROBLEM: sending mail via socks address to qmail showed that crlf + option does not work + SOLVED: socks address applies PH_LATE options + + PROBLEM: in debug mode, no info about socat and platform was issued + SOLVED: print socat version and uname output in debug mode + + PROBLEM: invoking socat with -t and no following parameters caused + SIGSEGV + SOLVED: -t and -b now check next argv entry + + PROBLEM: when opening of logfile (-lf) failed, no error was reported + and no further messages were printed + SOLVED: check result of fopen and print error message if it failed + +new features: + address type UDP-LISTEN now supports option fork: it internally applies + socket option SO_REUSEADDR so a new UDP socket can bind to port after + `accepting´ a connection (child processes might live forever though) + (suggestion from Damjan Lango) + + +####################### V 1.0.4.1: + +solved problems and bugs: + PROB: assert in libc caused an endless recursion + SOLVED: no longer catch SIGABRT + + PROB: socat printed wrong verbose prefix for "right to left" packets + SOLVED: new parameter for xiotransfer() passes correct prefix + +new features: + in debug mode, socat prints its command line arguments + in verbose mode, escape special characters and replace unprintables + with '.'. Patch from Adrian Thurston. + + +####################### V 1.0.4.0: + +solved problems and bugs: + Debug output for lstat and fstat said "stat" + +further corrections: + FreeBSD now includes libutil.h + +new features: + option setsid with exec/pty + option setpgid with exec/pty + option ctty with exec/pty + TCP V6 connect test + gettimeofday in sycls.c (no use yet) + +porting: + before Gethostbyname, invoke inet_aton for MacOSX + + +####################### V 1.0.3.0: + +solved problems and bugs: + + PROB: test 9 of test.sh (echo via file) failed on some platforms, + socat exited without error message + SOLVED: _xioopen_named_early(): preset statbuf.st_mode with 0 + + PROB: test 17 hung forever + REASON: child death before select loop did not result in EOF + SOLVED: check of existence of children before starting select loop + + PROB: test 17 failed + REASON: child dead triggered EOF before last data was read + SOLVED: after child death, read last data before setting EOF + + PROB: filan showed that exec processes incorrectly had fd3 open + REASON: inherited open fd3 from main process + SOLVED: set CLOEXEC flag on pty fd in main process + + PROB: help printed "undef" instead of group "FORK" + SOLVED: added "FORK" to group name array + + PROB: fatal messages did not include severity classifier + SOLVED: added "F" to severity classifier array + + PROB: IP6 addresses where printed incorrectly + SOLVED: removed type casts to unsigned short * + +further corrections: + socat catches illegal -l modes + corrected error message on setsockopt(linger) + option tabdly is of type uint + correction for UDP over IP6 + more cpp conditionals, esp. for IP6 situations + better handling of group NAMED options with listening UNIX sockets + applyopts2 now includes last given phase + corrected option group handling for most address types + introduce dropping of unappliable options (dropopts, dropopts2) + gopen now accepts socket and unix-socket options + exec and system now accept all socket and termios options + child process for exec and system addresses with option pty + improved descriptions and options for EXAMPLES + printf format for file mode changed to "0%03o" with length spec. + added va_end() in branch of msg() + changed phase of lock options from PASTOPEN to FD + support up to four early dying processes + +structural changes: + xiosysincludes now includes sysincludes.h for non xio files + +new features: + option umask + CHANGES file + TYPE_DOUBLE, u_double + OFUNC_OFFSET + added getsid(), setsid(), send() to sycls + procan prints sid (session id) + mail.sh gets -f (from) option + new EXAMPLEs for file creation + gatherinfo.sh now tells about failures + test.sh can check for much more address/option combinations + +porting: + ispeed, ospeed for termios on FreeBSD + getpgid() conditional for MacOS 10 + added ranlib in Makefile.in for MacOS 10 + disable pty option if no pty mechanism is available (MacOS 10) + now compiles and runs on MacOS 10 (still some tests fail) + setgroups() conditional for cygwin + sighandler_t defined conditionally + use gcc option -D_GNU_SOURCE diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..e77696a --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/COPYING.OpenSSL b/COPYING.OpenSSL new file mode 100644 index 0000000..7b93e0d --- /dev/null +++ b/COPYING.OpenSSL @@ -0,0 +1,127 @@ + + LICENSE ISSUES + ============== + + The OpenSSL toolkit stays under a dual license, i.e. both the conditions of + the OpenSSL License and the original SSLeay license apply to the toolkit. + See below for the actual license texts. Actually both licenses are BSD-style + Open Source licenses. In case of any license issues related to OpenSSL + please contact openssl-core@openssl.org. + + OpenSSL License + --------------- + +/* ==================================================================== + * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + + Original SSLeay License + ----------------------- + +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + diff --git a/Config/Makefile.AIX-5-1 b/Config/Makefile.AIX-5-1 new file mode 100644 index 0000000..906b044 --- /dev/null +++ b/Config/Makefile.AIX-5-1 @@ -0,0 +1,171 @@ +# $Id: Makefile.AIX-5-1,v 1.16 2006/07/13 21:29:05 gerhard Exp $ +# Copyright Gerhard Rieger 2001-2006 +# Published under the GNU General Public License V.2, see file COPYING + +# note: @...@ forms are filled in by configure script + +SHELL = /bin/sh +AR = ar +RANLIB = ranlib + +.SUFFIXES: .c .o + +prefix = /usr/local +exec_prefix = ${prefix} + +BINDEST = ${exec_prefix}/bin + +MANDEST = ${prefix}/man + +srcdir = . + + +CC = gcc +CCOPTS = $(CCOPT) -Wall -Wno-parentheses + +SYSDEFS = -D__GNUC__=2 -D__GNUC_MINOR__=9 -D_IBMR2 -D_POWER -D_AIX -D_AIX32 -D_AIX41 -D_AIX43 -D_AIX51 -D_LONG_LONG -D_IBMR2 -D_POWER -D_AIX -D_AIX32 -D_AIX41 -D_AIX43 -D_AIX51 -D_LONG_LONG -D__CHAR_UNSIGNED__ -D_ARCH_COM +CPPFLAGS = -I. -I/usr/local/include +#0 INCLS = -I. @V_INCL@ +DEFS = -DHAVE_CONFIG_H +LIBS = -L/usr/local/lib -lwrap -lbsd -L/opt/freeware/lib -lreadline -lssl -lcrypto +LDFLAGS = + +INSTALL = ./install-sh -c + +#OBJ = $(CSRC:.c=.o) $(GENSRC:.c=.o) + + +#0 CFLAGS = -O -D_GNU_SOURCE $(CCOPTS) $(DEFS) $(INCLS) +CFLAGS = -O -D_GNU_SOURCE $(CCOPTS) $(DEFS) $(CPPFLAGS) +CLIBS = $(LIBS) +#CLIBS = $(LIBS) -lm -lefence +XIOSRCS = xioinitialize.c xiohelp.c xioparam.c xiodiag.c xioopen.c xioopts.c \ + xiosignal.c xiosigchld.c xioread.c xiowrite.c \ + xiolayer.c xioshutdown.c xioclose.c xioexit.c \ + xio-process.c xio-fd.c xio-fdnum.c xio-stdio.c xio-pipe.c \ + xio-gopen.c xio-creat.c xio-file.c xio-named.c \ + xio-socket.c xio-listen.c xio-unix.c xio-ip.c xio-ip4.c xio-ip6.c xio-ipapp.c xio-tcp.c xio-socks.c xio-proxy.c xio-udp.c \ + xio-rawip.c \ + xio-progcall.c xio-exec.c xio-system.c xio-termios.c xio-readline.c \ + xio-pty.c xio-openssl.c \ + xio-ascii.c xiolockfile.c xio-tcpwrap.c xio-ext2.c +XIOOBJS = $(XIOSRCS:.c=.o) +UTLSRCS = error.c dalan.c procan.c sysutils.c utils.c nestlex.c filan.c sycls.c sslcls.c +UTLOBJS = $(UTLSRCS:.c=.o) +CFILES = $(XIOSRCS) $(UTLSRCS) socat.c procan_main.c filan_main.c fdname.c +OFILES = $(CFILES:.c=.o) +PROGS = socat procan filan + +HFILES = sycls.h sslcls.h error.h dalan.h procan.h filan.h sysincludes.h xio.h xioopen.h sysutils.h utils.h nestlex.h compat.h \ + xioconfig.h mytypes.h xioopts.h xiodiag.h xiohelp.h xiosysincludes.h \ + xiomodes.h xiolayer.h xio-process.h xio-fd.h xio-fdnum.h xio-stdio.h \ + xio-named.h xio-file.h xio-creat.h xio-gopen.h xio-pipe.h xio-socket.h \ + xio-listen.h xio-unix.h xio-rawip.h xio-ip.h xio-ip4.h xio-ip6.h \ + xio-ipapp.h xio-tcp.h xio-udp.h xio-socks.h xio-proxy.h xio-progcall.h xio-exec.h \ + xio-system.h xio-termios.h xio-readline.h \ + xio-pty.h xio-openssl.h \ + xio-ascii.h xiolockfile.h xio-tcpwrap.h xio-ext2.h + + +DOCFILES = README README.FIPS CHANGES FILES EXAMPLES PORTING SECURITY DEVELOPMENT socat.1 socat.html xio.help FAQ BUGREPORTS COPYING COPYING.OpenSSL +SHFILES = daemon.sh mail.sh ftp.sh readline.sh +TESTFILES = test.sh socks4echo.sh proxyecho.sh gatherinfo.sh readline-test.sh \ + proxy.sh socks4a-echo.sh testcert.conf +OSFILES = Config/Makefile.Linux-2-4-20 Config/config.Linux-2-4-20.h \ + Config/Makefile.AIX-5-1 Config/config.AIX-5-1.h \ + Config/Makefile.MacOS-10-2 Config/config.MacOS-10-2.h \ + Config/Makefile.SunOS-5-9 Config/config.SunOS-5-9.h \ + Config/Makefile.HP-UX-B-11-11 Config/config.HP-UX-B-11-11.h \ + Config/Makefile.FreeBSD-4-10 Config/config.FreeBSD-4-10.h \ + Config/Makefile.FreeBSD-5-4 Config/config.FreeBSD-5-4.h \ + Config/Makefile.OpenBSD-3-4 Config/config.OpenBSD-3-4.h \ + Config/Makefile.Tru64-5-1B Config/config.Tru64-5-1B.h + + +all: progs + +progs: $(PROGS) + +depend: $(CFILES) $(HFILES) + makedepend $(SYSDEFS) $(CFILES) + +socat: socat.o libxio.a + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ socat.o libxio.a $(CLIBS) + +procan: procan_main.o procan.o error.o sycls.o sysutils.o utils.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ procan_main.o procan.o error.o sycls.o sysutils.o utils.o $(CLIBS) + +filan: filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o $(CLIBS) + +libxio.a: $(XIOOBJS) $(UTLOBJS) + $(AR) r $@ $(XIOOBJS) $(UTLOBJS) + $(RANLIB) $@ + +doc: xio.help +# + +strip: progs + strip $(PROGS) + +install: progs socat.1 + mkdir -p $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 socat $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 procan $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 filan $(DESTDIR)$(BINDEST) + mkdir -p $(DESTDIR)$(MANDEST)/man1 + $(INSTALL) -m 644 socat.1 $(DESTDIR)$(MANDEST)/man1/ + +# make a GNU-zipped tar ball of the source files +dist: socat.tar.gz socat.tar.bz2 + +socat.tar.gz: socat.tar + gzip -9 socat.tar.gz + +socat.tar.bz2: socat.tar + bzip2 -9 socat.tar.bz2 + +VERSION = `sed 's/"//g' VERSION` +TARDIR = socat-$(VERSION) +socat.tar: configure.in configure Makefile.in config.h.in install-sh VERSION $(CFILES) $(HFILES) $(DOCFILES) $(SHFILES) $(OSFILES) $(TESTFILES) socat.spec + if [ ! -d $(TARDIR) ]; then mkdir $(TARDIR); fi + tar cf - $+ |(cd $(TARDIR); tar xf -) + tar cvf socat.tar $(TARDIR) + rm -f $(TARDIR)/COPYING # write protected + rm -r $(TARDIR) + +clean: + rm -f *.o libxio.a socat procan filan \ + socat.tar socat.tar.Z socat.tar.gz socat.tar.bz2 \ + socat.out compile.log test.log + +# remove all files that are generated from the original socat distribution +# note that Makefile is also removed, so you have to start with ./configure +# again +distclean: clean + rm -f config.status config.cache config.log config.h Makefile + rm -rf autom4te.cache + +info: socat + uname -a >socat.out + ./socat -V >>socat.out + ./socat -hh >>socat.out + +# perform some tests on socat +test: progs + ./test.sh + +cert: + # prepare critical files with correct permissions to avoid race cond + >cert.key + >cert.pem + chmod 600 cert.key cert.pem + # generate a private key + openssl genrsa -out cert.key 1024 + # generate a self signed cert + openssl req -new -key cert.key -x509 -days 3653 -out cert.crt + # ...enter fields + # generate the pem file + cat cert.key cert.crt >cert.pem + #echo use cert.pem on requestors side, i.e. with option cert=cert.pem + #echo use cert.crt on checkers side, i.e. with option cafile=cert.crt diff --git a/Config/Makefile.FreeBSD-6-1 b/Config/Makefile.FreeBSD-6-1 new file mode 100644 index 0000000..e54007e --- /dev/null +++ b/Config/Makefile.FreeBSD-6-1 @@ -0,0 +1,177 @@ +# $Id: Makefile.FreeBSD-6-1,v 1.2 2007/03/06 21:44:34 gerhard Exp $ +# Copyright Gerhard Rieger 2001-2006 +# Published under the GNU General Public License V.2, see file COPYING + +# note: @...@ forms are filled in by configure script + +SHELL = /bin/sh +AR = ar +RANLIB = ranlib + +.SUFFIXES: .c .o + +prefix = /usr/local +exec_prefix = ${prefix} + +BINDEST = ${exec_prefix}/bin + +MANDEST = ${prefix}/man + +srcdir = . + + +CC = gcc +CCOPTS = $(CCOPT) -Wall -Wno-parentheses + +SYSDEFS = -D_LONGLONG +CPPFLAGS = -I. +#0 INCLS = -I. @V_INCL@ +DEFS = -DHAVE_CONFIG_H +LIBS = -lwrap -lutil -lreadline -lssl +LDFLAGS = + +INSTALL = /usr/bin/install -c + +#OBJ = $(CSRC:.c=.o) $(GENSRC:.c=.o) + + +#0 CFLAGS = -O -D_GNU_SOURCE $(CCOPTS) $(DEFS) $(INCLS) +CFLAGS = -O -D_GNU_SOURCE $(CCOPTS) $(DEFS) $(CPPFLAGS) +CLIBS = $(LIBS) +#CLIBS = $(LIBS) -lm -lefence +XIOSRCS = xioinitialize.c xiohelp.c xioparam.c xiodiag.c xioopen.c xioopts.c \ + xiosignal.c xiosigchld.c xioread.c xiowrite.c \ + xiolayer.c xioshutdown.c xioclose.c xioexit.c \ + xio-process.c xio-fd.c xio-fdnum.c xio-stdio.c xio-pipe.c \ + xio-gopen.c xio-creat.c xio-file.c xio-named.c \ + xio-socket.c xio-listen.c xio-unix.c xio-ip.c xio-ip4.c xio-ip6.c xio-ipapp.c xio-tcp.c xio-socks.c xio-proxy.c xio-udp.c \ + xio-rawip.c \ + xio-progcall.c xio-exec.c xio-system.c xio-termios.c xio-readline.c \ + xio-pty.c xio-openssl.c \ + xio-ascii.c xiolockfile.c xio-tcpwrap.c xio-ext2.c xio-tun.c +XIOOBJS = $(XIOSRCS:.c=.o) +UTLSRCS = error.c dalan.c procan.c hostan.c fdname.c sysutils.c utils.c nestlex.c filan.c sycls.c sslcls.c +UTLOBJS = $(UTLSRCS:.c=.o) +CFILES = $(XIOSRCS) $(UTLSRCS) socat.c procan_main.c filan_main.c +OFILES = $(CFILES:.c=.o) +PROGS = socat procan filan + +HFILES = sycls.h sslcls.h error.h dalan.h procan.h filan.h hostan.h sysincludes.h xio.h xioopen.h sysutils.h utils.h nestlex.h compat.h \ + xioconfig.h mytypes.h xioopts.h xiodiag.h xiohelp.h xiosysincludes.h \ + xiomodes.h xiolayer.h xio-process.h xio-fd.h xio-fdnum.h xio-stdio.h \ + xio-named.h xio-file.h xio-creat.h xio-gopen.h xio-pipe.h xio-socket.h \ + xio-listen.h xio-unix.h xio-rawip.h xio-ip.h xio-ip4.h xio-ip6.h \ + xio-ipapp.h xio-tcp.h xio-udp.h xio-socks.h xio-proxy.h xio-progcall.h xio-exec.h \ + xio-system.h xio-termios.h xio-readline.h \ + xio-pty.h xio-openssl.h \ + xio-ascii.h xiolockfile.h xio-tcpwrap.h xio-ext2.h xio-tun.h + + +DOCFILES = README README.FIPS CHANGES FILES EXAMPLES PORTING SECURITY DEVELOPMENT doc/socat.1 doc/socat.html doc/xio.help FAQ BUGREPORTS COPYING COPYING.OpenSSL doc/dest-unreach.css doc/socat-openssltunnel.html doc/socat-multicast.html doc/socat-tun.html +SHFILES = daemon.sh mail.sh ftp.sh readline.sh +TESTFILES = test.sh socks4echo.sh proxyecho.sh gatherinfo.sh readline-test.sh \ + proxy.sh socks4a-echo.sh testcert.conf +OSFILES = Config/Makefile.Linux-2-6-16 Config/config.Linux-2-6-16.h \ + Config/Makefile.AIX-5-1 Config/config.AIX-5-1.h \ + Config/Makefile.SunOS-5-8 Config/config.SunOS-5-8.h \ + Config/Makefile.HP-UX-B-11-11 Config/config.HP-UX-B-11-11.h \ + Config/Makefile.FreeBSD-6-1 Config/config.FreeBSD-6-1.h \ + Config/Makefile.NetBSD-2-0-2 Config/config.NetBSD-2-0-2.h \ + Config/Makefile.OpenBSD-3-8 Config/config.OpenBSD-3-8.h \ + Config/Makefile.Tru64-5-1B Config/config.Tru64-5-1B.h + + +all: progs + +progs: $(PROGS) + +depend: $(CFILES) $(HFILES) + makedepend $(SYSDEFS) $(CFILES) + +socat: socat.o libxio.a + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ socat.o libxio.a $(CLIBS) + +PROCAN_OBJS=procan_main.o procan.o hostan.o error.o sycls.o sysutils.o utils.o +procan: $(PROCAN_OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(PROCAN_OBJS) $(CLIBS) + +filan: filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o $(CLIBS) + +libxio.a: $(XIOOBJS) $(UTLOBJS) + $(AR) r $@ $(XIOOBJS) $(UTLOBJS) + $(RANLIB) $@ + +doc: doc/xio.help +# + +strip: progs + strip $(PROGS) + +install: progs doc/socat.1 + mkdir -p $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 socat $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 procan $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 filan $(DESTDIR)$(BINDEST) + mkdir -p $(DESTDIR)$(MANDEST)/man1 + $(INSTALL) -m 644 doc/socat.1 $(DESTDIR)$(MANDEST)/man1/ + +uninstall: + rm -f $(DESTDIR)$(BINDEST)/socat + rm -f $(DESTDIR)$(BINDEST)/procat + rm -f $(DESTDIR)$(BINDEST)/filan + rm -f $(DESTDIR)$(MANDEST)/man1/socat.1 + +# make a GNU-zipped tar ball of the source files +dist: socat.tar.gz socat.tar.bz2 + +socat.tar.gz: socat.tar + gzip -9 socat.tar.gz + +socat.tar.bz2: socat.tar + bzip2 -9 socat.tar.bz2 + +VERSION = `sed 's/"//g' VERSION` +TARDIR = socat-$(VERSION) +socat.tar: configure.in configure Makefile.in config.h.in install-sh VERSION $(CFILES) $(HFILES) $(DOCFILES) $(SHFILES) $(OSFILES) $(TESTFILES) socat.spec + if [ ! -d $(TARDIR) ]; then mkdir $(TARDIR); fi + tar cf - $+ |(cd $(TARDIR); tar xf -) + tar cvf socat.tar $(TARDIR) + rm -f $(TARDIR)/COPYING # write protected + rm -r $(TARDIR) + +clean: + rm -f *.o libxio.a socat procan filan \ + socat.tar socat.tar.Z socat.tar.gz socat.tar.bz2 \ + socat.out compile.log test.log + +# remove all files that are generated from the original socat distribution +# note that Makefile is also removed, so you have to start with ./configure +# again +distclean: clean + rm -f config.status config.cache config.log config.h Makefile + rm -rf autom4te.cache + +info: socat + uname -a >socat.out + ./socat -V >>socat.out + ./socat -hh >>socat.out + +# perform some tests on socat +test: progs + ./test.sh + +cert: + # prepare critical files with correct permissions to avoid race cond + >cert.key + >cert.pem + chmod 600 cert.key cert.pem + # generate a private key + openssl genrsa -out cert.key 1024 + # generate a self signed cert + openssl req -new -key cert.key -x509 -days 3653 -out cert.crt + # ...enter fields + # generate the pem file + cat cert.key cert.crt >cert.pem + #echo use cert.pem on requestors side, i.e. with option cert=cert.pem + #echo use cert.crt on checkers side, i.e. with option cafile=cert.crt diff --git a/Config/Makefile.HP-UX-B-11-11 b/Config/Makefile.HP-UX-B-11-11 new file mode 100644 index 0000000..31605b3 --- /dev/null +++ b/Config/Makefile.HP-UX-B-11-11 @@ -0,0 +1,177 @@ +# $Id: Makefile.HP-UX-B-11-11,v 1.7 2007/03/06 21:44:34 gerhard Exp $ +# Copyright Gerhard Rieger 2001-2006 +# Published under the GNU General Public License V.2, see file COPYING + +# note: @...@ forms are filled in by configure script + +SHELL = /bin/sh +AR = ar +RANLIB = ranlib + +.SUFFIXES: .c .o + +prefix = /usr/local +exec_prefix = ${prefix} + +BINDEST = ${exec_prefix}/bin + +MANDEST = ${prefix}/man + +srcdir = . + + +CC = gcc +CCOPTS = $(CCOPT) -Wall -Wno-parentheses + +SYSDEFS = +CPPFLAGS = -I. +#0 INCLS = -I. @V_INCL@ +DEFS = -DHAVE_CONFIG_H +LIBS = -lssl +LDFLAGS = + +INSTALL = /opt/imake/bin/install -c + +#OBJ = $(CSRC:.c=.o) $(GENSRC:.c=.o) + + +#0 CFLAGS = -O -D_GNU_SOURCE $(CCOPTS) $(DEFS) $(INCLS) +CFLAGS = -O -D_GNU_SOURCE $(CCOPTS) $(DEFS) $(CPPFLAGS) +CLIBS = $(LIBS) +#CLIBS = $(LIBS) -lm -lefence +XIOSRCS = xioinitialize.c xiohelp.c xioparam.c xiodiag.c xioopen.c xioopts.c \ + xiosignal.c xiosigchld.c xioread.c xiowrite.c \ + xiolayer.c xioshutdown.c xioclose.c xioexit.c \ + xio-process.c xio-fd.c xio-fdnum.c xio-stdio.c xio-pipe.c \ + xio-gopen.c xio-creat.c xio-file.c xio-named.c \ + xio-socket.c xio-listen.c xio-unix.c xio-ip.c xio-ip4.c xio-ip6.c xio-ipapp.c xio-tcp.c xio-socks.c xio-proxy.c xio-udp.c \ + xio-rawip.c \ + xio-progcall.c xio-exec.c xio-system.c xio-termios.c xio-readline.c \ + xio-pty.c xio-openssl.c \ + xio-ascii.c xiolockfile.c xio-tcpwrap.c xio-ext2.c xio-tun.c +XIOOBJS = $(XIOSRCS:.c=.o) +UTLSRCS = error.c dalan.c procan.c hostan.c fdname.c sysutils.c utils.c nestlex.c filan.c sycls.c sslcls.c +UTLOBJS = $(UTLSRCS:.c=.o) +CFILES = $(XIOSRCS) $(UTLSRCS) socat.c procan_main.c filan_main.c +OFILES = $(CFILES:.c=.o) +PROGS = socat procan filan + +HFILES = sycls.h sslcls.h error.h dalan.h procan.h filan.h hostan.h sysincludes.h xio.h xioopen.h sysutils.h utils.h nestlex.h compat.h \ + xioconfig.h mytypes.h xioopts.h xiodiag.h xiohelp.h xiosysincludes.h \ + xiomodes.h xiolayer.h xio-process.h xio-fd.h xio-fdnum.h xio-stdio.h \ + xio-named.h xio-file.h xio-creat.h xio-gopen.h xio-pipe.h xio-socket.h \ + xio-listen.h xio-unix.h xio-rawip.h xio-ip.h xio-ip4.h xio-ip6.h \ + xio-ipapp.h xio-tcp.h xio-udp.h xio-socks.h xio-proxy.h xio-progcall.h xio-exec.h \ + xio-system.h xio-termios.h xio-readline.h \ + xio-pty.h xio-openssl.h \ + xio-ascii.h xiolockfile.h xio-tcpwrap.h xio-ext2.h xio-tun.h + + +DOCFILES = README README.FIPS CHANGES FILES EXAMPLES PORTING SECURITY DEVELOPMENT doc/socat.1 doc/socat.html doc/xio.help FAQ BUGREPORTS COPYING COPYING.OpenSSL doc/dest-unreach.css doc/socat-openssltunnel.html doc/socat-multicast.html doc/socat-tun.html +SHFILES = daemon.sh mail.sh ftp.sh readline.sh +TESTFILES = test.sh socks4echo.sh proxyecho.sh gatherinfo.sh readline-test.sh \ + proxy.sh socks4a-echo.sh testcert.conf +OSFILES = Config/Makefile.Linux-2-6-16 Config/config.Linux-2-6-16.h \ + Config/Makefile.AIX-5-1 Config/config.AIX-5-1.h \ + Config/Makefile.SunOS-5-8 Config/config.SunOS-5-8.h \ + Config/Makefile.HP-UX-B-11-11 Config/config.HP-UX-B-11-11.h \ + Config/Makefile.FreeBSD-6-1 Config/config.FreeBSD-6-1.h \ + Config/Makefile.NetBSD-2-0-2 Config/config.NetBSD-2-0-2.h \ + Config/Makefile.OpenBSD-3-8 Config/config.OpenBSD-3-8.h \ + Config/Makefile.Tru64-5-1B Config/config.Tru64-5-1B.h + + +all: progs + +progs: $(PROGS) + +depend: $(CFILES) $(HFILES) + makedepend $(SYSDEFS) $(CFILES) + +socat: socat.o libxio.a + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ socat.o libxio.a $(CLIBS) + +PROCAN_OBJS=procan_main.o procan.o hostan.o error.o sycls.o sysutils.o utils.o +procan: $(PROCAN_OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(PROCAN_OBJS) $(CLIBS) + +filan: filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o $(CLIBS) + +libxio.a: $(XIOOBJS) $(UTLOBJS) + $(AR) r $@ $(XIOOBJS) $(UTLOBJS) + $(RANLIB) $@ + +doc: doc/xio.help +# + +strip: progs + strip $(PROGS) + +install: progs doc/socat.1 + mkdir -p $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 socat $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 procan $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 filan $(DESTDIR)$(BINDEST) + mkdir -p $(DESTDIR)$(MANDEST)/man1 + $(INSTALL) -m 644 doc/socat.1 $(DESTDIR)$(MANDEST)/man1/ + +uninstall: + rm -f $(DESTDIR)$(BINDEST)/socat + rm -f $(DESTDIR)$(BINDEST)/procat + rm -f $(DESTDIR)$(BINDEST)/filan + rm -f $(DESTDIR)$(MANDEST)/man1/socat.1 + +# make a GNU-zipped tar ball of the source files +dist: socat.tar.gz socat.tar.bz2 + +socat.tar.gz: socat.tar + gzip -9 socat.tar.gz + +socat.tar.bz2: socat.tar + bzip2 -9 socat.tar.bz2 + +VERSION = `sed 's/"//g' VERSION` +TARDIR = socat-$(VERSION) +socat.tar: configure.in configure Makefile.in config.h.in install-sh VERSION $(CFILES) $(HFILES) $(DOCFILES) $(SHFILES) $(OSFILES) $(TESTFILES) socat.spec + if [ ! -d $(TARDIR) ]; then mkdir $(TARDIR); fi + tar cf - $+ |(cd $(TARDIR); tar xf -) + tar cvf socat.tar $(TARDIR) + rm -f $(TARDIR)/COPYING # write protected + rm -r $(TARDIR) + +clean: + rm -f *.o libxio.a socat procan filan \ + socat.tar socat.tar.Z socat.tar.gz socat.tar.bz2 \ + socat.out compile.log test.log + +# remove all files that are generated from the original socat distribution +# note that Makefile is also removed, so you have to start with ./configure +# again +distclean: clean + rm -f config.status config.cache config.log config.h Makefile + rm -rf autom4te.cache + +info: socat + uname -a >socat.out + ./socat -V >>socat.out + ./socat -hh >>socat.out + +# perform some tests on socat +test: progs + ./test.sh + +cert: + # prepare critical files with correct permissions to avoid race cond + >cert.key + >cert.pem + chmod 600 cert.key cert.pem + # generate a private key + openssl genrsa -out cert.key 1024 + # generate a self signed cert + openssl req -new -key cert.key -x509 -days 3653 -out cert.crt + # ...enter fields + # generate the pem file + cat cert.key cert.crt >cert.pem + #echo use cert.pem on requestors side, i.e. with option cert=cert.pem + #echo use cert.crt on checkers side, i.e. with option cafile=cert.crt diff --git a/Config/Makefile.Linux-2-6-16 b/Config/Makefile.Linux-2-6-16 new file mode 100644 index 0000000..bdb3e60 --- /dev/null +++ b/Config/Makefile.Linux-2-6-16 @@ -0,0 +1,177 @@ +# $Id: Makefile.Linux-2-6-16,v 1.1 2007/03/06 21:51:57 gerhard Exp $ +# Copyright Gerhard Rieger 2001-2006 +# Published under the GNU General Public License V.2, see file COPYING + +# note: @...@ forms are filled in by configure script + +SHELL = /bin/sh +AR = ar +RANLIB = ranlib + +.SUFFIXES: .c .o + +prefix = /usr/local +exec_prefix = ${prefix} + +BINDEST = ${exec_prefix}/bin + +MANDEST = ${prefix}/man + +srcdir = . + + +CC = gcc +CCOPTS = $(CCOPT) -Wall -Wno-parentheses + +SYSDEFS = +CPPFLAGS = -I. +#0 INCLS = -I. @V_INCL@ +DEFS = -DHAVE_CONFIG_H +LIBS = -lwrap -lutil -lreadline -lssl +LDFLAGS = + +INSTALL = /usr/bin/install -c + +#OBJ = $(CSRC:.c=.o) $(GENSRC:.c=.o) + + +#0 CFLAGS = -O -D_GNU_SOURCE $(CCOPTS) $(DEFS) $(INCLS) +CFLAGS = -O -D_GNU_SOURCE $(CCOPTS) $(DEFS) $(CPPFLAGS) +CLIBS = $(LIBS) +#CLIBS = $(LIBS) -lm -lefence +XIOSRCS = xioinitialize.c xiohelp.c xioparam.c xiodiag.c xioopen.c xioopts.c \ + xiosignal.c xiosigchld.c xioread.c xiowrite.c \ + xiolayer.c xioshutdown.c xioclose.c xioexit.c \ + xio-process.c xio-fd.c xio-fdnum.c xio-stdio.c xio-pipe.c \ + xio-gopen.c xio-creat.c xio-file.c xio-named.c \ + xio-socket.c xio-listen.c xio-unix.c xio-ip.c xio-ip4.c xio-ip6.c xio-ipapp.c xio-tcp.c xio-socks.c xio-proxy.c xio-udp.c \ + xio-rawip.c \ + xio-progcall.c xio-exec.c xio-system.c xio-termios.c xio-readline.c \ + xio-pty.c xio-openssl.c \ + xio-ascii.c xiolockfile.c xio-tcpwrap.c xio-ext2.c xio-tun.c +XIOOBJS = $(XIOSRCS:.c=.o) +UTLSRCS = error.c dalan.c procan.c hostan.c fdname.c sysutils.c utils.c nestlex.c filan.c sycls.c sslcls.c +UTLOBJS = $(UTLSRCS:.c=.o) +CFILES = $(XIOSRCS) $(UTLSRCS) socat.c procan_main.c filan_main.c +OFILES = $(CFILES:.c=.o) +PROGS = socat procan filan + +HFILES = sycls.h sslcls.h error.h dalan.h procan.h filan.h hostan.h sysincludes.h xio.h xioopen.h sysutils.h utils.h nestlex.h compat.h \ + xioconfig.h mytypes.h xioopts.h xiodiag.h xiohelp.h xiosysincludes.h \ + xiomodes.h xiolayer.h xio-process.h xio-fd.h xio-fdnum.h xio-stdio.h \ + xio-named.h xio-file.h xio-creat.h xio-gopen.h xio-pipe.h xio-socket.h \ + xio-listen.h xio-unix.h xio-rawip.h xio-ip.h xio-ip4.h xio-ip6.h \ + xio-ipapp.h xio-tcp.h xio-udp.h xio-socks.h xio-proxy.h xio-progcall.h xio-exec.h \ + xio-system.h xio-termios.h xio-readline.h \ + xio-pty.h xio-openssl.h \ + xio-ascii.h xiolockfile.h xio-tcpwrap.h xio-ext2.h xio-tun.h + + +DOCFILES = README README.FIPS CHANGES FILES EXAMPLES PORTING SECURITY DEVELOPMENT doc/socat.1 doc/socat.html doc/xio.help FAQ BUGREPORTS COPYING COPYING.OpenSSL doc/dest-unreach.css doc/socat-openssltunnel.html doc/socat-multicast.html doc/socat-tun.html +SHFILES = daemon.sh mail.sh ftp.sh readline.sh +TESTFILES = test.sh socks4echo.sh proxyecho.sh gatherinfo.sh readline-test.sh \ + proxy.sh socks4a-echo.sh testcert.conf +OSFILES = Config/Makefile.Linux-2-6-16 Config/config.Linux-2-6-16.h \ + Config/Makefile.AIX-5-1 Config/config.AIX-5-1.h \ + Config/Makefile.SunOS-5-8 Config/config.SunOS-5-8.h \ + Config/Makefile.HP-UX-B-11-11 Config/config.HP-UX-B-11-11.h \ + Config/Makefile.FreeBSD-6-1 Config/config.FreeBSD-6-1.h \ + Config/Makefile.NetBSD-2-0-2 Config/config.NetBSD-2-0-2.h \ + Config/Makefile.OpenBSD-3-8 Config/config.OpenBSD-3-8.h \ + Config/Makefile.Tru64-5-1B Config/config.Tru64-5-1B.h + + +all: progs + +progs: $(PROGS) + +depend: $(CFILES) $(HFILES) + makedepend $(SYSDEFS) $(CFILES) + +socat: socat.o libxio.a + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ socat.o libxio.a $(CLIBS) + +PROCAN_OBJS=procan_main.o procan.o hostan.o error.o sycls.o sysutils.o utils.o +procan: $(PROCAN_OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(PROCAN_OBJS) $(CLIBS) + +filan: filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o $(CLIBS) + +libxio.a: $(XIOOBJS) $(UTLOBJS) + $(AR) r $@ $(XIOOBJS) $(UTLOBJS) + $(RANLIB) $@ + +doc: doc/xio.help +# + +strip: progs + strip $(PROGS) + +install: progs doc/socat.1 + mkdir -p $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 socat $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 procan $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 filan $(DESTDIR)$(BINDEST) + mkdir -p $(DESTDIR)$(MANDEST)/man1 + $(INSTALL) -m 644 doc/socat.1 $(DESTDIR)$(MANDEST)/man1/ + +uninstall: + rm -f $(DESTDIR)$(BINDEST)/socat + rm -f $(DESTDIR)$(BINDEST)/procat + rm -f $(DESTDIR)$(BINDEST)/filan + rm -f $(DESTDIR)$(MANDEST)/man1/socat.1 + +# make a GNU-zipped tar ball of the source files +dist: socat.tar.gz socat.tar.bz2 + +socat.tar.gz: socat.tar + gzip -9 socat.tar.gz + +socat.tar.bz2: socat.tar + bzip2 -9 socat.tar.bz2 + +VERSION = `sed 's/"//g' VERSION` +TARDIR = socat-$(VERSION) +socat.tar: configure.in configure Makefile.in config.h.in install-sh VERSION $(CFILES) $(HFILES) $(DOCFILES) $(SHFILES) $(OSFILES) $(TESTFILES) socat.spec + if [ ! -d $(TARDIR) ]; then mkdir $(TARDIR); fi + tar cf - $+ |(cd $(TARDIR); tar xf -) + tar cvf socat.tar $(TARDIR) + rm -f $(TARDIR)/COPYING # write protected + rm -r $(TARDIR) + +clean: + rm -f *.o libxio.a socat procan filan \ + socat.tar socat.tar.Z socat.tar.gz socat.tar.bz2 \ + socat.out compile.log test.log + +# remove all files that are generated from the original socat distribution +# note that Makefile is also removed, so you have to start with ./configure +# again +distclean: clean + rm -f config.status config.cache config.log config.h Makefile + rm -rf autom4te.cache + +info: socat + uname -a >socat.out + ./socat -V >>socat.out + ./socat -hh >>socat.out + +# perform some tests on socat +test: progs + ./test.sh + +cert: + # prepare critical files with correct permissions to avoid race cond + >cert.key + >cert.pem + chmod 600 cert.key cert.pem + # generate a private key + openssl genrsa -out cert.key 1024 + # generate a self signed cert + openssl req -new -key cert.key -x509 -days 3653 -out cert.crt + # ...enter fields + # generate the pem file + cat cert.key cert.crt >cert.pem + #echo use cert.pem on requestors side, i.e. with option cert=cert.pem + #echo use cert.crt on checkers side, i.e. with option cafile=cert.crt diff --git a/Config/Makefile.NetBSD-2-0-2 b/Config/Makefile.NetBSD-2-0-2 new file mode 100644 index 0000000..52a888a --- /dev/null +++ b/Config/Makefile.NetBSD-2-0-2 @@ -0,0 +1,171 @@ +# $Id: Makefile.NetBSD-2-0-2,v 1.1 2006/07/13 21:40:28 gerhard Exp $ +# Copyright Gerhard Rieger 2001-2006 +# Published under the GNU General Public License V.2, see file COPYING + +# note: @...@ forms are filled in by configure script + +SHELL = /bin/sh +AR = ar +RANLIB = ranlib + +.SUFFIXES: .c .o + +prefix = /usr/local +exec_prefix = ${prefix} + +BINDEST = ${exec_prefix}/bin + +MANDEST = ${prefix}/man + +srcdir = . + + +CC = gcc +CCOPTS = $(CCOPT) -Wall -Wno-parentheses + +SYSDEFS = -D__GNUC__=3 -D__GNUC_MINOR__=3 -D__GNUC_PATCHLEVEL__=3 +CPPFLAGS = -I. +#0 INCLS = -I. @V_INCL@ +DEFS = -DHAVE_CONFIG_H +LIBS = -lwrap -lutil -lssl -lcrypto +LDFLAGS = + +INSTALL = /usr/bin/install -c + +#OBJ = $(CSRC:.c=.o) $(GENSRC:.c=.o) + + +#0 CFLAGS = -O -D_GNU_SOURCE $(CCOPTS) $(DEFS) $(INCLS) +CFLAGS = -O -D_GNU_SOURCE $(CCOPTS) $(DEFS) $(CPPFLAGS) +CLIBS = $(LIBS) +#CLIBS = $(LIBS) -lm -lefence +XIOSRCS = xioinitialize.c xiohelp.c xioparam.c xiodiag.c xioopen.c xioopts.c \ + xiosignal.c xiosigchld.c xioread.c xiowrite.c \ + xiolayer.c xioshutdown.c xioclose.c xioexit.c \ + xio-process.c xio-fd.c xio-fdnum.c xio-stdio.c xio-pipe.c \ + xio-gopen.c xio-creat.c xio-file.c xio-named.c \ + xio-socket.c xio-listen.c xio-unix.c xio-ip.c xio-ip4.c xio-ip6.c xio-ipapp.c xio-tcp.c xio-socks.c xio-proxy.c xio-udp.c \ + xio-rawip.c \ + xio-progcall.c xio-exec.c xio-system.c xio-termios.c xio-readline.c \ + xio-pty.c xio-openssl.c \ + xio-ascii.c xiolockfile.c xio-tcpwrap.c xio-ext2.c +XIOOBJS = $(XIOSRCS:.c=.o) +UTLSRCS = error.c dalan.c procan.c sysutils.c utils.c nestlex.c filan.c sycls.c sslcls.c +UTLOBJS = $(UTLSRCS:.c=.o) +CFILES = $(XIOSRCS) $(UTLSRCS) socat.c procan_main.c filan_main.c fdname.c +OFILES = $(CFILES:.c=.o) +PROGS = socat procan filan + +HFILES = sycls.h sslcls.h error.h dalan.h procan.h filan.h sysincludes.h xio.h xioopen.h sysutils.h utils.h nestlex.h compat.h \ + xioconfig.h mytypes.h xioopts.h xiodiag.h xiohelp.h xiosysincludes.h \ + xiomodes.h xiolayer.h xio-process.h xio-fd.h xio-fdnum.h xio-stdio.h \ + xio-named.h xio-file.h xio-creat.h xio-gopen.h xio-pipe.h xio-socket.h \ + xio-listen.h xio-unix.h xio-rawip.h xio-ip.h xio-ip4.h xio-ip6.h \ + xio-ipapp.h xio-tcp.h xio-udp.h xio-socks.h xio-proxy.h xio-progcall.h xio-exec.h \ + xio-system.h xio-termios.h xio-readline.h \ + xio-pty.h xio-openssl.h \ + xio-ascii.h xiolockfile.h xio-tcpwrap.h xio-ext2.h + + +DOCFILES = README README.FIPS CHANGES FILES EXAMPLES PORTING SECURITY DEVELOPMENT socat.1 socat.html xio.help FAQ BUGREPORTS COPYING COPYING.OpenSSL +SHFILES = daemon.sh mail.sh ftp.sh readline.sh +TESTFILES = test.sh socks4echo.sh proxyecho.sh gatherinfo.sh readline-test.sh \ + proxy.sh socks4a-echo.sh testcert.conf +OSFILES = Config/Makefile.Linux-2-4-20 Config/config.Linux-2-4-20.h \ + Config/Makefile.AIX-5-1 Config/config.AIX-5-1.h \ + Config/Makefile.MacOS-10-2 Config/config.MacOS-10-2.h \ + Config/Makefile.SunOS-5-9 Config/config.SunOS-5-9.h \ + Config/Makefile.HP-UX-B-11-11 Config/config.HP-UX-B-11-11.h \ + Config/Makefile.FreeBSD-4-10 Config/config.FreeBSD-4-10.h \ + Config/Makefile.FreeBSD-5-4 Config/config.FreeBSD-5-4.h \ + Config/Makefile.OpenBSD-3-4 Config/config.OpenBSD-3-4.h \ + Config/Makefile.Tru64-5-1B Config/config.Tru64-5-1B.h + + +all: progs + +progs: $(PROGS) + +depend: $(CFILES) $(HFILES) + makedepend $(SYSDEFS) $(CFILES) + +socat: socat.o libxio.a + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ socat.o libxio.a $(CLIBS) + +procan: procan_main.o procan.o error.o sycls.o sysutils.o utils.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ procan_main.o procan.o error.o sycls.o sysutils.o utils.o $(CLIBS) + +filan: filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o $(CLIBS) + +libxio.a: $(XIOOBJS) $(UTLOBJS) + $(AR) r $@ $(XIOOBJS) $(UTLOBJS) + $(RANLIB) $@ + +doc: xio.help +# + +strip: progs + strip $(PROGS) + +install: progs socat.1 + mkdir -p $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 socat $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 procan $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 filan $(DESTDIR)$(BINDEST) + mkdir -p $(DESTDIR)$(MANDEST)/man1 + $(INSTALL) -m 644 socat.1 $(DESTDIR)$(MANDEST)/man1/ + +# make a GNU-zipped tar ball of the source files +dist: socat.tar.gz socat.tar.bz2 + +socat.tar.gz: socat.tar + gzip -9 socat.tar.gz + +socat.tar.bz2: socat.tar + bzip2 -9 socat.tar.bz2 + +VERSION = `sed 's/"//g' VERSION` +TARDIR = socat-$(VERSION) +socat.tar: configure.in configure Makefile.in config.h.in install-sh VERSION $(CFILES) $(HFILES) $(DOCFILES) $(SHFILES) $(OSFILES) $(TESTFILES) socat.spec + if [ ! -d $(TARDIR) ]; then mkdir $(TARDIR); fi + tar cf - $+ |(cd $(TARDIR); tar xf -) + tar cvf socat.tar $(TARDIR) + rm -f $(TARDIR)/COPYING # write protected + rm -r $(TARDIR) + +clean: + rm -f *.o libxio.a socat procan filan \ + socat.tar socat.tar.Z socat.tar.gz socat.tar.bz2 \ + socat.out compile.log test.log + +# remove all files that are generated from the original socat distribution +# note that Makefile is also removed, so you have to start with ./configure +# again +distclean: clean + rm -f config.status config.cache config.log config.h Makefile + rm -rf autom4te.cache + +info: socat + uname -a >socat.out + ./socat -V >>socat.out + ./socat -hh >>socat.out + +# perform some tests on socat +test: progs + ./test.sh + +cert: + # prepare critical files with correct permissions to avoid race cond + >cert.key + >cert.pem + chmod 600 cert.key cert.pem + # generate a private key + openssl genrsa -out cert.key 1024 + # generate a self signed cert + openssl req -new -key cert.key -x509 -days 3653 -out cert.crt + # ...enter fields + # generate the pem file + cat cert.key cert.crt >cert.pem + #echo use cert.pem on requestors side, i.e. with option cert=cert.pem + #echo use cert.crt on checkers side, i.e. with option cafile=cert.crt diff --git a/Config/Makefile.OpenBSD-3-8 b/Config/Makefile.OpenBSD-3-8 new file mode 100644 index 0000000..5863bec --- /dev/null +++ b/Config/Makefile.OpenBSD-3-8 @@ -0,0 +1,171 @@ +# $Id: Makefile.OpenBSD-3-8,v 1.1 2006/07/13 21:40:31 gerhard Exp $ +# Copyright Gerhard Rieger 2001-2006 +# Published under the GNU General Public License V.2, see file COPYING + +# note: @...@ forms are filled in by configure script + +SHELL = /bin/sh +AR = ar +RANLIB = ranlib + +.SUFFIXES: .c .o + +prefix = /usr/local +exec_prefix = ${prefix} + +BINDEST = ${exec_prefix}/bin + +MANDEST = ${prefix}/man + +srcdir = . + + +CC = gcc +CCOPTS = $(CCOPT) -Wall -Wno-parentheses + +SYSDEFS = -D__GNUC__=3 -D__GNUC_MINOR__=3 -D__GNUC_PATCHLEVEL__=5 +CPPFLAGS = -I. +#0 INCLS = -I. @V_INCL@ +DEFS = -DHAVE_CONFIG_H +LIBS = -lwrap -lutil -lreadline -lcurses -lssl -lcrypto +LDFLAGS = + +INSTALL = /usr/bin/install -c + +#OBJ = $(CSRC:.c=.o) $(GENSRC:.c=.o) + + +#0 CFLAGS = -O -D_GNU_SOURCE $(CCOPTS) $(DEFS) $(INCLS) +CFLAGS = -O -D_GNU_SOURCE $(CCOPTS) $(DEFS) $(CPPFLAGS) +CLIBS = $(LIBS) +#CLIBS = $(LIBS) -lm -lefence +XIOSRCS = xioinitialize.c xiohelp.c xioparam.c xiodiag.c xioopen.c xioopts.c \ + xiosignal.c xiosigchld.c xioread.c xiowrite.c \ + xiolayer.c xioshutdown.c xioclose.c xioexit.c \ + xio-process.c xio-fd.c xio-fdnum.c xio-stdio.c xio-pipe.c \ + xio-gopen.c xio-creat.c xio-file.c xio-named.c \ + xio-socket.c xio-listen.c xio-unix.c xio-ip.c xio-ip4.c xio-ip6.c xio-ipapp.c xio-tcp.c xio-socks.c xio-proxy.c xio-udp.c \ + xio-rawip.c \ + xio-progcall.c xio-exec.c xio-system.c xio-termios.c xio-readline.c \ + xio-pty.c xio-openssl.c \ + xio-ascii.c xiolockfile.c xio-tcpwrap.c xio-ext2.c +XIOOBJS = $(XIOSRCS:.c=.o) +UTLSRCS = error.c dalan.c procan.c sysutils.c utils.c nestlex.c filan.c sycls.c sslcls.c +UTLOBJS = $(UTLSRCS:.c=.o) +CFILES = $(XIOSRCS) $(UTLSRCS) socat.c procan_main.c filan_main.c fdname.c +OFILES = $(CFILES:.c=.o) +PROGS = socat procan filan + +HFILES = sycls.h sslcls.h error.h dalan.h procan.h filan.h sysincludes.h xio.h xioopen.h sysutils.h utils.h nestlex.h compat.h \ + xioconfig.h mytypes.h xioopts.h xiodiag.h xiohelp.h xiosysincludes.h \ + xiomodes.h xiolayer.h xio-process.h xio-fd.h xio-fdnum.h xio-stdio.h \ + xio-named.h xio-file.h xio-creat.h xio-gopen.h xio-pipe.h xio-socket.h \ + xio-listen.h xio-unix.h xio-rawip.h xio-ip.h xio-ip4.h xio-ip6.h \ + xio-ipapp.h xio-tcp.h xio-udp.h xio-socks.h xio-proxy.h xio-progcall.h xio-exec.h \ + xio-system.h xio-termios.h xio-readline.h \ + xio-pty.h xio-openssl.h \ + xio-ascii.h xiolockfile.h xio-tcpwrap.h xio-ext2.h + + +DOCFILES = README README.FIPS CHANGES FILES EXAMPLES PORTING SECURITY DEVELOPMENT socat.1 socat.html xio.help FAQ BUGREPORTS COPYING COPYING.OpenSSL +SHFILES = daemon.sh mail.sh ftp.sh readline.sh +TESTFILES = test.sh socks4echo.sh proxyecho.sh gatherinfo.sh readline-test.sh \ + proxy.sh socks4a-echo.sh testcert.conf +OSFILES = Config/Makefile.Linux-2-4-20 Config/config.Linux-2-4-20.h \ + Config/Makefile.AIX-5-1 Config/config.AIX-5-1.h \ + Config/Makefile.MacOS-10-2 Config/config.MacOS-10-2.h \ + Config/Makefile.SunOS-5-9 Config/config.SunOS-5-9.h \ + Config/Makefile.HP-UX-B-11-11 Config/config.HP-UX-B-11-11.h \ + Config/Makefile.FreeBSD-4-10 Config/config.FreeBSD-4-10.h \ + Config/Makefile.FreeBSD-5-4 Config/config.FreeBSD-5-4.h \ + Config/Makefile.OpenBSD-3-4 Config/config.OpenBSD-3-4.h \ + Config/Makefile.Tru64-5-1B Config/config.Tru64-5-1B.h + + +all: progs + +progs: $(PROGS) + +depend: $(CFILES) $(HFILES) + makedepend $(SYSDEFS) $(CFILES) + +socat: socat.o libxio.a + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ socat.o libxio.a $(CLIBS) + +procan: procan_main.o procan.o error.o sycls.o sysutils.o utils.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ procan_main.o procan.o error.o sycls.o sysutils.o utils.o $(CLIBS) + +filan: filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o $(CLIBS) + +libxio.a: $(XIOOBJS) $(UTLOBJS) + $(AR) r $@ $(XIOOBJS) $(UTLOBJS) + $(RANLIB) $@ + +doc: xio.help +# + +strip: progs + strip $(PROGS) + +install: progs socat.1 + mkdir -p $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 socat $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 procan $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 filan $(DESTDIR)$(BINDEST) + mkdir -p $(DESTDIR)$(MANDEST)/man1 + $(INSTALL) -m 644 socat.1 $(DESTDIR)$(MANDEST)/man1/ + +# make a GNU-zipped tar ball of the source files +dist: socat.tar.gz socat.tar.bz2 + +socat.tar.gz: socat.tar + gzip -9 socat.tar.gz + +socat.tar.bz2: socat.tar + bzip2 -9 socat.tar.bz2 + +VERSION = `sed 's/"//g' VERSION` +TARDIR = socat-$(VERSION) +socat.tar: configure.in configure Makefile.in config.h.in install-sh VERSION $(CFILES) $(HFILES) $(DOCFILES) $(SHFILES) $(OSFILES) $(TESTFILES) socat.spec + if [ ! -d $(TARDIR) ]; then mkdir $(TARDIR); fi + tar cf - $+ |(cd $(TARDIR); tar xf -) + tar cvf socat.tar $(TARDIR) + rm -f $(TARDIR)/COPYING # write protected + rm -r $(TARDIR) + +clean: + rm -f *.o libxio.a socat procan filan \ + socat.tar socat.tar.Z socat.tar.gz socat.tar.bz2 \ + socat.out compile.log test.log + +# remove all files that are generated from the original socat distribution +# note that Makefile is also removed, so you have to start with ./configure +# again +distclean: clean + rm -f config.status config.cache config.log config.h Makefile + rm -rf autom4te.cache + +info: socat + uname -a >socat.out + ./socat -V >>socat.out + ./socat -hh >>socat.out + +# perform some tests on socat +test: progs + ./test.sh + +cert: + # prepare critical files with correct permissions to avoid race cond + >cert.key + >cert.pem + chmod 600 cert.key cert.pem + # generate a private key + openssl genrsa -out cert.key 1024 + # generate a self signed cert + openssl req -new -key cert.key -x509 -days 3653 -out cert.crt + # ...enter fields + # generate the pem file + cat cert.key cert.crt >cert.pem + #echo use cert.pem on requestors side, i.e. with option cert=cert.pem + #echo use cert.crt on checkers side, i.e. with option cafile=cert.crt diff --git a/Config/Makefile.SunOS-5-8 b/Config/Makefile.SunOS-5-8 new file mode 100644 index 0000000..82cf882 --- /dev/null +++ b/Config/Makefile.SunOS-5-8 @@ -0,0 +1,177 @@ +# $Id: Makefile.SunOS-5-8,v 1.24 2007/03/06 21:44:34 gerhard Exp $ +# Copyright Gerhard Rieger 2001-2006 +# Published under the GNU General Public License V.2, see file COPYING + +# note: @...@ forms are filled in by configure script + +SHELL = /bin/sh +AR = ar +RANLIB = ranlib + +.SUFFIXES: .c .o + +prefix = /usr/local +exec_prefix = ${prefix} + +BINDEST = ${exec_prefix}/bin + +MANDEST = ${prefix}/man + +srcdir = . + + +CC = gcc +CCOPTS = $(CCOPT) -Wall -Wno-parentheses + +SYSDEFS = +CPPFLAGS = -I. -I/usr/local/ssl/include +#0 INCLS = -I. @V_INCL@ +DEFS = -DHAVE_CONFIG_H +LIBS = -lwrap -lrt -lsocket -lnsl -lresolv -lreadline -lcurses -L/usr/local/ssl/lib -lssl -lcrypto +LDFLAGS = + +INSTALL = ./install-sh -c + +#OBJ = $(CSRC:.c=.o) $(GENSRC:.c=.o) + + +#0 CFLAGS = -O -D_GNU_SOURCE $(CCOPTS) $(DEFS) $(INCLS) +CFLAGS = -O -D_GNU_SOURCE $(CCOPTS) $(DEFS) $(CPPFLAGS) +CLIBS = $(LIBS) +#CLIBS = $(LIBS) -lm -lefence +XIOSRCS = xioinitialize.c xiohelp.c xioparam.c xiodiag.c xioopen.c xioopts.c \ + xiosignal.c xiosigchld.c xioread.c xiowrite.c \ + xiolayer.c xioshutdown.c xioclose.c xioexit.c \ + xio-process.c xio-fd.c xio-fdnum.c xio-stdio.c xio-pipe.c \ + xio-gopen.c xio-creat.c xio-file.c xio-named.c \ + xio-socket.c xio-listen.c xio-unix.c xio-ip.c xio-ip4.c xio-ip6.c xio-ipapp.c xio-tcp.c xio-socks.c xio-proxy.c xio-udp.c \ + xio-rawip.c \ + xio-progcall.c xio-exec.c xio-system.c xio-termios.c xio-readline.c \ + xio-pty.c xio-openssl.c \ + xio-ascii.c xiolockfile.c xio-tcpwrap.c xio-ext2.c xio-tun.c +XIOOBJS = $(XIOSRCS:.c=.o) +UTLSRCS = error.c dalan.c procan.c hostan.c fdname.c sysutils.c utils.c nestlex.c filan.c sycls.c sslcls.c +UTLOBJS = $(UTLSRCS:.c=.o) +CFILES = $(XIOSRCS) $(UTLSRCS) socat.c procan_main.c filan_main.c +OFILES = $(CFILES:.c=.o) +PROGS = socat procan filan + +HFILES = sycls.h sslcls.h error.h dalan.h procan.h filan.h hostan.h sysincludes.h xio.h xioopen.h sysutils.h utils.h nestlex.h compat.h \ + xioconfig.h mytypes.h xioopts.h xiodiag.h xiohelp.h xiosysincludes.h \ + xiomodes.h xiolayer.h xio-process.h xio-fd.h xio-fdnum.h xio-stdio.h \ + xio-named.h xio-file.h xio-creat.h xio-gopen.h xio-pipe.h xio-socket.h \ + xio-listen.h xio-unix.h xio-rawip.h xio-ip.h xio-ip4.h xio-ip6.h \ + xio-ipapp.h xio-tcp.h xio-udp.h xio-socks.h xio-proxy.h xio-progcall.h xio-exec.h \ + xio-system.h xio-termios.h xio-readline.h \ + xio-pty.h xio-openssl.h \ + xio-ascii.h xiolockfile.h xio-tcpwrap.h xio-ext2.h xio-tun.h + + +DOCFILES = README README.FIPS CHANGES FILES EXAMPLES PORTING SECURITY DEVELOPMENT doc/socat.1 doc/socat.html doc/xio.help FAQ BUGREPORTS COPYING COPYING.OpenSSL doc/dest-unreach.css doc/socat-openssltunnel.html doc/socat-multicast.html doc/socat-tun.html +SHFILES = daemon.sh mail.sh ftp.sh readline.sh +TESTFILES = test.sh socks4echo.sh proxyecho.sh gatherinfo.sh readline-test.sh \ + proxy.sh socks4a-echo.sh testcert.conf +OSFILES = Config/Makefile.Linux-2-6-16 Config/config.Linux-2-6-16.h \ + Config/Makefile.AIX-5-1 Config/config.AIX-5-1.h \ + Config/Makefile.SunOS-5-8 Config/config.SunOS-5-8.h \ + Config/Makefile.HP-UX-B-11-11 Config/config.HP-UX-B-11-11.h \ + Config/Makefile.FreeBSD-6-1 Config/config.FreeBSD-6-1.h \ + Config/Makefile.NetBSD-2-0-2 Config/config.NetBSD-2-0-2.h \ + Config/Makefile.OpenBSD-3-8 Config/config.OpenBSD-3-8.h \ + Config/Makefile.Tru64-5-1B Config/config.Tru64-5-1B.h + + +all: progs + +progs: $(PROGS) + +depend: $(CFILES) $(HFILES) + makedepend $(SYSDEFS) $(CFILES) + +socat: socat.o libxio.a + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ socat.o libxio.a $(CLIBS) + +PROCAN_OBJS=procan_main.o procan.o hostan.o error.o sycls.o sysutils.o utils.o +procan: $(PROCAN_OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(PROCAN_OBJS) $(CLIBS) + +filan: filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o $(CLIBS) + +libxio.a: $(XIOOBJS) $(UTLOBJS) + $(AR) r $@ $(XIOOBJS) $(UTLOBJS) + $(RANLIB) $@ + +doc: doc/xio.help +# + +strip: progs + strip $(PROGS) + +install: progs doc/socat.1 + mkdir -p $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 socat $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 procan $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 filan $(DESTDIR)$(BINDEST) + mkdir -p $(DESTDIR)$(MANDEST)/man1 + $(INSTALL) -m 644 doc/socat.1 $(DESTDIR)$(MANDEST)/man1/ + +uninstall: + rm -f $(DESTDIR)$(BINDEST)/socat + rm -f $(DESTDIR)$(BINDEST)/procat + rm -f $(DESTDIR)$(BINDEST)/filan + rm -f $(DESTDIR)$(MANDEST)/man1/socat.1 + +# make a GNU-zipped tar ball of the source files +dist: socat.tar.gz socat.tar.bz2 + +socat.tar.gz: socat.tar + gzip -9 socat.tar.gz + +socat.tar.bz2: socat.tar + bzip2 -9 socat.tar.bz2 + +VERSION = `sed 's/"//g' VERSION` +TARDIR = socat-$(VERSION) +socat.tar: configure.in configure Makefile.in config.h.in install-sh VERSION $(CFILES) $(HFILES) $(DOCFILES) $(SHFILES) $(OSFILES) $(TESTFILES) socat.spec + if [ ! -d $(TARDIR) ]; then mkdir $(TARDIR); fi + tar cf - $+ |(cd $(TARDIR); tar xf -) + tar cvf socat.tar $(TARDIR) + rm -f $(TARDIR)/COPYING # write protected + rm -r $(TARDIR) + +clean: + rm -f *.o libxio.a socat procan filan \ + socat.tar socat.tar.Z socat.tar.gz socat.tar.bz2 \ + socat.out compile.log test.log + +# remove all files that are generated from the original socat distribution +# note that Makefile is also removed, so you have to start with ./configure +# again +distclean: clean + rm -f config.status config.cache config.log config.h Makefile + rm -rf autom4te.cache + +info: socat + uname -a >socat.out + ./socat -V >>socat.out + ./socat -hh >>socat.out + +# perform some tests on socat +test: progs + ./test.sh + +cert: + # prepare critical files with correct permissions to avoid race cond + >cert.key + >cert.pem + chmod 600 cert.key cert.pem + # generate a private key + openssl genrsa -out cert.key 1024 + # generate a self signed cert + openssl req -new -key cert.key -x509 -days 3653 -out cert.crt + # ...enter fields + # generate the pem file + cat cert.key cert.crt >cert.pem + #echo use cert.pem on requestors side, i.e. with option cert=cert.pem + #echo use cert.crt on checkers side, i.e. with option cafile=cert.crt diff --git a/Config/Makefile.Tru64-5-1B b/Config/Makefile.Tru64-5-1B new file mode 100644 index 0000000..67dac46 --- /dev/null +++ b/Config/Makefile.Tru64-5-1B @@ -0,0 +1,171 @@ +# $Id: Makefile.Tru64-5-1B,v 1.6 2006/07/13 21:30:05 gerhard Exp $ +# Copyright Gerhard Rieger 2001-2006 +# Published under the GNU General Public License V.2, see file COPYING + +# note: @...@ forms are filled in by configure script + +SHELL = /bin/sh +AR = ar +RANLIB = ranlib + +.SUFFIXES: .c .o + +prefix = /usr/local +exec_prefix = ${prefix} + +BINDEST = ${exec_prefix}/bin + +MANDEST = ${prefix}/man + +srcdir = . + + +CC = gcc +CCOPTS = $(CCOPT) -Wall -Wno-parentheses + +SYSDEFS = -D__GNUC__=2 -D__GNUC_MINOR__=9 -Dunix -D__osf__ -D_LONGLONG -DSYSTYPE_BSD -D_SYSTYPE_BSD -D__unix__ -D__osf__ -D_LONGLONG -D__SYSTYPE_BSD__ -D_SYSTYPE_BSD -D__unix -D__SYSTYPE_BSD -D__LANGUAGE_C__ -D__LANGUAGE_C -DLANGUAGE_C -D__alpha -D__alpha__ -D__alpha_ev4__ +CPPFLAGS = -I. +#0 INCLS = -I. @V_INCL@ +DEFS = -DHAVE_CONFIG_H +LIBS = -lutil -lbsd -lrt -lreadline -lcurses -lssl -lcrypto +LDFLAGS = + +INSTALL = /usr/local/bin/install -c + +#OBJ = $(CSRC:.c=.o) $(GENSRC:.c=.o) + + +#0 CFLAGS = -O -D_GNU_SOURCE $(CCOPTS) $(DEFS) $(INCLS) +CFLAGS = -O -D_GNU_SOURCE $(CCOPTS) $(DEFS) $(CPPFLAGS) +CLIBS = $(LIBS) +#CLIBS = $(LIBS) -lm -lefence +XIOSRCS = xioinitialize.c xiohelp.c xioparam.c xiodiag.c xioopen.c xioopts.c \ + xiosignal.c xiosigchld.c xioread.c xiowrite.c \ + xiolayer.c xioshutdown.c xioclose.c xioexit.c \ + xio-process.c xio-fd.c xio-fdnum.c xio-stdio.c xio-pipe.c \ + xio-gopen.c xio-creat.c xio-file.c xio-named.c \ + xio-socket.c xio-listen.c xio-unix.c xio-ip.c xio-ip4.c xio-ip6.c xio-ipapp.c xio-tcp.c xio-socks.c xio-proxy.c xio-udp.c \ + xio-rawip.c \ + xio-progcall.c xio-exec.c xio-system.c xio-termios.c xio-readline.c \ + xio-pty.c xio-openssl.c \ + xio-ascii.c xiolockfile.c xio-tcpwrap.c xio-ext2.c +XIOOBJS = $(XIOSRCS:.c=.o) +UTLSRCS = error.c dalan.c procan.c sysutils.c utils.c nestlex.c filan.c sycls.c sslcls.c +UTLOBJS = $(UTLSRCS:.c=.o) +CFILES = $(XIOSRCS) $(UTLSRCS) socat.c procan_main.c filan_main.c fdname.c +OFILES = $(CFILES:.c=.o) +PROGS = socat procan filan + +HFILES = sycls.h sslcls.h error.h dalan.h procan.h filan.h sysincludes.h xio.h xioopen.h sysutils.h utils.h nestlex.h compat.h \ + xioconfig.h mytypes.h xioopts.h xiodiag.h xiohelp.h xiosysincludes.h \ + xiomodes.h xiolayer.h xio-process.h xio-fd.h xio-fdnum.h xio-stdio.h \ + xio-named.h xio-file.h xio-creat.h xio-gopen.h xio-pipe.h xio-socket.h \ + xio-listen.h xio-unix.h xio-rawip.h xio-ip.h xio-ip4.h xio-ip6.h \ + xio-ipapp.h xio-tcp.h xio-udp.h xio-socks.h xio-proxy.h xio-progcall.h xio-exec.h \ + xio-system.h xio-termios.h xio-readline.h \ + xio-pty.h xio-openssl.h \ + xio-ascii.h xiolockfile.h xio-tcpwrap.h xio-ext2.h + + +DOCFILES = README README.FIPS CHANGES FILES EXAMPLES PORTING SECURITY DEVELOPMENT socat.1 socat.html xio.help FAQ BUGREPORTS COPYING COPYING.OpenSSL +SHFILES = daemon.sh mail.sh ftp.sh readline.sh +TESTFILES = test.sh socks4echo.sh proxyecho.sh gatherinfo.sh readline-test.sh \ + proxy.sh socks4a-echo.sh testcert.conf +OSFILES = Config/Makefile.Linux-2-4-20 Config/config.Linux-2-4-20.h \ + Config/Makefile.AIX-5-1 Config/config.AIX-5-1.h \ + Config/Makefile.MacOS-10-2 Config/config.MacOS-10-2.h \ + Config/Makefile.SunOS-5-9 Config/config.SunOS-5-9.h \ + Config/Makefile.HP-UX-B-11-11 Config/config.HP-UX-B-11-11.h \ + Config/Makefile.FreeBSD-4-10 Config/config.FreeBSD-4-10.h \ + Config/Makefile.FreeBSD-5-4 Config/config.FreeBSD-5-4.h \ + Config/Makefile.OpenBSD-3-4 Config/config.OpenBSD-3-4.h \ + Config/Makefile.Tru64-5-1B Config/config.Tru64-5-1B.h + + +all: progs + +progs: $(PROGS) + +depend: $(CFILES) $(HFILES) + makedepend $(SYSDEFS) $(CFILES) + +socat: socat.o libxio.a + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ socat.o libxio.a $(CLIBS) + +procan: procan_main.o procan.o error.o sycls.o sysutils.o utils.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ procan_main.o procan.o error.o sycls.o sysutils.o utils.o $(CLIBS) + +filan: filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o $(CLIBS) + +libxio.a: $(XIOOBJS) $(UTLOBJS) + $(AR) r $@ $(XIOOBJS) $(UTLOBJS) + $(RANLIB) $@ + +doc: xio.help +# + +strip: progs + strip $(PROGS) + +install: progs socat.1 + mkdir -p $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 socat $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 procan $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 filan $(DESTDIR)$(BINDEST) + mkdir -p $(DESTDIR)$(MANDEST)/man1 + $(INSTALL) -m 644 socat.1 $(DESTDIR)$(MANDEST)/man1/ + +# make a GNU-zipped tar ball of the source files +dist: socat.tar.gz socat.tar.bz2 + +socat.tar.gz: socat.tar + gzip -9 socat.tar.gz + +socat.tar.bz2: socat.tar + bzip2 -9 socat.tar.bz2 + +VERSION = `sed 's/"//g' VERSION` +TARDIR = socat-$(VERSION) +socat.tar: configure.in configure Makefile.in config.h.in install-sh VERSION $(CFILES) $(HFILES) $(DOCFILES) $(SHFILES) $(OSFILES) $(TESTFILES) socat.spec + if [ ! -d $(TARDIR) ]; then mkdir $(TARDIR); fi + tar cf - $+ |(cd $(TARDIR); tar xf -) + tar cvf socat.tar $(TARDIR) + rm -f $(TARDIR)/COPYING # write protected + rm -r $(TARDIR) + +clean: + rm -f *.o libxio.a socat procan filan \ + socat.tar socat.tar.Z socat.tar.gz socat.tar.bz2 \ + socat.out compile.log test.log + +# remove all files that are generated from the original socat distribution +# note that Makefile is also removed, so you have to start with ./configure +# again +distclean: clean + rm -f config.status config.cache config.log config.h Makefile + rm -rf autom4te.cache + +info: socat + uname -a >socat.out + ./socat -V >>socat.out + ./socat -hh >>socat.out + +# perform some tests on socat +test: progs + ./test.sh + +cert: + # prepare critical files with correct permissions to avoid race cond + >cert.key + >cert.pem + chmod 600 cert.key cert.pem + # generate a private key + openssl genrsa -out cert.key 1024 + # generate a self signed cert + openssl req -new -key cert.key -x509 -days 3653 -out cert.crt + # ...enter fields + # generate the pem file + cat cert.key cert.crt >cert.pem + #echo use cert.pem on requestors side, i.e. with option cert=cert.pem + #echo use cert.crt on checkers side, i.e. with option cafile=cert.crt diff --git a/Config/config.AIX-5-1.h b/Config/config.AIX-5-1.h new file mode 100644 index 0000000..33cf69b --- /dev/null +++ b/Config/config.AIX-5-1.h @@ -0,0 +1,450 @@ +/* config.h. Generated by configure. */ +/* $Id: config.AIX-5-1.h,v 1.14 2006/07/13 21:33:50 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __config_h_included +#define __config_h_included 1 + +/* Define to empty if the keyword does not work. */ +/* #undef const */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define if your struct stat has st_blksize. */ +#define HAVE_ST_BLKSIZE 1 + +/* Define if your struct stat has st_blocks. */ +#define HAVE_ST_BLOCKS 1 + +/* Define if your struct stat has st_rdev. */ +#define HAVE_ST_RDEV 1 + +/* Define if you have the strftime function. */ +#define HAVE_STRFTIME 1 + +/* Define if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to `int' if doesn't define. */ +/* #undef mode_t */ + +/* Define to `long' if doesn't define. */ +/* #undef off_t */ + +/* Define to `int' if doesn't define. */ +/* #undef pid_t */ + +/* Define as the return type of signal handlers (int or void). */ +#define RETSIGTYPE void + +/* Define to `unsigned' if doesn't define. */ +/* #undef size_t */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ + +/* Define if you have the putenv function. */ +#define HAVE_PUTENV 1 + +/* Define if you have the select function. */ +#define HAVE_SELECT 1 + +/* Define if you have the poll function. */ +#define HAVE_POLL 1 + +/* Define if you have the socket function. */ +#define HAVE_SOCKET 1 + +/* Define if you have the strdup function. */ +#define HAVE_STRDUP 1 + +/* Define if you have the strerror function. */ +#define HAVE_STRERROR 1 + +/* Define if you have the strstr function. */ +#define HAVE_STRSTR 1 + +/* Define if you have the strtod function. */ +#define HAVE_STRTOD 1 + +/* Define if you have the strtol function. */ +#define HAVE_STRTOL 1 + +/* Define if you have the strtoul function. */ +#define HAVE_STRTOUL 1 + +/* Define if you have the uname function. */ +#define HAVE_UNAME 1 + +/* Define if you have the getpgid function. */ +#define HAVE_GETPGID 1 + +/* Define if you have the getsid function. */ +#define HAVE_GETSID 1 + +/* Define if you have the nanosleep function. */ +#define HAVE_NANOSLEEP 1 + +/* Define if you have the getaddrinfo function. */ +#define HAVE_GETADDRINFO 1 + +/* Define if you have the getipnodebyname function. */ +#define HAVE_GETIPNODEBYNAME 1 + +/* Define if you have the setgroups function. */ +#define HAVE_SETGROUPS 1 + +/* Define if you have the inet_aton function. */ +#define HAVE_INET_ATON 1 + +/* Define if you have the memrchr function. */ +/* #undef HAVE_MEMRCHR */ + +/* Define if you have the sigaction function */ +#define HAVE_SIGACTION 1 + +/* Define if you have the stat64 function */ +#define HAVE_STAT64 1 + +/* Define if you have the fstat64 function */ +#define HAVE_FSTAT64 1 + +/* Define if you have the lstat64 function */ +#define HAVE_LSTAT64 1 + +/* Define if you have the lseek64 function */ +#define HAVE_LSEEK64 1 + +/* Define if you have the truncate64 function */ +#define HAVE_TRUNCATE64 1 + +/* Define if you have the ftruncate64 function */ +#define HAVE_FTRUNCATE64 1 + +/* Define if you have the strtoll function */ +#define HAVE_STRTOLL 1 + +/* Define if you have the hstrerror function */ +#define HAVE_HSTRERROR 1 + +/* Define if you have the hstrerror prototype */ +/* #undef HAVE_PROTOTYPE_HSTRERROR */ + +/* Define if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYSLOG_H 1 + +/* Define if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if you have the header file. */ +#define HAVE_PWD_H 1 + +/* Define if you have the header file. */ +#define HAVE_GRP_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_STDINT_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_POLL_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UN_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_PTY_H */ + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_SYSTM_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IP_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IP6_H 1 + +/* Define if you have the header file. */ +#define HAVE_RESOLV_H 1 + +/* Define if you have the header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define if you have the header file. */ +#define HAVE_NET_IF_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UTSNAME_H 1 + +/* Define if you have the header file. (AIX) */ +#define HAVE_SYS_SELECT_H 1 + +/* Define if you have the header file. (AIX) */ +#define HAVE_SYS_FILE_H 1 + +/* Define if you have the header file. (NetBSD, OpenBSD: openpty()) */ +/* #undef HAVE_UTIL_H */ + +/* Define if you have the header file. (FreeBSD: openpty()) */ +/* #undef HAVE_LIBUTIL_H */ + +/* Define if you have the header file. (stream opts on SunOS)*/ +#define HAVE_SYS_STROPTS_H 1 + +/* Define if you have the header file. */ +#define HAVE_REGEX_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_LINUX_EXT2_FS_H */ + +/* Define if you have the header file. */ +#define HAVE_READLINE_READLINE_H 1 + +/* Define if you have the header file. */ +#define HAVE_READLINE_HISTORY_H 1 + +/* Define if you have the readline library. */ +#define HAVE_LIBREADLINE 1 + +/* Define if you have the m library (-lm). */ +/* #undef HAVE_LIBM */ + +/* Define if you have the floor function */ +/* #undef HAVE_FLOOR */ + +/* some platforms need _XOPEN_EXTENDED_SOURCE to get syslog headers (AIX4.1) */ +/* #undef _XOPEN_EXTENDED_SOURCE */ + +/* fdset may have component fds_bits or __fds_bits */ +#define HAVE_FDS_BITS 1 + +/* Define if your struct termios has component c_ispeed */ +/* #undef HAVE_TERMIOS_ISPEED */ + +/* the offset of c_ispeed in struct termios - usable in an speed_t array. + Applies only when HAVE_TERMIOS_ISPEED is set */ +/* #undef ISPEED_OFFSET */ + +/* the offset of c_ospeed in struct termios - see ISPEED_OFFSET */ +#ifdef ISPEED_OFFSET +# define OSPEED_OFFSET (ISPEED_OFFSET+1) +#else +/* # undef OSPEED_OFFSET */ +#endif + +/* Define if your termios.h likes _SVID3 defined */ +/* #undef _SVID3 */ + +/* Define if you have struct timespec (e.g. for nanosleep) */ +#define HAVE_STRUCT_TIMESPEC 1 + +/* Define if you have struct linger */ +#define HAVE_STRUCT_LINGER 1 + +/* Define if your struct sockaddr has sa_len */ +#define HAVE_STRUCT_SOCKADDR_SALEN 1 + +/* there are several implementations of sockaddr_in6 */ +#define HAVE_IP6_SOCKADDR 0 + +/* Define if you have struct iovec */ +#define HAVE_STRUCT_IOVEC 1 + +/* define if your struct msghdr has msg_control */ +#define HAVE_STRUCT_MSGHDR_MSGCONTROL 1 + +/* define if your struct msghdr has msg_controllen */ +#define HAVE_STRUCT_MSGHDR_MSGCONTROLLEN 1 + +/* define if your struct msghdr has msg_flag */ +#define HAVE_STRUCT_MSGHDR_MSGFLAGS 1 + +/* define if your struct ip has ip_hl; otherwise assume ip_vhl */ +#define HAVE_STRUCT_IP_IP_HL 1 + +/* Define if you have the setenv function */ +#define HAVE_SETENV 1 + +/* Define if you have the flock function */ +/* #undef HAVE_FLOCK */ + +/* Define if you have the openpty function */ +/* #undef HAVE_OPENPTY */ + +/* Define if you have the grantpt function */ +#define HAVE_GRANTPT 1 + +/* Define if you have the unlockpt function */ +#define HAVE_UNLOCKPT 1 + +/* Define if you have the ptsname function */ +#define HAVE_PTSNAME 1 + +/* Define if you have the /dev/ptmx pseudo terminal multiplexer */ +/* #undef HAVE_DEV_PTMX */ + +/* Define if you have the /dev/ptc pseudo terminal multiplexer */ +#define HAVE_DEV_PTC 1 + +/* Define if you have the long long type */ +#define HAVE_TYPE_LONGLONG 1 + +/* is socklen_t already typedef'd? */ +#define HAVE_TYPE_SOCKLEN 1 + +/* Define if you have the struct stat64 type */ +#define HAVE_TYPE_STAT64 1 + +/* Define if you have the struct off64_t type */ +#define HAVE_TYPE_OFF64 1 + +/* is sighandler_t already typedef'd? */ +/* #undef HAVE_TYPE_SIGHANDLER */ + +/* is uint8_t already defined? */ +#define HAVE_TYPE_UINT8 1 + +/* is uint16_t already defined? */ +#define HAVE_TYPE_UINT16 1 + +/* is uint32_t already defined? */ +#define HAVE_TYPE_UINT32 1 + +/* Define if you have the printf "Z" modifier */ +/* #undef HAVE_FORMAT_Z */ + +/* Define the shift offset of the CRDLY mask */ +#define CRDLY_SHIFT 8 + +/* Define the shift offset of the TABDLY mask */ +#define TABDLY_SHIFT 10 + +/* Define the shift offset of the CSIZE mask */ +#define CSIZE_SHIFT 4 + +/* Define if you have tcpwrappers (libwrap, tcpd) and it declares hosts_allow_table */ +#define HAVE_HOSTS_ALLOW_TABLE 1 +#if defined(HAVE_HOSTS_ALLOW_TABLE) && HAVE_HOSTS_ALLOW_TABLE + #define HAVE_HOSTS_DENY_TABLE 1 +#else +/* #undef HAVE_HOSTS_DENY_TABLE */ +#endif + +/* 1..short, 3..int, 5..long; 2,4,6..unsigned */ +#define HAVE_BASIC_SIZE_T 6 /* unsigned long */ +#define HAVE_BASIC_MODE_T 4 /* unsigned int */ +#define HAVE_BASIC_PID_T 3 /* int */ +#define HAVE_BASIC_UID_T 4 /* unsigned int */ +#define HAVE_BASIC_GID_T 4 /* unsigned int */ +#define HAVE_BASIC_TIME_T 3 /* int */ +#define HAVE_BASIC_OFF64_T 7 /* long long */ + +#define HAVE_BASIC_SOCKLEN_T 6 /* unsigned long */ + +#define HAVE_TYPEOF_ST_DEV 4 /* unsigned int */ +#define HAVE_TYPEOF_ST_INO 4 /* unsigned int */ +#define HAVE_TYPEOF_ST_NLINK 1 /* short */ +#define HAVE_TYPEOF_ST_SIZE 5 /* long */ +#define HAVE_TYPEOF_ST_BLKSIZE 3 /* int */ +#define HAVE_TYPEOF_ST_BLOCKS 3 /* int */ + +#define HAVE_TYPEOF_ST64_DEV 4 /* unsigned int */ +#define HAVE_TYPEOF_ST64_INO 4 /* unsigned int */ +#define HAVE_TYPEOF_ST64_NLINK 1 /* short */ +#define HAVE_TYPEOF_ST64_SIZE 7 /* long long */ +#define HAVE_TYPEOF_ST64_BLKSIZE 3 /* int */ +#define HAVE_TYPEOF_ST64_BLOCKS 3 /* int */ + +/* #undef HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC */ + +#define HAVE_TYPEOF_RLIM_MAX 6 /* unsigned long */ + +/* Define if you have the /proc filesystem */ +#define HAVE_PROC_DIR 1 + +/* Define if you have the /proc/$$/fd directories */ +/* #undef HAVE_PROC_DIR_FD */ + +#define WITH_HELP 1 +#define WITH_STDIO 1 +#define WITH_FDNUM 1 +#define WITH_FILE 1 +#define WITH_CREAT 1 +#define WITH_GOPEN 1 +#define WITH_TERMIOS 1 +#define WITH_PIPE 1 +#define WITH_UNIX 1 +#define WITH_IP4 1 +#define WITH_IP6 1 +#define WITH_RAWIP 1 +#define WITH_TCP 1 +#define WITH_UDP 1 +#define WITH_LISTEN 1 +#define WITH_SOCKS4 1 +#define WITH_SOCKS4A 1 +#define WITH_PROXY 1 +#define WITH_EXEC 1 +#define WITH_SYSTEM 1 +#define WITH_READLINE 1 +#define WITH_PTY 1 +#define WITH_EXT2 1 +#define WITH_OPENSSL 1 +/* #undef WITH_FIPS */ +/* #undef OPENSSL_FIPS */ +#define WITH_LIBWRAP 1 +#define HAVE_TCPD_H 1 +#define HAVE_LIBWRAP 1 + +#define WITH_SYCLS 1 +#define WITH_FILAN 1 +#define WITH_RETRY 1 + +#define WITH_MSGLEVEL 0 + +#endif /* !defined(__config_h_included) */ diff --git a/Config/config.FreeBSD-6-1.h b/Config/config.FreeBSD-6-1.h new file mode 100644 index 0000000..881807c --- /dev/null +++ b/Config/config.FreeBSD-6-1.h @@ -0,0 +1,485 @@ +/* config.h. Generated by configure. */ +/* $Id: config.FreeBSD-6-1.h,v 1.2 2007/03/06 21:44:34 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __config_h_included +#define __config_h_included 1 + +/* Define to empty if the keyword does not work. */ +/* #undef const */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define if your struct stat has st_blksize. */ +#define HAVE_ST_BLKSIZE 1 + +/* Define if your struct stat has st_blocks. */ +#define HAVE_ST_BLOCKS 1 + +/* Define if your struct stat has st_rdev. */ +#define HAVE_ST_RDEV 1 + +/* Define if you have the strftime function. */ +#define HAVE_STRFTIME 1 + +/* Define if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to `int' if doesn't define. */ +/* #undef mode_t */ + +/* Define to `long' if doesn't define. */ +/* #undef off_t */ + +/* Define to `int' if doesn't define. */ +/* #undef pid_t */ + +/* Define as the return type of signal handlers (int or void). */ +#define RETSIGTYPE void + +/* Define to `unsigned' if doesn't define. */ +/* #undef size_t */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ + +/* Define if you have the putenv function. */ +#define HAVE_PUTENV 1 + +/* Define if you have the select function. */ +#define HAVE_SELECT 1 + +/* Define if you have the poll function. */ +#define HAVE_POLL 1 + +/* Define if you have the socket function. */ +#define HAVE_SOCKET 1 + +/* Define if you have the strdup function. */ +#define HAVE_STRDUP 1 + +/* Define if you have the strerror function. */ +#define HAVE_STRERROR 1 + +/* Define if you have the strstr function. */ +#define HAVE_STRSTR 1 + +/* Define if you have the strtod function. */ +#define HAVE_STRTOD 1 + +/* Define if you have the strtol function. */ +#define HAVE_STRTOL 1 + +/* Define if you have the strtoul function. */ +#define HAVE_STRTOUL 1 + +/* Define if you have the uname function. */ +#define HAVE_UNAME 1 + +/* Define if you have the getpgid function. */ +#define HAVE_GETPGID 1 + +/* Define if you have the getsid function. */ +#define HAVE_GETSID 1 + +/* Define if you have the nanosleep function. */ +#define HAVE_NANOSLEEP 1 + +/* Define if you have the getaddrinfo function. */ +#define HAVE_GETADDRINFO 1 + +/* Define if you have the getipnodebyname function. */ +#define HAVE_GETIPNODEBYNAME 1 + +/* Define if you have the setgroups function. */ +#define HAVE_SETGROUPS 1 + +/* Define if you have the inet_aton function. */ +#define HAVE_INET_ATON 1 + +/* Define if you have the memrchr function. */ +/* #undef HAVE_MEMRCHR */ + +/* Define if you have the sigaction function */ +#define HAVE_SIGACTION 1 + +/* Define if you have the stat64 function */ +/* #undef HAVE_STAT64 */ + +/* Define if you have the fstat64 function */ +/* #undef HAVE_FSTAT64 */ + +/* Define if you have the lstat64 function */ +/* #undef HAVE_LSTAT64 */ + +/* Define if you have the lseek64 function */ +/* #undef HAVE_LSEEK64 */ + +/* Define if you have the truncate64 function */ +/* #undef HAVE_TRUNCATE64 */ + +/* Define if you have the ftruncate64 function */ +/* #undef HAVE_FTRUNCATE64 */ + +/* Define if you have the strtoll function */ +#define HAVE_STRTOLL 1 + +/* Define if you have the hstrerror function */ +#define HAVE_HSTRERROR 1 + +/* Define if you have the inet_ntop function */ +#define HAVE_INET_NTOP 1 + +/* Define if you have the hstrerror prototype */ +#define HAVE_PROTOTYPE_HSTRERROR 1 + +/* Define if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYSLOG_H 1 + +/* Define if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if you have the header file. */ +#define HAVE_PWD_H 1 + +/* Define if you have the header file. */ +#define HAVE_GRP_H 1 + +/* Define if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_POLL_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UN_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_PTY_H */ + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_SYSTM_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IP_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IP6_H 1 + +/* Define if you have the header file. */ +#define HAVE_ARPA_NAMESER_H 1 + +/* Define if you have the header file. */ +#define HAVE_RESOLV_H 1 + +/* Define if you have the header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define if you have the header file. */ +#define HAVE_NET_IF_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_LINUX_IF_TUN_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_UTSNAME_H 1 + +/* Define if you have the header file. (AIX) */ +#define HAVE_SYS_SELECT_H 1 + +/* Define if you have the header file. (AIX) */ +#define HAVE_SYS_FILE_H 1 + +/* Define if you have the header file. (NetBSD, OpenBSD: openpty()) */ +/* #undef HAVE_UTIL_H */ + +/* Define if you have the header file. (FreeBSD: openpty()) */ +#define HAVE_LIBUTIL_H 1 + +/* Define if you have the header file. (stream opts on SunOS)*/ +/* #undef HAVE_SYS_STROPTS_H */ + +/* Define if you have the header file. */ +#define HAVE_REGEX_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_LINUX_FS_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_LINUX_EXT2_FS_H */ + +/* Define if you have the header file. */ +#define HAVE_READLINE_READLINE_H 1 + +/* Define if you have the header file. */ +#define HAVE_READLINE_HISTORY_H 1 + +/* Define if you have the readline library. */ +#define HAVE_LIBREADLINE 1 + +/* Define if you have the m library (-lm). */ +/* #undef HAVE_LIBM */ + +/* Define if you have the floor function */ +/* #undef HAVE_FLOOR */ + +/* some platforms need _XOPEN_EXTENDED_SOURCE to get syslog headers (AIX4.1) */ +/* #undef _XOPEN_EXTENDED_SOURCE */ + +/* fdset may have component fds_bits or __fds_bits */ +#define HAVE_FDS_BITS 1 + +/* Define if your struct termios has component c_ispeed */ +#define HAVE_TERMIOS_ISPEED 1 + +/* the offset of c_ispeed in struct termios - usable in an speed_t array. + Applies only when HAVE_TERMIOS_ISPEED is set */ +#define ISPEED_OFFSET 9 + +/* the offset of c_ospeed in struct termios - see ISPEED_OFFSET */ +#ifdef ISPEED_OFFSET +# define OSPEED_OFFSET (ISPEED_OFFSET+1) +#else +/* # undef OSPEED_OFFSET */ +#endif + +/* Define if your termios.h likes _SVID3 defined */ +/* #undef _SVID3 */ + +/* Define if you have struct timespec (e.g. for nanosleep) */ +#define HAVE_STRUCT_TIMESPEC 1 + +/* Define if you have struct linger */ +#define HAVE_STRUCT_LINGER 1 + +/* Define if you have struct ip_mreq */ +#define HAVE_STRUCT_IP_MREQ 1 + +/* Define if you have struct ip_mreqn */ +/* #undef HAVE_STRUCT_IP_MREQN */ + +/* Define if you have struct ipv6_mreq */ +#define HAVE_STRUCT_IPV6_MREQ 1 + +/* Define if you have struct ifreq */ +#define HAVE_STRUCT_IFREQ 1 + +/* Define if you have struct ifreq.ifr_index */ +#define HAVE_STRUCT_IFREQ_IFR_INDEX 1 + +/* Define if you have struct ifreq.ifr_ifindex */ +/* #undef HAVE_STRUCT_IFREQ_IFR_IFINDEX */ + +/* Define if your struct sockaddr has sa_len */ +#define HAVE_STRUCT_SOCKADDR_SALEN 1 + +/* there are several implementations of sockaddr_in6 */ +#define HAVE_IP6_SOCKADDR 0 + +/* Define if you have struct iovec */ +#define HAVE_STRUCT_IOVEC 1 + +/* define if your struct msghdr has msg_control */ +#define HAVE_STRUCT_MSGHDR_MSGCONTROL 1 + +/* define if your struct msghdr has msg_controllen */ +#define HAVE_STRUCT_MSGHDR_MSGCONTROLLEN 1 + +/* define if your struct msghdr has msg_flag */ +#define HAVE_STRUCT_MSGHDR_MSGFLAGS 1 + +/* define if your struct ip has ip_hl; otherwise assume ip_vhl */ +#define HAVE_STRUCT_IP_IP_HL 1 + +/* Define if you have the setenv function */ +#define HAVE_SETENV 1 + +/* Define if you have the flock function */ +#define HAVE_FLOCK 1 + +/* Define if you have the openpty function */ +#define HAVE_OPENPTY 1 + +/* Define if you have the grantpt function */ +#define HAVE_GRANTPT 1 + +/* Define if you have the unlockpt function */ +#define HAVE_UNLOCKPT 1 + +/* Define if you have the ptsname function */ +#define HAVE_PTSNAME 1 + +/* Define if you have the /dev/ptmx pseudo terminal multiplexer */ +/* #undef HAVE_DEV_PTMX */ + +/* Define if you have the /dev/ptc pseudo terminal multiplexer */ +/* #undef HAVE_DEV_PTC */ + +/* Define if you have the long long type */ +#define HAVE_TYPE_LONGLONG 1 + +/* is socklen_t already typedef'd? */ +#define HAVE_TYPE_SOCKLEN 1 + +/* Define if you have the struct stat64 type */ +/* #undef HAVE_TYPE_STAT64 */ + +/* Define if you have the struct off64_t type */ +/* #undef HAVE_TYPE_OFF64 */ + +/* is sighandler_t already typedef'd? */ +/* #undef HAVE_TYPE_SIGHANDLER */ + +/* is uint8_t already defined? */ +#define HAVE_TYPE_UINT8 1 + +/* is uint16_t already defined? */ +#define HAVE_TYPE_UINT16 1 + +/* is uint32_t already defined? */ +#define HAVE_TYPE_UINT32 1 + +/* is uint64_t already defined? */ +#define HAVE_TYPE_UINT64 1 + +/* Define if you have the printf "Z" modifier */ +/* #undef HAVE_FORMAT_Z */ + +/* Define the shift offset of the CRDLY mask */ +#define CRDLY_SHIFT -1 + +/* Define the shift offset of the TABDLY mask */ +#define TABDLY_SHIFT -1 + +/* Define the shift offset of the CSIZE mask */ +#define CSIZE_SHIFT 8 + +/* Define if you have tcpwrappers (libwrap, tcpd) and it declares hosts_allow_table */ +#define HAVE_HOSTS_ALLOW_TABLE 1 +#if defined(HAVE_HOSTS_ALLOW_TABLE) && HAVE_HOSTS_ALLOW_TABLE +# define HAVE_HOSTS_DENY_TABLE 1 +#else +/* # undef HAVE_HOSTS_DENY_TABLE */ +#endif + +/* 1..short, 3..int, 5..long; 2,4,6..unsigned */ +#define HAVE_BASIC_SIZE_T 4 /* unsigned int */ +#define HAVE_BASIC_MODE_T 2 /* unsigned short */ +#define HAVE_BASIC_PID_T 3 /* int */ +#define HAVE_BASIC_UID_T 4 /* unsigned int */ +#define HAVE_BASIC_GID_T 4 /* unsigned int */ +#define HAVE_BASIC_TIME_T 3 /* int */ +#define HAVE_BASIC_OFF64_T 0 /* unknown, taking default */ + +#define HAVE_BASIC_SOCKLEN_T 4 /* unsigned int */ + +#define HAVE_TYPEOF_ST_DEV 4 /* unsigned int */ +#define HAVE_TYPEOF_ST_INO 4 /* unsigned int */ +#define HAVE_TYPEOF_ST_NLINK 2 /* unsigned short */ +#define HAVE_TYPEOF_ST_SIZE 7 /* long long */ +#define HAVE_TYPEOF_ST_BLKSIZE 4 /* unsigned int */ +#define HAVE_TYPEOF_ST_BLOCKS 7 /* long long */ + +/* #undef HAVE_TYPEOF_ST64_DEV */ +/* #undef HAVE_TYPEOF_ST64_INO */ +/* #undef HAVE_TYPEOF_ST64_NLINK */ +/* #undef HAVE_TYPEOF_ST64_SIZE */ +/* #undef HAVE_TYPEOF_ST64_BLKSIZE */ +/* #undef HAVE_TYPEOF_ST64_BLOCKS */ + +/* #undef HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC */ + +#define HAVE_TYPEOF_RLIM_MAX 7 /* long long */ + +/* Define if you have the /proc filesystem */ +#define HAVE_PROC_DIR 1 + +/* Define if you have the /proc/$$/fd directories */ +/* #undef HAVE_PROC_DIR_FD */ + +#define WITH_HELP 1 +#define WITH_STDIO 1 +#define WITH_FDNUM 1 +#define WITH_FILE 1 +#define WITH_CREAT 1 +#define WITH_GOPEN 1 +#define WITH_TERMIOS 1 +#define WITH_PIPE 1 +#define WITH_UNIX 1 +/* #undef WITH_ABSTRACT_UNIXSOCKET */ +#define WITH_IP4 1 +#define WITH_IP6 1 +#define WITH_RAWIP 1 +#define WITH_TCP 1 +#define WITH_UDP 1 +#define WITH_LISTEN 1 +#define WITH_SOCKS4 1 +#define WITH_SOCKS4A 1 +#define WITH_PROXY 1 +#define WITH_EXEC 1 +#define WITH_SYSTEM 1 +#define WITH_READLINE 1 +/* #undef WITH_TUN */ +#define WITH_PTY 1 +#define WITH_EXT2 1 +#define WITH_OPENSSL 1 +/* #undef WITH_FIPS */ +/* #undef OPENSSL_FIPS */ +#define WITH_LIBWRAP 1 +#define HAVE_TCPD_H 1 +#define HAVE_LIBWRAP 1 + +#define WITH_SYCLS 1 +#define WITH_FILAN 1 +#define WITH_RETRY 1 + +#define WITH_MSGLEVEL 0 + +#endif /* !defined(__config_h_included) */ diff --git a/Config/config.HP-UX-B-11-11.h b/Config/config.HP-UX-B-11-11.h new file mode 100644 index 0000000..a83b248 --- /dev/null +++ b/Config/config.HP-UX-B-11-11.h @@ -0,0 +1,485 @@ +/* config.h. Generated by configure. */ +/* $Id: config.HP-UX-B-11-11.h,v 1.7 2007/03/06 21:44:34 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __config_h_included +#define __config_h_included 1 + +/* Define to empty if the keyword does not work. */ +/* #undef const */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define if your struct stat has st_blksize. */ +#define HAVE_ST_BLKSIZE 1 + +/* Define if your struct stat has st_blocks. */ +#define HAVE_ST_BLOCKS 1 + +/* Define if your struct stat has st_rdev. */ +#define HAVE_ST_RDEV 1 + +/* Define if you have the strftime function. */ +#define HAVE_STRFTIME 1 + +/* Define if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to `int' if doesn't define. */ +/* #undef mode_t */ + +/* Define to `long' if doesn't define. */ +/* #undef off_t */ + +/* Define to `int' if doesn't define. */ +/* #undef pid_t */ + +/* Define as the return type of signal handlers (int or void). */ +#define RETSIGTYPE void + +/* Define to `unsigned' if doesn't define. */ +/* #undef size_t */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ + +/* Define if you have the putenv function. */ +#define HAVE_PUTENV 1 + +/* Define if you have the select function. */ +#define HAVE_SELECT 1 + +/* Define if you have the poll function. */ +#define HAVE_POLL 1 + +/* Define if you have the socket function. */ +#define HAVE_SOCKET 1 + +/* Define if you have the strdup function. */ +#define HAVE_STRDUP 1 + +/* Define if you have the strerror function. */ +#define HAVE_STRERROR 1 + +/* Define if you have the strstr function. */ +#define HAVE_STRSTR 1 + +/* Define if you have the strtod function. */ +#define HAVE_STRTOD 1 + +/* Define if you have the strtol function. */ +#define HAVE_STRTOL 1 + +/* Define if you have the strtoul function. */ +#define HAVE_STRTOUL 1 + +/* Define if you have the uname function. */ +#define HAVE_UNAME 1 + +/* Define if you have the getpgid function. */ +#define HAVE_GETPGID 1 + +/* Define if you have the getsid function. */ +#define HAVE_GETSID 1 + +/* Define if you have the nanosleep function. */ +#define HAVE_NANOSLEEP 1 + +/* Define if you have the getaddrinfo function. */ +#define HAVE_GETADDRINFO 1 + +/* Define if you have the getipnodebyname function. */ +#define HAVE_GETIPNODEBYNAME 1 + +/* Define if you have the setgroups function. */ +#define HAVE_SETGROUPS 1 + +/* Define if you have the inet_aton function. */ +#define HAVE_INET_ATON 1 + +/* Define if you have the memrchr function. */ +/* #undef HAVE_MEMRCHR */ + +/* Define if you have the sigaction function */ +#define HAVE_SIGACTION 1 + +/* Define if you have the stat64 function */ +#define HAVE_STAT64 1 + +/* Define if you have the fstat64 function */ +#define HAVE_FSTAT64 1 + +/* Define if you have the lstat64 function */ +#define HAVE_LSTAT64 1 + +/* Define if you have the lseek64 function */ +#define HAVE_LSEEK64 1 + +/* Define if you have the truncate64 function */ +#define HAVE_TRUNCATE64 1 + +/* Define if you have the ftruncate64 function */ +#define HAVE_FTRUNCATE64 1 + +/* Define if you have the strtoll function */ +/* #undef HAVE_STRTOLL */ + +/* Define if you have the hstrerror function */ +/* #undef HAVE_HSTRERROR */ + +/* Define if you have the inet_ntop function */ +#define HAVE_INET_NTOP 1 + +/* Define if you have the hstrerror prototype */ +/* #undef HAVE_PROTOTYPE_HSTRERROR */ + +/* Define if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYSLOG_H 1 + +/* Define if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if you have the header file. */ +#define HAVE_PWD_H 1 + +/* Define if you have the header file. */ +#define HAVE_GRP_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_STDINT_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_POLL_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UN_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_PTY_H */ + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_SYSTM_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IP_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IP6_H 1 + +/* Define if you have the header file. */ +#define HAVE_ARPA_NAMESER_H 1 + +/* Define if you have the header file. */ +#define HAVE_RESOLV_H 1 + +/* Define if you have the header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define if you have the header file. */ +#define HAVE_NET_IF_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_LINUX_IF_TUN_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_UTSNAME_H 1 + +/* Define if you have the header file. (AIX) */ +/* #undef HAVE_SYS_SELECT_H */ + +/* Define if you have the header file. (AIX) */ +#define HAVE_SYS_FILE_H 1 + +/* Define if you have the header file. (NetBSD, OpenBSD: openpty()) */ +/* #undef HAVE_UTIL_H */ + +/* Define if you have the header file. (FreeBSD: openpty()) */ +/* #undef HAVE_LIBUTIL_H */ + +/* Define if you have the header file. (stream opts on SunOS)*/ +#define HAVE_SYS_STROPTS_H 1 + +/* Define if you have the header file. */ +#define HAVE_REGEX_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_LINUX_FS_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_LINUX_EXT2_FS_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_READLINE_READLINE_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_READLINE_HISTORY_H */ + +/* Define if you have the readline library. */ +/* #undef HAVE_LIBREADLINE */ + +/* Define if you have the m library (-lm). */ +/* #undef HAVE_LIBM */ + +/* Define if you have the floor function */ +/* #undef HAVE_FLOOR */ + +/* some platforms need _XOPEN_EXTENDED_SOURCE to get syslog headers (AIX4.1) */ +/* #undef _XOPEN_EXTENDED_SOURCE */ + +/* fdset may have component fds_bits or __fds_bits */ +#define HAVE_FDS_BITS 1 + +/* Define if your struct termios has component c_ispeed */ +/* #undef HAVE_TERMIOS_ISPEED */ + +/* the offset of c_ispeed in struct termios - usable in an speed_t array. + Applies only when HAVE_TERMIOS_ISPEED is set */ +/* #undef ISPEED_OFFSET */ + +/* the offset of c_ospeed in struct termios - see ISPEED_OFFSET */ +#ifdef ISPEED_OFFSET +# define OSPEED_OFFSET (ISPEED_OFFSET+1) +#else +/* # undef OSPEED_OFFSET */ +#endif + +/* Define if your termios.h likes _SVID3 defined */ +/* #undef _SVID3 */ + +/* Define if you have struct timespec (e.g. for nanosleep) */ +#define HAVE_STRUCT_TIMESPEC 1 + +/* Define if you have struct linger */ +#define HAVE_STRUCT_LINGER 1 + +/* Define if you have struct ip_mreq */ +#define HAVE_STRUCT_IP_MREQ 1 + +/* Define if you have struct ip_mreqn */ +/* #undef HAVE_STRUCT_IP_MREQN */ + +/* Define if you have struct ipv6_mreq */ +#define HAVE_STRUCT_IPV6_MREQ 1 + +/* Define if you have struct ifreq */ +#define HAVE_STRUCT_IFREQ 1 + +/* Define if you have struct ifreq.ifr_index */ +#define HAVE_STRUCT_IFREQ_IFR_INDEX 1 + +/* Define if you have struct ifreq.ifr_ifindex */ +/* #undef HAVE_STRUCT_IFREQ_IFR_IFINDEX */ + +/* Define if your struct sockaddr has sa_len */ +/* #undef HAVE_STRUCT_SOCKADDR_SALEN */ + +/* there are several implementations of sockaddr_in6 */ +#define HAVE_IP6_SOCKADDR 0 + +/* Define if you have struct iovec */ +#define HAVE_STRUCT_IOVEC 1 + +/* define if your struct msghdr has msg_control */ +/* #undef HAVE_STRUCT_MSGHDR_MSGCONTROL */ + +/* define if your struct msghdr has msg_controllen */ +/* #undef HAVE_STRUCT_MSGHDR_MSGCONTROLLEN */ + +/* define if your struct msghdr has msg_flag */ +/* #undef HAVE_STRUCT_MSGHDR_MSGFLAGS */ + +/* define if your struct ip has ip_hl; otherwise assume ip_vhl */ +#define HAVE_STRUCT_IP_IP_HL 1 + +/* Define if you have the setenv function */ +/* #undef HAVE_SETENV */ + +/* Define if you have the flock function */ +/* #undef HAVE_FLOCK */ + +/* Define if you have the openpty function */ +/* #undef HAVE_OPENPTY */ + +/* Define if you have the grantpt function */ +#define HAVE_GRANTPT 1 + +/* Define if you have the unlockpt function */ +#define HAVE_UNLOCKPT 1 + +/* Define if you have the ptsname function */ +#define HAVE_PTSNAME 1 + +/* Define if you have the /dev/ptmx pseudo terminal multiplexer */ +#define HAVE_DEV_PTMX 1 + +/* Define if you have the /dev/ptc pseudo terminal multiplexer */ +/* #undef HAVE_DEV_PTC */ + +/* Define if you have the long long type */ +#define HAVE_TYPE_LONGLONG 1 + +/* is socklen_t already typedef'd? */ +#define HAVE_TYPE_SOCKLEN 1 + +/* Define if you have the struct stat64 type */ +/* #undef HAVE_TYPE_STAT64 */ + +/* Define if you have the struct off64_t type */ +#define HAVE_TYPE_OFF64 1 + +/* is sighandler_t already typedef'd? */ +/* #undef HAVE_TYPE_SIGHANDLER */ + +/* is uint8_t already defined? */ +#define HAVE_TYPE_UINT8 1 + +/* is uint16_t already defined? */ +#define HAVE_TYPE_UINT16 1 + +/* is uint32_t already defined? */ +#define HAVE_TYPE_UINT32 1 + +/* is uint64_t already defined? */ +#define HAVE_TYPE_UINT64 1 + +/* Define if you have the printf "Z" modifier */ +/* #undef HAVE_FORMAT_Z */ + +/* Define the shift offset of the CRDLY mask */ +#define CRDLY_SHIFT 9 + +/* Define the shift offset of the TABDLY mask */ +#define TABDLY_SHIFT 11 + +/* Define the shift offset of the CSIZE mask */ +#define CSIZE_SHIFT 5 + +/* Define if you have tcpwrappers (libwrap, tcpd) and it declares hosts_allow_table */ +/* #undef HAVE_HOSTS_ALLOW_TABLE */ +#if defined(HAVE_HOSTS_ALLOW_TABLE) && HAVE_HOSTS_ALLOW_TABLE +# define HAVE_HOSTS_DENY_TABLE 1 +#else +/* # undef HAVE_HOSTS_DENY_TABLE */ +#endif + +/* 1..short, 3..int, 5..long; 2,4,6..unsigned */ +#define HAVE_BASIC_SIZE_T 6 /* unsigned long */ +#define HAVE_BASIC_MODE_T 2 /* unsigned short */ +#define HAVE_BASIC_PID_T 3 /* int */ +#define HAVE_BASIC_UID_T 3 /* int */ +#define HAVE_BASIC_GID_T 3 /* int */ +#define HAVE_BASIC_TIME_T 5 /* long */ +#define HAVE_BASIC_OFF64_T 7 /* long long */ + +#define HAVE_BASIC_SOCKLEN_T 6 /* unsigned long */ + +#define HAVE_TYPEOF_ST_DEV 3 /* int */ +#define HAVE_TYPEOF_ST_INO 6 /* unsigned long */ +#define HAVE_TYPEOF_ST_NLINK 2 /* unsigned short */ +#define HAVE_TYPEOF_ST_SIZE 5 /* long */ +#define HAVE_TYPEOF_ST_BLKSIZE 5 /* long */ +#define HAVE_TYPEOF_ST_BLOCKS 5 /* long */ + +#define HAVE_TYPEOF_ST64_DEV 0 /* unknown, taking default */ +#define HAVE_TYPEOF_ST64_INO 0 /* unknown, taking default */ +#define HAVE_TYPEOF_ST64_NLINK 0 /* unknown, taking default */ +#define HAVE_TYPEOF_ST64_SIZE 0 /* unknown, taking default */ +#define HAVE_TYPEOF_ST64_BLKSIZE 0 /* unknown, taking default */ +#define HAVE_TYPEOF_ST64_BLOCKS 0 /* unknown, taking default */ + +/* #undef HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC */ + +#define HAVE_TYPEOF_RLIM_MAX 6 /* unsigned long */ + +/* Define if you have the /proc filesystem */ +/* #undef HAVE_PROC_DIR */ + +/* Define if you have the /proc/$$/fd directories */ +/* #undef HAVE_PROC_DIR_FD */ + +#define WITH_HELP 1 +#define WITH_STDIO 1 +#define WITH_FDNUM 1 +#define WITH_FILE 1 +#define WITH_CREAT 1 +#define WITH_GOPEN 1 +#define WITH_TERMIOS 1 +#define WITH_PIPE 1 +#define WITH_UNIX 1 +/* #undef WITH_ABSTRACT_UNIXSOCKET */ +#define WITH_IP4 1 +#define WITH_IP6 1 +#define WITH_RAWIP 1 +#define WITH_TCP 1 +#define WITH_UDP 1 +#define WITH_LISTEN 1 +#define WITH_SOCKS4 1 +#define WITH_SOCKS4A 1 +#define WITH_PROXY 1 +#define WITH_EXEC 1 +#define WITH_SYSTEM 1 +/* #undef WITH_READLINE */ +/* #undef WITH_TUN */ +#define WITH_PTY 1 +#define WITH_EXT2 1 +#define WITH_OPENSSL 1 +/* #undef WITH_FIPS */ +/* #undef OPENSSL_FIPS */ +/* #undef WITH_LIBWRAP */ +/* #undef HAVE_TCPD_H */ +/* #undef HAVE_LIBWRAP */ + +#define WITH_SYCLS 1 +#define WITH_FILAN 1 +#define WITH_RETRY 1 + +#define WITH_MSGLEVEL 0 + +#endif /* !defined(__config_h_included) */ diff --git a/Config/config.Linux-2-6-16.h b/Config/config.Linux-2-6-16.h new file mode 100644 index 0000000..15b8717 --- /dev/null +++ b/Config/config.Linux-2-6-16.h @@ -0,0 +1,485 @@ +/* config.h. Generated by configure. */ +/* $Id: config.Linux-2-6-16.h,v 1.1 2007/03/06 21:51:57 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __config_h_included +#define __config_h_included 1 + +/* Define to empty if the keyword does not work. */ +/* #undef const */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define if your struct stat has st_blksize. */ +#define HAVE_ST_BLKSIZE 1 + +/* Define if your struct stat has st_blocks. */ +#define HAVE_ST_BLOCKS 1 + +/* Define if your struct stat has st_rdev. */ +#define HAVE_ST_RDEV 1 + +/* Define if you have the strftime function. */ +#define HAVE_STRFTIME 1 + +/* Define if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to `int' if doesn't define. */ +/* #undef mode_t */ + +/* Define to `long' if doesn't define. */ +/* #undef off_t */ + +/* Define to `int' if doesn't define. */ +/* #undef pid_t */ + +/* Define as the return type of signal handlers (int or void). */ +#define RETSIGTYPE void + +/* Define to `unsigned' if doesn't define. */ +/* #undef size_t */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ + +/* Define if you have the putenv function. */ +#define HAVE_PUTENV 1 + +/* Define if you have the select function. */ +#define HAVE_SELECT 1 + +/* Define if you have the poll function. */ +#define HAVE_POLL 1 + +/* Define if you have the socket function. */ +#define HAVE_SOCKET 1 + +/* Define if you have the strdup function. */ +#define HAVE_STRDUP 1 + +/* Define if you have the strerror function. */ +#define HAVE_STRERROR 1 + +/* Define if you have the strstr function. */ +#define HAVE_STRSTR 1 + +/* Define if you have the strtod function. */ +#define HAVE_STRTOD 1 + +/* Define if you have the strtol function. */ +#define HAVE_STRTOL 1 + +/* Define if you have the strtoul function. */ +#define HAVE_STRTOUL 1 + +/* Define if you have the uname function. */ +#define HAVE_UNAME 1 + +/* Define if you have the getpgid function. */ +#define HAVE_GETPGID 1 + +/* Define if you have the getsid function. */ +#define HAVE_GETSID 1 + +/* Define if you have the nanosleep function. */ +#define HAVE_NANOSLEEP 1 + +/* Define if you have the getaddrinfo function. */ +#define HAVE_GETADDRINFO 1 + +/* Define if you have the getipnodebyname function. */ +/* #undef HAVE_GETIPNODEBYNAME */ + +/* Define if you have the setgroups function. */ +#define HAVE_SETGROUPS 1 + +/* Define if you have the inet_aton function. */ +#define HAVE_INET_ATON 1 + +/* Define if you have the memrchr function. */ +#define HAVE_MEMRCHR 1 + +/* Define if you have the sigaction function */ +#define HAVE_SIGACTION 1 + +/* Define if you have the stat64 function */ +#define HAVE_STAT64 1 + +/* Define if you have the fstat64 function */ +#define HAVE_FSTAT64 1 + +/* Define if you have the lstat64 function */ +#define HAVE_LSTAT64 1 + +/* Define if you have the lseek64 function */ +#define HAVE_LSEEK64 1 + +/* Define if you have the truncate64 function */ +#define HAVE_TRUNCATE64 1 + +/* Define if you have the ftruncate64 function */ +#define HAVE_FTRUNCATE64 1 + +/* Define if you have the strtoll function */ +#define HAVE_STRTOLL 1 + +/* Define if you have the hstrerror function */ +#define HAVE_HSTRERROR 1 + +/* Define if you have the inet_ntop function */ +#define HAVE_INET_NTOP 1 + +/* Define if you have the hstrerror prototype */ +#define HAVE_PROTOTYPE_HSTRERROR 1 + +/* Define if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYSLOG_H 1 + +/* Define if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if you have the header file. */ +#define HAVE_PWD_H 1 + +/* Define if you have the header file. */ +#define HAVE_GRP_H 1 + +/* Define if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_POLL_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UN_H 1 + +/* Define if you have the header file. */ +#define HAVE_PTY_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_SYSTM_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IP_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IP6_H 1 + +/* Define if you have the header file. */ +#define HAVE_ARPA_NAMESER_H 1 + +/* Define if you have the header file. */ +#define HAVE_RESOLV_H 1 + +/* Define if you have the header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define if you have the header file. */ +#define HAVE_NET_IF_H 1 + +/* Define if you have the header file. */ +#define HAVE_LINUX_IF_TUN_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UTSNAME_H 1 + +/* Define if you have the header file. (AIX) */ +#define HAVE_SYS_SELECT_H 1 + +/* Define if you have the header file. (AIX) */ +#define HAVE_SYS_FILE_H 1 + +/* Define if you have the header file. (NetBSD, OpenBSD: openpty()) */ +/* #undef HAVE_UTIL_H */ + +/* Define if you have the header file. (FreeBSD: openpty()) */ +/* #undef HAVE_LIBUTIL_H */ + +/* Define if you have the header file. (stream opts on SunOS)*/ +#define HAVE_SYS_STROPTS_H 1 + +/* Define if you have the header file. */ +#define HAVE_REGEX_H 1 + +/* Define if you have the header file. */ +#define HAVE_LINUX_FS_H 1 + +/* Define if you have the header file. */ +#define HAVE_LINUX_EXT2_FS_H 1 + +/* Define if you have the header file. */ +#define HAVE_READLINE_READLINE_H 1 + +/* Define if you have the header file. */ +#define HAVE_READLINE_HISTORY_H 1 + +/* Define if you have the readline library. */ +#define HAVE_LIBREADLINE 1 + +/* Define if you have the m library (-lm). */ +/* #undef HAVE_LIBM */ + +/* Define if you have the floor function */ +/* #undef HAVE_FLOOR */ + +/* some platforms need _XOPEN_EXTENDED_SOURCE to get syslog headers (AIX4.1) */ +/* #undef _XOPEN_EXTENDED_SOURCE */ + +/* fdset may have component fds_bits or __fds_bits */ +#define HAVE_FDS_BITS 1 + +/* Define if your struct termios has component c_ispeed */ +#define HAVE_TERMIOS_ISPEED 1 + +/* the offset of c_ispeed in struct termios - usable in an speed_t array. + Applies only when HAVE_TERMIOS_ISPEED is set */ +#define ISPEED_OFFSET 13 + +/* the offset of c_ospeed in struct termios - see ISPEED_OFFSET */ +#ifdef ISPEED_OFFSET +# define OSPEED_OFFSET (ISPEED_OFFSET+1) +#else +/* # undef OSPEED_OFFSET */ +#endif + +/* Define if your termios.h likes _SVID3 defined */ +/* #undef _SVID3 */ + +/* Define if you have struct timespec (e.g. for nanosleep) */ +#define HAVE_STRUCT_TIMESPEC 1 + +/* Define if you have struct linger */ +#define HAVE_STRUCT_LINGER 1 + +/* Define if you have struct ip_mreq */ +#define HAVE_STRUCT_IP_MREQ 1 + +/* Define if you have struct ip_mreqn */ +#define HAVE_STRUCT_IP_MREQN 1 + +/* Define if you have struct ipv6_mreq */ +#define HAVE_STRUCT_IPV6_MREQ 1 + +/* Define if you have struct ifreq */ +#define HAVE_STRUCT_IFREQ 1 + +/* Define if you have struct ifreq.ifr_index */ +/* #undef HAVE_STRUCT_IFREQ_IFR_INDEX */ + +/* Define if you have struct ifreq.ifr_ifindex */ +#define HAVE_STRUCT_IFREQ_IFR_IFINDEX 1 + +/* Define if your struct sockaddr has sa_len */ +/* #undef HAVE_STRUCT_SOCKADDR_SALEN */ + +/* there are several implementations of sockaddr_in6 */ +#define HAVE_IP6_SOCKADDR 0 + +/* Define if you have struct iovec */ +#define HAVE_STRUCT_IOVEC 1 + +/* define if your struct msghdr has msg_control */ +#define HAVE_STRUCT_MSGHDR_MSGCONTROL 1 + +/* define if your struct msghdr has msg_controllen */ +#define HAVE_STRUCT_MSGHDR_MSGCONTROLLEN 1 + +/* define if your struct msghdr has msg_flag */ +#define HAVE_STRUCT_MSGHDR_MSGFLAGS 1 + +/* define if your struct ip has ip_hl; otherwise assume ip_vhl */ +#define HAVE_STRUCT_IP_IP_HL 1 + +/* Define if you have the setenv function */ +#define HAVE_SETENV 1 + +/* Define if you have the flock function */ +#define HAVE_FLOCK 1 + +/* Define if you have the openpty function */ +#define HAVE_OPENPTY 1 + +/* Define if you have the grantpt function */ +#define HAVE_GRANTPT 1 + +/* Define if you have the unlockpt function */ +#define HAVE_UNLOCKPT 1 + +/* Define if you have the ptsname function */ +#define HAVE_PTSNAME 1 + +/* Define if you have the /dev/ptmx pseudo terminal multiplexer */ +#define HAVE_DEV_PTMX 1 + +/* Define if you have the /dev/ptc pseudo terminal multiplexer */ +/* #undef HAVE_DEV_PTC */ + +/* Define if you have the long long type */ +#define HAVE_TYPE_LONGLONG 1 + +/* is socklen_t already typedef'd? */ +#define HAVE_TYPE_SOCKLEN 1 + +/* Define if you have the struct stat64 type */ +#define HAVE_TYPE_STAT64 1 + +/* Define if you have the struct off64_t type */ +#define HAVE_TYPE_OFF64 1 + +/* is sighandler_t already typedef'd? */ +#define HAVE_TYPE_SIGHANDLER 1 + +/* is uint8_t already defined? */ +#define HAVE_TYPE_UINT8 1 + +/* is uint16_t already defined? */ +#define HAVE_TYPE_UINT16 1 + +/* is uint32_t already defined? */ +#define HAVE_TYPE_UINT32 1 + +/* is uint64_t already defined? */ +#define HAVE_TYPE_UINT64 1 + +/* Define if you have the printf "Z" modifier */ +#define HAVE_FORMAT_Z 1 + +/* Define the shift offset of the CRDLY mask */ +#define CRDLY_SHIFT 9 + +/* Define the shift offset of the TABDLY mask */ +#define TABDLY_SHIFT 11 + +/* Define the shift offset of the CSIZE mask */ +#define CSIZE_SHIFT 4 + +/* Define if you have tcpwrappers (libwrap, tcpd) and it declares hosts_allow_table */ +#define HAVE_HOSTS_ALLOW_TABLE 1 +#if defined(HAVE_HOSTS_ALLOW_TABLE) && HAVE_HOSTS_ALLOW_TABLE +# define HAVE_HOSTS_DENY_TABLE 1 +#else +/* # undef HAVE_HOSTS_DENY_TABLE */ +#endif + +/* 1..short, 3..int, 5..long; 2,4,6..unsigned */ +#define HAVE_BASIC_SIZE_T 4 /* unsigned int */ +#define HAVE_BASIC_MODE_T 4 /* unsigned int */ +#define HAVE_BASIC_PID_T 3 /* int */ +#define HAVE_BASIC_UID_T 4 /* unsigned int */ +#define HAVE_BASIC_GID_T 4 /* unsigned int */ +#define HAVE_BASIC_TIME_T 5 /* long */ +#define HAVE_BASIC_OFF64_T 7 /* long long */ + +#define HAVE_BASIC_SOCKLEN_T 4 /* unsigned int */ + +#define HAVE_TYPEOF_ST_DEV 8 /* unsigned long long */ +#define HAVE_TYPEOF_ST_INO 6 /* unsigned long */ +#define HAVE_TYPEOF_ST_NLINK 4 /* unsigned int */ +#define HAVE_TYPEOF_ST_SIZE 5 /* long */ +#define HAVE_TYPEOF_ST_BLKSIZE 5 /* long */ +#define HAVE_TYPEOF_ST_BLOCKS 5 /* long */ + +#define HAVE_TYPEOF_ST64_DEV 8 /* unsigned long long */ +#define HAVE_TYPEOF_ST64_INO 8 /* unsigned long long */ +#define HAVE_TYPEOF_ST64_NLINK 4 /* unsigned int */ +#define HAVE_TYPEOF_ST64_SIZE 7 /* long long */ +#define HAVE_TYPEOF_ST64_BLKSIZE 5 /* long */ +#define HAVE_TYPEOF_ST64_BLOCKS 7 /* long long */ + +/* #undef HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC */ + +#define HAVE_TYPEOF_RLIM_MAX 6 /* unsigned long */ + +/* Define if you have the /proc filesystem */ +#define HAVE_PROC_DIR 1 + +/* Define if you have the /proc/$$/fd directories */ +#define HAVE_PROC_DIR_FD 1 + +#define WITH_HELP 1 +#define WITH_STDIO 1 +#define WITH_FDNUM 1 +#define WITH_FILE 1 +#define WITH_CREAT 1 +#define WITH_GOPEN 1 +#define WITH_TERMIOS 1 +#define WITH_PIPE 1 +#define WITH_UNIX 1 +#define WITH_ABSTRACT_UNIXSOCKET 1 +#define WITH_IP4 1 +#define WITH_IP6 1 +#define WITH_RAWIP 1 +#define WITH_TCP 1 +#define WITH_UDP 1 +#define WITH_LISTEN 1 +#define WITH_SOCKS4 1 +#define WITH_SOCKS4A 1 +#define WITH_PROXY 1 +#define WITH_EXEC 1 +#define WITH_SYSTEM 1 +#define WITH_READLINE 1 +#define WITH_TUN 1 +#define WITH_PTY 1 +#define WITH_EXT2 1 +#define WITH_OPENSSL 1 +/* #undef WITH_FIPS */ +/* #undef OPENSSL_FIPS */ +#define WITH_LIBWRAP 1 +#define HAVE_TCPD_H 1 +#define HAVE_LIBWRAP 1 + +#define WITH_SYCLS 1 +#define WITH_FILAN 1 +#define WITH_RETRY 1 + +#define WITH_MSGLEVEL 0 + +#endif /* !defined(__config_h_included) */ diff --git a/Config/config.NetBSD-2-0-2.h b/Config/config.NetBSD-2-0-2.h new file mode 100644 index 0000000..8b82877 --- /dev/null +++ b/Config/config.NetBSD-2-0-2.h @@ -0,0 +1,450 @@ +/* config.h. Generated by configure. */ +/* $Id: config.NetBSD-2-0-2.h,v 1.1 2006/07/13 21:44:07 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __config_h_included +#define __config_h_included 1 + +/* Define to empty if the keyword does not work. */ +/* #undef const */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define if your struct stat has st_blksize. */ +#define HAVE_ST_BLKSIZE 1 + +/* Define if your struct stat has st_blocks. */ +#define HAVE_ST_BLOCKS 1 + +/* Define if your struct stat has st_rdev. */ +#define HAVE_ST_RDEV 1 + +/* Define if you have the strftime function. */ +#define HAVE_STRFTIME 1 + +/* Define if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to `int' if doesn't define. */ +/* #undef mode_t */ + +/* Define to `long' if doesn't define. */ +/* #undef off_t */ + +/* Define to `int' if doesn't define. */ +/* #undef pid_t */ + +/* Define as the return type of signal handlers (int or void). */ +#define RETSIGTYPE void + +/* Define to `unsigned' if doesn't define. */ +/* #undef size_t */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ + +/* Define if you have the putenv function. */ +#define HAVE_PUTENV 1 + +/* Define if you have the select function. */ +#define HAVE_SELECT 1 + +/* Define if you have the poll function. */ +#define HAVE_POLL 1 + +/* Define if you have the socket function. */ +#define HAVE_SOCKET 1 + +/* Define if you have the strdup function. */ +#define HAVE_STRDUP 1 + +/* Define if you have the strerror function. */ +#define HAVE_STRERROR 1 + +/* Define if you have the strstr function. */ +#define HAVE_STRSTR 1 + +/* Define if you have the strtod function. */ +#define HAVE_STRTOD 1 + +/* Define if you have the strtol function. */ +#define HAVE_STRTOL 1 + +/* Define if you have the strtoul function. */ +#define HAVE_STRTOUL 1 + +/* Define if you have the uname function. */ +#define HAVE_UNAME 1 + +/* Define if you have the getpgid function. */ +#define HAVE_GETPGID 1 + +/* Define if you have the getsid function. */ +#define HAVE_GETSID 1 + +/* Define if you have the nanosleep function. */ +#define HAVE_NANOSLEEP 1 + +/* Define if you have the getaddrinfo function. */ +#define HAVE_GETADDRINFO 1 + +/* Define if you have the getipnodebyname function. */ +/* #undef HAVE_GETIPNODEBYNAME */ + +/* Define if you have the setgroups function. */ +#define HAVE_SETGROUPS 1 + +/* Define if you have the inet_aton function. */ +#define HAVE_INET_ATON 1 + +/* Define if you have the memrchr function. */ +/* #undef HAVE_MEMRCHR */ + +/* Define if you have the sigaction function */ +#define HAVE_SIGACTION 1 + +/* Define if you have the stat64 function */ +/* #undef HAVE_STAT64 */ + +/* Define if you have the fstat64 function */ +/* #undef HAVE_FSTAT64 */ + +/* Define if you have the lstat64 function */ +/* #undef HAVE_LSTAT64 */ + +/* Define if you have the lseek64 function */ +/* #undef HAVE_LSEEK64 */ + +/* Define if you have the truncate64 function */ +/* #undef HAVE_TRUNCATE64 */ + +/* Define if you have the ftruncate64 function */ +/* #undef HAVE_FTRUNCATE64 */ + +/* Define if you have the strtoll function */ +#define HAVE_STRTOLL 1 + +/* Define if you have the hstrerror function */ +#define HAVE_HSTRERROR 1 + +/* Define if you have the hstrerror prototype */ +#define HAVE_PROTOTYPE_HSTRERROR 1 + +/* Define if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYSLOG_H 1 + +/* Define if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if you have the header file. */ +#define HAVE_PWD_H 1 + +/* Define if you have the header file. */ +#define HAVE_GRP_H 1 + +/* Define if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_POLL_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UN_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_PTY_H */ + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_SYSTM_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IP_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IP6_H 1 + +/* Define if you have the header file. */ +#define HAVE_RESOLV_H 1 + +/* Define if you have the header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define if you have the header file. */ +#define HAVE_NET_IF_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UTSNAME_H 1 + +/* Define if you have the header file. (AIX) */ +#define HAVE_SYS_SELECT_H 1 + +/* Define if you have the header file. (AIX) */ +#define HAVE_SYS_FILE_H 1 + +/* Define if you have the header file. (NetBSD, OpenBSD: openpty()) */ +#define HAVE_UTIL_H 1 + +/* Define if you have the header file. (FreeBSD: openpty()) */ +/* #undef HAVE_LIBUTIL_H */ + +/* Define if you have the header file. (stream opts on SunOS)*/ +/* #undef HAVE_SYS_STROPTS_H */ + +/* Define if you have the header file. */ +#define HAVE_REGEX_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_LINUX_EXT2_FS_H */ + +/* Define if you have the header file. */ +#define HAVE_READLINE_READLINE_H 1 + +/* Define if you have the header file. */ +#define HAVE_READLINE_HISTORY_H 1 + +/* Define if you have the readline library. */ +/* #undef HAVE_LIBREADLINE */ + +/* Define if you have the m library (-lm). */ +/* #undef HAVE_LIBM */ + +/* Define if you have the floor function */ +/* #undef HAVE_FLOOR */ + +/* some platforms need _XOPEN_EXTENDED_SOURCE to get syslog headers (AIX4.1) */ +/* #undef _XOPEN_EXTENDED_SOURCE */ + +/* fdset may have component fds_bits or __fds_bits */ +#define HAVE_FDS_BITS 1 + +/* Define if your struct termios has component c_ispeed */ +#define HAVE_TERMIOS_ISPEED 1 + +/* the offset of c_ispeed in struct termios - usable in an speed_t array. + Applies only when HAVE_TERMIOS_ISPEED is set */ +#define ISPEED_OFFSET 9 + +/* the offset of c_ospeed in struct termios - see ISPEED_OFFSET */ +#ifdef ISPEED_OFFSET +# define OSPEED_OFFSET (ISPEED_OFFSET+1) +#else +/* # undef OSPEED_OFFSET */ +#endif + +/* Define if your termios.h likes _SVID3 defined */ +/* #undef _SVID3 */ + +/* Define if you have struct timespec (e.g. for nanosleep) */ +#define HAVE_STRUCT_TIMESPEC 1 + +/* Define if you have struct linger */ +#define HAVE_STRUCT_LINGER 1 + +/* Define if your struct sockaddr has sa_len */ +#define HAVE_STRUCT_SOCKADDR_SALEN 1 + +/* there are several implementations of sockaddr_in6 */ +#define HAVE_IP6_SOCKADDR 0 + +/* Define if you have struct iovec */ +#define HAVE_STRUCT_IOVEC 1 + +/* define if your struct msghdr has msg_control */ +#define HAVE_STRUCT_MSGHDR_MSGCONTROL 1 + +/* define if your struct msghdr has msg_controllen */ +#define HAVE_STRUCT_MSGHDR_MSGCONTROLLEN 1 + +/* define if your struct msghdr has msg_flag */ +#define HAVE_STRUCT_MSGHDR_MSGFLAGS 1 + +/* define if your struct ip has ip_hl; otherwise assume ip_vhl */ +#define HAVE_STRUCT_IP_IP_HL 1 + +/* Define if you have the setenv function */ +#define HAVE_SETENV 1 + +/* Define if you have the flock function */ +#define HAVE_FLOCK 1 + +/* Define if you have the openpty function */ +#define HAVE_OPENPTY 1 + +/* Define if you have the grantpt function */ +/* #undef HAVE_GRANTPT */ + +/* Define if you have the unlockpt function */ +/* #undef HAVE_UNLOCKPT */ + +/* Define if you have the ptsname function */ +/* #undef HAVE_PTSNAME */ + +/* Define if you have the /dev/ptmx pseudo terminal multiplexer */ +/* #undef HAVE_DEV_PTMX */ + +/* Define if you have the /dev/ptc pseudo terminal multiplexer */ +/* #undef HAVE_DEV_PTC */ + +/* Define if you have the long long type */ +#define HAVE_TYPE_LONGLONG 1 + +/* is socklen_t already typedef'd? */ +#define HAVE_TYPE_SOCKLEN 1 + +/* Define if you have the struct stat64 type */ +/* #undef HAVE_TYPE_STAT64 */ + +/* Define if you have the struct off64_t type */ +/* #undef HAVE_TYPE_OFF64 */ + +/* is sighandler_t already typedef'd? */ +/* #undef HAVE_TYPE_SIGHANDLER */ + +/* is uint8_t already defined? */ +#define HAVE_TYPE_UINT8 1 + +/* is uint16_t already defined? */ +#define HAVE_TYPE_UINT16 1 + +/* is uint32_t already defined? */ +#define HAVE_TYPE_UINT32 1 + +/* Define if you have the printf "Z" modifier */ +/* #undef HAVE_FORMAT_Z */ + +/* Define the shift offset of the CRDLY mask */ +#define CRDLY_SHIFT -1 + +/* Define the shift offset of the TABDLY mask */ +#define TABDLY_SHIFT -1 + +/* Define the shift offset of the CSIZE mask */ +#define CSIZE_SHIFT 8 + +/* Define if you have tcpwrappers (libwrap, tcpd) and it declares hosts_allow_table */ +#define HAVE_HOSTS_ALLOW_TABLE 1 +#if defined(HAVE_HOSTS_ALLOW_TABLE) && HAVE_HOSTS_ALLOW_TABLE + #define HAVE_HOSTS_DENY_TABLE 1 +#else +/* #undef HAVE_HOSTS_DENY_TABLE */ +#endif + +/* 1..short, 3..int, 5..long; 2,4,6..unsigned */ +#define HAVE_BASIC_SIZE_T 4 /* unsigned int */ +#define HAVE_BASIC_MODE_T 4 /* unsigned int */ +#define HAVE_BASIC_PID_T 3 /* int */ +#define HAVE_BASIC_UID_T 4 /* unsigned int */ +#define HAVE_BASIC_GID_T 4 /* unsigned int */ +#define HAVE_BASIC_TIME_T 5 /* long */ +#define HAVE_BASIC_OFF64_T 0 /* unknown, taking default */ + +#define HAVE_BASIC_SOCKLEN_T 4 /* unsigned int */ + +#define HAVE_TYPEOF_ST_DEV 4 /* unsigned int */ +#define HAVE_TYPEOF_ST_INO 4 /* unsigned int */ +#define HAVE_TYPEOF_ST_NLINK 4 /* unsigned int */ +#define HAVE_TYPEOF_ST_SIZE 7 /* long long */ +#define HAVE_TYPEOF_ST_BLKSIZE 4 /* unsigned int */ +#define HAVE_TYPEOF_ST_BLOCKS 7 /* long long */ + +/* #undef HAVE_TYPEOF_ST64_DEV */ +/* #undef HAVE_TYPEOF_ST64_INO */ +/* #undef HAVE_TYPEOF_ST64_NLINK */ +/* #undef HAVE_TYPEOF_ST64_SIZE */ +/* #undef HAVE_TYPEOF_ST64_BLKSIZE */ +/* #undef HAVE_TYPEOF_ST64_BLOCKS */ + +/* #undef HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC */ + +#define HAVE_TYPEOF_RLIM_MAX 7 /* long long */ + +/* Define if you have the /proc filesystem */ +#define HAVE_PROC_DIR 1 + +/* Define if you have the /proc/$$/fd directories */ +/* #undef HAVE_PROC_DIR_FD */ + +#define WITH_HELP 1 +#define WITH_STDIO 1 +#define WITH_FDNUM 1 +#define WITH_FILE 1 +#define WITH_CREAT 1 +#define WITH_GOPEN 1 +#define WITH_TERMIOS 1 +#define WITH_PIPE 1 +#define WITH_UNIX 1 +#define WITH_IP4 1 +#define WITH_IP6 1 +#define WITH_RAWIP 1 +#define WITH_TCP 1 +#define WITH_UDP 1 +#define WITH_LISTEN 1 +#define WITH_SOCKS4 1 +#define WITH_SOCKS4A 1 +#define WITH_PROXY 1 +#define WITH_EXEC 1 +#define WITH_SYSTEM 1 +/* #undef WITH_READLINE */ +#define WITH_PTY 1 +#define WITH_EXT2 1 +#define WITH_OPENSSL 1 +/* #undef WITH_FIPS */ +/* #undef OPENSSL_FIPS */ +#define WITH_LIBWRAP 1 +#define HAVE_TCPD_H 1 +#define HAVE_LIBWRAP 1 + +#define WITH_SYCLS 1 +#define WITH_FILAN 1 +#define WITH_RETRY 1 + +#define WITH_MSGLEVEL 0 + +#endif /* !defined(__config_h_included) */ diff --git a/Config/config.OpenBSD-3-8.h b/Config/config.OpenBSD-3-8.h new file mode 100644 index 0000000..14b32a8 --- /dev/null +++ b/Config/config.OpenBSD-3-8.h @@ -0,0 +1,450 @@ +/* config.h. Generated by configure. */ +/* $Id: config.OpenBSD-3-8.h,v 1.1 2006/07/13 21:44:11 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __config_h_included +#define __config_h_included 1 + +/* Define to empty if the keyword does not work. */ +/* #undef const */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define if your struct stat has st_blksize. */ +#define HAVE_ST_BLKSIZE 1 + +/* Define if your struct stat has st_blocks. */ +#define HAVE_ST_BLOCKS 1 + +/* Define if your struct stat has st_rdev. */ +#define HAVE_ST_RDEV 1 + +/* Define if you have the strftime function. */ +#define HAVE_STRFTIME 1 + +/* Define if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to `int' if doesn't define. */ +/* #undef mode_t */ + +/* Define to `long' if doesn't define. */ +/* #undef off_t */ + +/* Define to `int' if doesn't define. */ +/* #undef pid_t */ + +/* Define as the return type of signal handlers (int or void). */ +#define RETSIGTYPE void + +/* Define to `unsigned' if doesn't define. */ +/* #undef size_t */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ + +/* Define if you have the putenv function. */ +#define HAVE_PUTENV 1 + +/* Define if you have the select function. */ +#define HAVE_SELECT 1 + +/* Define if you have the poll function. */ +#define HAVE_POLL 1 + +/* Define if you have the socket function. */ +#define HAVE_SOCKET 1 + +/* Define if you have the strdup function. */ +#define HAVE_STRDUP 1 + +/* Define if you have the strerror function. */ +#define HAVE_STRERROR 1 + +/* Define if you have the strstr function. */ +#define HAVE_STRSTR 1 + +/* Define if you have the strtod function. */ +#define HAVE_STRTOD 1 + +/* Define if you have the strtol function. */ +#define HAVE_STRTOL 1 + +/* Define if you have the strtoul function. */ +#define HAVE_STRTOUL 1 + +/* Define if you have the uname function. */ +#define HAVE_UNAME 1 + +/* Define if you have the getpgid function. */ +#define HAVE_GETPGID 1 + +/* Define if you have the getsid function. */ +#define HAVE_GETSID 1 + +/* Define if you have the nanosleep function. */ +#define HAVE_NANOSLEEP 1 + +/* Define if you have the getaddrinfo function. */ +#define HAVE_GETADDRINFO 1 + +/* Define if you have the getipnodebyname function. */ +/* #undef HAVE_GETIPNODEBYNAME */ + +/* Define if you have the setgroups function. */ +#define HAVE_SETGROUPS 1 + +/* Define if you have the inet_aton function. */ +#define HAVE_INET_ATON 1 + +/* Define if you have the memrchr function. */ +/* #undef HAVE_MEMRCHR */ + +/* Define if you have the sigaction function */ +#define HAVE_SIGACTION 1 + +/* Define if you have the stat64 function */ +/* #undef HAVE_STAT64 */ + +/* Define if you have the fstat64 function */ +/* #undef HAVE_FSTAT64 */ + +/* Define if you have the lstat64 function */ +/* #undef HAVE_LSTAT64 */ + +/* Define if you have the lseek64 function */ +/* #undef HAVE_LSEEK64 */ + +/* Define if you have the truncate64 function */ +/* #undef HAVE_TRUNCATE64 */ + +/* Define if you have the ftruncate64 function */ +/* #undef HAVE_FTRUNCATE64 */ + +/* Define if you have the strtoll function */ +#define HAVE_STRTOLL 1 + +/* Define if you have the hstrerror function */ +#define HAVE_HSTRERROR 1 + +/* Define if you have the hstrerror prototype */ +#define HAVE_PROTOTYPE_HSTRERROR 1 + +/* Define if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYSLOG_H 1 + +/* Define if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if you have the header file. */ +#define HAVE_PWD_H 1 + +/* Define if you have the header file. */ +#define HAVE_GRP_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_STDINT_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_POLL_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UN_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_PTY_H */ + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_SYSTM_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IP_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IP6_H 1 + +/* Define if you have the header file. */ +#define HAVE_RESOLV_H 1 + +/* Define if you have the header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define if you have the header file. */ +#define HAVE_NET_IF_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UTSNAME_H 1 + +/* Define if you have the header file. (AIX) */ +#define HAVE_SYS_SELECT_H 1 + +/* Define if you have the header file. (AIX) */ +#define HAVE_SYS_FILE_H 1 + +/* Define if you have the header file. (NetBSD, OpenBSD: openpty()) */ +#define HAVE_UTIL_H 1 + +/* Define if you have the header file. (FreeBSD: openpty()) */ +/* #undef HAVE_LIBUTIL_H */ + +/* Define if you have the header file. (stream opts on SunOS)*/ +/* #undef HAVE_SYS_STROPTS_H */ + +/* Define if you have the header file. */ +#define HAVE_REGEX_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_LINUX_EXT2_FS_H */ + +/* Define if you have the header file. */ +#define HAVE_READLINE_READLINE_H 1 + +/* Define if you have the header file. */ +#define HAVE_READLINE_HISTORY_H 1 + +/* Define if you have the readline library. */ +#define HAVE_LIBREADLINE 1 + +/* Define if you have the m library (-lm). */ +/* #undef HAVE_LIBM */ + +/* Define if you have the floor function */ +/* #undef HAVE_FLOOR */ + +/* some platforms need _XOPEN_EXTENDED_SOURCE to get syslog headers (AIX4.1) */ +/* #undef _XOPEN_EXTENDED_SOURCE */ + +/* fdset may have component fds_bits or __fds_bits */ +#define HAVE_FDS_BITS 1 + +/* Define if your struct termios has component c_ispeed */ +#define HAVE_TERMIOS_ISPEED 1 + +/* the offset of c_ispeed in struct termios - usable in an speed_t array. + Applies only when HAVE_TERMIOS_ISPEED is set */ +#define ISPEED_OFFSET 9 + +/* the offset of c_ospeed in struct termios - see ISPEED_OFFSET */ +#ifdef ISPEED_OFFSET +# define OSPEED_OFFSET (ISPEED_OFFSET+1) +#else +/* # undef OSPEED_OFFSET */ +#endif + +/* Define if your termios.h likes _SVID3 defined */ +/* #undef _SVID3 */ + +/* Define if you have struct timespec (e.g. for nanosleep) */ +#define HAVE_STRUCT_TIMESPEC 1 + +/* Define if you have struct linger */ +#define HAVE_STRUCT_LINGER 1 + +/* Define if your struct sockaddr has sa_len */ +#define HAVE_STRUCT_SOCKADDR_SALEN 1 + +/* there are several implementations of sockaddr_in6 */ +#define HAVE_IP6_SOCKADDR 0 + +/* Define if you have struct iovec */ +/* #undef HAVE_STRUCT_IOVEC */ + +/* define if your struct msghdr has msg_control */ +#define HAVE_STRUCT_MSGHDR_MSGCONTROL 1 + +/* define if your struct msghdr has msg_controllen */ +#define HAVE_STRUCT_MSGHDR_MSGCONTROLLEN 1 + +/* define if your struct msghdr has msg_flag */ +#define HAVE_STRUCT_MSGHDR_MSGFLAGS 1 + +/* define if your struct ip has ip_hl; otherwise assume ip_vhl */ +#define HAVE_STRUCT_IP_IP_HL 1 + +/* Define if you have the setenv function */ +#define HAVE_SETENV 1 + +/* Define if you have the flock function */ +#define HAVE_FLOCK 1 + +/* Define if you have the openpty function */ +#define HAVE_OPENPTY 1 + +/* Define if you have the grantpt function */ +/* #undef HAVE_GRANTPT */ + +/* Define if you have the unlockpt function */ +/* #undef HAVE_UNLOCKPT */ + +/* Define if you have the ptsname function */ +/* #undef HAVE_PTSNAME */ + +/* Define if you have the /dev/ptmx pseudo terminal multiplexer */ +/* #undef HAVE_DEV_PTMX */ + +/* Define if you have the /dev/ptc pseudo terminal multiplexer */ +/* #undef HAVE_DEV_PTC */ + +/* Define if you have the long long type */ +#define HAVE_TYPE_LONGLONG 1 + +/* is socklen_t already typedef'd? */ +#define HAVE_TYPE_SOCKLEN 1 + +/* Define if you have the struct stat64 type */ +/* #undef HAVE_TYPE_STAT64 */ + +/* Define if you have the struct off64_t type */ +/* #undef HAVE_TYPE_OFF64 */ + +/* is sighandler_t already typedef'd? */ +/* #undef HAVE_TYPE_SIGHANDLER */ + +/* is uint8_t already defined? */ +#define HAVE_TYPE_UINT8 1 + +/* is uint16_t already defined? */ +#define HAVE_TYPE_UINT16 1 + +/* is uint32_t already defined? */ +#define HAVE_TYPE_UINT32 1 + +/* Define if you have the printf "Z" modifier */ +/* #undef HAVE_FORMAT_Z */ + +/* Define the shift offset of the CRDLY mask */ +#define CRDLY_SHIFT -1 + +/* Define the shift offset of the TABDLY mask */ +#define TABDLY_SHIFT -1 + +/* Define the shift offset of the CSIZE mask */ +#define CSIZE_SHIFT 8 + +/* Define if you have tcpwrappers (libwrap, tcpd) and it declares hosts_allow_table */ +#define HAVE_HOSTS_ALLOW_TABLE 1 +#if defined(HAVE_HOSTS_ALLOW_TABLE) && HAVE_HOSTS_ALLOW_TABLE + #define HAVE_HOSTS_DENY_TABLE 1 +#else +/* #undef HAVE_HOSTS_DENY_TABLE */ +#endif + +/* 1..short, 3..int, 5..long; 2,4,6..unsigned */ +#define HAVE_BASIC_SIZE_T 4 /* unsigned int */ +#define HAVE_BASIC_MODE_T 4 /* unsigned int */ +#define HAVE_BASIC_PID_T 3 /* int */ +#define HAVE_BASIC_UID_T 4 /* unsigned int */ +#define HAVE_BASIC_GID_T 4 /* unsigned int */ +#define HAVE_BASIC_TIME_T 3 /* int */ +#define HAVE_BASIC_OFF64_T 0 /* unknown, taking default */ + +#define HAVE_BASIC_SOCKLEN_T 4 /* unsigned int */ + +#define HAVE_TYPEOF_ST_DEV 3 /* int */ +#define HAVE_TYPEOF_ST_INO 4 /* unsigned int */ +#define HAVE_TYPEOF_ST_NLINK 4 /* unsigned int */ +#define HAVE_TYPEOF_ST_SIZE 7 /* long long */ +#define HAVE_TYPEOF_ST_BLKSIZE 4 /* unsigned int */ +#define HAVE_TYPEOF_ST_BLOCKS 7 /* long long */ + +/* #undef HAVE_TYPEOF_ST64_DEV */ +/* #undef HAVE_TYPEOF_ST64_INO */ +/* #undef HAVE_TYPEOF_ST64_NLINK */ +/* #undef HAVE_TYPEOF_ST64_SIZE */ +/* #undef HAVE_TYPEOF_ST64_BLKSIZE */ +/* #undef HAVE_TYPEOF_ST64_BLOCKS */ + +/* #undef HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC */ + +#define HAVE_TYPEOF_RLIM_MAX 8 /* unsigned long long */ + +/* Define if you have the /proc filesystem */ +/* #undef HAVE_PROC_DIR */ + +/* Define if you have the /proc/$$/fd directories */ +/* #undef HAVE_PROC_DIR_FD */ + +#define WITH_HELP 1 +#define WITH_STDIO 1 +#define WITH_FDNUM 1 +#define WITH_FILE 1 +#define WITH_CREAT 1 +#define WITH_GOPEN 1 +#define WITH_TERMIOS 1 +#define WITH_PIPE 1 +#define WITH_UNIX 1 +#define WITH_IP4 1 +#define WITH_IP6 1 +#define WITH_RAWIP 1 +#define WITH_TCP 1 +#define WITH_UDP 1 +#define WITH_LISTEN 1 +#define WITH_SOCKS4 1 +#define WITH_SOCKS4A 1 +#define WITH_PROXY 1 +#define WITH_EXEC 1 +#define WITH_SYSTEM 1 +#define WITH_READLINE 1 +#define WITH_PTY 1 +#define WITH_EXT2 1 +#define WITH_OPENSSL 1 +/* #undef WITH_FIPS */ +/* #undef OPENSSL_FIPS */ +#define WITH_LIBWRAP 1 +#define HAVE_TCPD_H 1 +#define HAVE_LIBWRAP 1 + +#define WITH_SYCLS 1 +#define WITH_FILAN 1 +#define WITH_RETRY 1 + +#define WITH_MSGLEVEL 0 + +#endif /* !defined(__config_h_included) */ diff --git a/Config/config.SunOS-5-8.h b/Config/config.SunOS-5-8.h new file mode 100644 index 0000000..ce9790b --- /dev/null +++ b/Config/config.SunOS-5-8.h @@ -0,0 +1,485 @@ +/* config.h. Generated by configure. */ +/* $Id: config.SunOS-5-8.h,v 1.18 2007/03/06 21:44:34 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __config_h_included +#define __config_h_included 1 + +/* Define to empty if the keyword does not work. */ +/* #undef const */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define if your struct stat has st_blksize. */ +#define HAVE_ST_BLKSIZE 1 + +/* Define if your struct stat has st_blocks. */ +#define HAVE_ST_BLOCKS 1 + +/* Define if your struct stat has st_rdev. */ +#define HAVE_ST_RDEV 1 + +/* Define if you have the strftime function. */ +#define HAVE_STRFTIME 1 + +/* Define if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to `int' if doesn't define. */ +/* #undef mode_t */ + +/* Define to `long' if doesn't define. */ +/* #undef off_t */ + +/* Define to `int' if doesn't define. */ +/* #undef pid_t */ + +/* Define as the return type of signal handlers (int or void). */ +#define RETSIGTYPE void + +/* Define to `unsigned' if doesn't define. */ +/* #undef size_t */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ + +/* Define if you have the putenv function. */ +#define HAVE_PUTENV 1 + +/* Define if you have the select function. */ +#define HAVE_SELECT 1 + +/* Define if you have the poll function. */ +#define HAVE_POLL 1 + +/* Define if you have the socket function. */ +#define HAVE_SOCKET 1 + +/* Define if you have the strdup function. */ +#define HAVE_STRDUP 1 + +/* Define if you have the strerror function. */ +#define HAVE_STRERROR 1 + +/* Define if you have the strstr function. */ +#define HAVE_STRSTR 1 + +/* Define if you have the strtod function. */ +#define HAVE_STRTOD 1 + +/* Define if you have the strtol function. */ +#define HAVE_STRTOL 1 + +/* Define if you have the strtoul function. */ +#define HAVE_STRTOUL 1 + +/* Define if you have the uname function. */ +#define HAVE_UNAME 1 + +/* Define if you have the getpgid function. */ +#define HAVE_GETPGID 1 + +/* Define if you have the getsid function. */ +#define HAVE_GETSID 1 + +/* Define if you have the nanosleep function. */ +#define HAVE_NANOSLEEP 1 + +/* Define if you have the getaddrinfo function. */ +#define HAVE_GETADDRINFO 1 + +/* Define if you have the getipnodebyname function. */ +#define HAVE_GETIPNODEBYNAME 1 + +/* Define if you have the setgroups function. */ +#define HAVE_SETGROUPS 1 + +/* Define if you have the inet_aton function. */ +#define HAVE_INET_ATON 1 + +/* Define if you have the memrchr function. */ +/* #undef HAVE_MEMRCHR */ + +/* Define if you have the sigaction function */ +#define HAVE_SIGACTION 1 + +/* Define if you have the stat64 function */ +#define HAVE_STAT64 1 + +/* Define if you have the fstat64 function */ +#define HAVE_FSTAT64 1 + +/* Define if you have the lstat64 function */ +#define HAVE_LSTAT64 1 + +/* Define if you have the lseek64 function */ +#define HAVE_LSEEK64 1 + +/* Define if you have the truncate64 function */ +#define HAVE_TRUNCATE64 1 + +/* Define if you have the ftruncate64 function */ +#define HAVE_FTRUNCATE64 1 + +/* Define if you have the strtoll function */ +#define HAVE_STRTOLL 1 + +/* Define if you have the hstrerror function */ +#define HAVE_HSTRERROR 1 + +/* Define if you have the inet_ntop function */ +#define HAVE_INET_NTOP 1 + +/* Define if you have the hstrerror prototype */ +#define HAVE_PROTOTYPE_HSTRERROR 1 + +/* Define if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYSLOG_H 1 + +/* Define if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if you have the header file. */ +#define HAVE_PWD_H 1 + +/* Define if you have the header file. */ +#define HAVE_GRP_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_STDINT_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_POLL_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UN_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_PTY_H */ + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_SYSTM_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IP_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IP6_H 1 + +/* Define if you have the header file. */ +#define HAVE_ARPA_NAMESER_H 1 + +/* Define if you have the header file. */ +#define HAVE_RESOLV_H 1 + +/* Define if you have the header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define if you have the header file. */ +#define HAVE_NET_IF_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_LINUX_IF_TUN_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_UTSNAME_H 1 + +/* Define if you have the header file. (AIX) */ +#define HAVE_SYS_SELECT_H 1 + +/* Define if you have the header file. (AIX) */ +#define HAVE_SYS_FILE_H 1 + +/* Define if you have the header file. (NetBSD, OpenBSD: openpty()) */ +/* #undef HAVE_UTIL_H */ + +/* Define if you have the header file. (FreeBSD: openpty()) */ +/* #undef HAVE_LIBUTIL_H */ + +/* Define if you have the header file. (stream opts on SunOS)*/ +#define HAVE_SYS_STROPTS_H 1 + +/* Define if you have the header file. */ +#define HAVE_REGEX_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_LINUX_FS_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_LINUX_EXT2_FS_H */ + +/* Define if you have the header file. */ +#define HAVE_READLINE_READLINE_H 1 + +/* Define if you have the header file. */ +#define HAVE_READLINE_HISTORY_H 1 + +/* Define if you have the readline library. */ +#define HAVE_LIBREADLINE 1 + +/* Define if you have the m library (-lm). */ +/* #undef HAVE_LIBM */ + +/* Define if you have the floor function */ +/* #undef HAVE_FLOOR */ + +/* some platforms need _XOPEN_EXTENDED_SOURCE to get syslog headers (AIX4.1) */ +/* #undef _XOPEN_EXTENDED_SOURCE */ + +/* fdset may have component fds_bits or __fds_bits */ +#define HAVE_FDS_BITS 1 + +/* Define if your struct termios has component c_ispeed */ +/* #undef HAVE_TERMIOS_ISPEED */ + +/* the offset of c_ispeed in struct termios - usable in an speed_t array. + Applies only when HAVE_TERMIOS_ISPEED is set */ +/* #undef ISPEED_OFFSET */ + +/* the offset of c_ospeed in struct termios - see ISPEED_OFFSET */ +#ifdef ISPEED_OFFSET +# define OSPEED_OFFSET (ISPEED_OFFSET+1) +#else +/* # undef OSPEED_OFFSET */ +#endif + +/* Define if your termios.h likes _SVID3 defined */ +/* #undef _SVID3 */ + +/* Define if you have struct timespec (e.g. for nanosleep) */ +#define HAVE_STRUCT_TIMESPEC 1 + +/* Define if you have struct linger */ +#define HAVE_STRUCT_LINGER 1 + +/* Define if you have struct ip_mreq */ +#define HAVE_STRUCT_IP_MREQ 1 + +/* Define if you have struct ip_mreqn */ +/* #undef HAVE_STRUCT_IP_MREQN */ + +/* Define if you have struct ipv6_mreq */ +#define HAVE_STRUCT_IPV6_MREQ 1 + +/* Define if you have struct ifreq */ +#define HAVE_STRUCT_IFREQ 1 + +/* Define if you have struct ifreq.ifr_index */ +#define HAVE_STRUCT_IFREQ_IFR_INDEX 1 + +/* Define if you have struct ifreq.ifr_ifindex */ +/* #undef HAVE_STRUCT_IFREQ_IFR_IFINDEX */ + +/* Define if your struct sockaddr has sa_len */ +/* #undef HAVE_STRUCT_SOCKADDR_SALEN */ + +/* there are several implementations of sockaddr_in6 */ +#define HAVE_IP6_SOCKADDR 0 + +/* Define if you have struct iovec */ +#define HAVE_STRUCT_IOVEC 1 + +/* define if your struct msghdr has msg_control */ +/* #undef HAVE_STRUCT_MSGHDR_MSGCONTROL */ + +/* define if your struct msghdr has msg_controllen */ +/* #undef HAVE_STRUCT_MSGHDR_MSGCONTROLLEN */ + +/* define if your struct msghdr has msg_flag */ +/* #undef HAVE_STRUCT_MSGHDR_MSGFLAGS */ + +/* define if your struct ip has ip_hl; otherwise assume ip_vhl */ +#define HAVE_STRUCT_IP_IP_HL 1 + +/* Define if you have the setenv function */ +/* #undef HAVE_SETENV */ + +/* Define if you have the flock function */ +/* #undef HAVE_FLOCK */ + +/* Define if you have the openpty function */ +/* #undef HAVE_OPENPTY */ + +/* Define if you have the grantpt function */ +#define HAVE_GRANTPT 1 + +/* Define if you have the unlockpt function */ +#define HAVE_UNLOCKPT 1 + +/* Define if you have the ptsname function */ +#define HAVE_PTSNAME 1 + +/* Define if you have the /dev/ptmx pseudo terminal multiplexer */ +#define HAVE_DEV_PTMX 1 + +/* Define if you have the /dev/ptc pseudo terminal multiplexer */ +/* #undef HAVE_DEV_PTC */ + +/* Define if you have the long long type */ +#define HAVE_TYPE_LONGLONG 1 + +/* is socklen_t already typedef'd? */ +#define HAVE_TYPE_SOCKLEN 1 + +/* Define if you have the struct stat64 type */ +#define HAVE_TYPE_STAT64 1 + +/* Define if you have the struct off64_t type */ +#define HAVE_TYPE_OFF64 1 + +/* is sighandler_t already typedef'd? */ +/* #undef HAVE_TYPE_SIGHANDLER */ + +/* is uint8_t already defined? */ +#define HAVE_TYPE_UINT8 1 + +/* is uint16_t already defined? */ +#define HAVE_TYPE_UINT16 1 + +/* is uint32_t already defined? */ +#define HAVE_TYPE_UINT32 1 + +/* is uint64_t already defined? */ +#define HAVE_TYPE_UINT64 1 + +/* Define if you have the printf "Z" modifier */ +/* #undef HAVE_FORMAT_Z */ + +/* Define the shift offset of the CRDLY mask */ +#define CRDLY_SHIFT 9 + +/* Define the shift offset of the TABDLY mask */ +#define TABDLY_SHIFT 11 + +/* Define the shift offset of the CSIZE mask */ +#define CSIZE_SHIFT 4 + +/* Define if you have tcpwrappers (libwrap, tcpd) and it declares hosts_allow_table */ +#define HAVE_HOSTS_ALLOW_TABLE 1 +#if defined(HAVE_HOSTS_ALLOW_TABLE) && HAVE_HOSTS_ALLOW_TABLE +# define HAVE_HOSTS_DENY_TABLE 1 +#else +/* # undef HAVE_HOSTS_DENY_TABLE */ +#endif + +/* 1..short, 3..int, 5..long; 2,4,6..unsigned */ +#define HAVE_BASIC_SIZE_T 4 /* unsigned int */ +#define HAVE_BASIC_MODE_T 6 /* unsigned long */ +#define HAVE_BASIC_PID_T 5 /* long */ +#define HAVE_BASIC_UID_T 5 /* long */ +#define HAVE_BASIC_GID_T 5 /* long */ +#define HAVE_BASIC_TIME_T 5 /* long */ +#define HAVE_BASIC_OFF64_T 7 /* long long */ + +#define HAVE_BASIC_SOCKLEN_T 4 /* unsigned int */ + +#define HAVE_TYPEOF_ST_DEV 6 /* unsigned long */ +#define HAVE_TYPEOF_ST_INO 6 /* unsigned long */ +#define HAVE_TYPEOF_ST_NLINK 6 /* unsigned long */ +#define HAVE_TYPEOF_ST_SIZE 5 /* long */ +#define HAVE_TYPEOF_ST_BLKSIZE 5 /* long */ +#define HAVE_TYPEOF_ST_BLOCKS 5 /* long */ + +#define HAVE_TYPEOF_ST64_DEV 6 /* unsigned long */ +#define HAVE_TYPEOF_ST64_INO 8 /* unsigned long long */ +#define HAVE_TYPEOF_ST64_NLINK 6 /* unsigned long */ +#define HAVE_TYPEOF_ST64_SIZE 7 /* long long */ +#define HAVE_TYPEOF_ST64_BLKSIZE 5 /* long */ +#define HAVE_TYPEOF_ST64_BLOCKS 7 /* long long */ + +/* #undef HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC */ + +#define HAVE_TYPEOF_RLIM_MAX 6 /* unsigned long */ + +/* Define if you have the /proc filesystem */ +#define HAVE_PROC_DIR 1 + +/* Define if you have the /proc/$$/fd directories */ +#define HAVE_PROC_DIR_FD 1 + +#define WITH_HELP 1 +#define WITH_STDIO 1 +#define WITH_FDNUM 1 +#define WITH_FILE 1 +#define WITH_CREAT 1 +#define WITH_GOPEN 1 +#define WITH_TERMIOS 1 +#define WITH_PIPE 1 +#define WITH_UNIX 1 +/* #undef WITH_ABSTRACT_UNIXSOCKET */ +#define WITH_IP4 1 +#define WITH_IP6 1 +#define WITH_RAWIP 1 +#define WITH_TCP 1 +#define WITH_UDP 1 +#define WITH_LISTEN 1 +#define WITH_SOCKS4 1 +#define WITH_SOCKS4A 1 +#define WITH_PROXY 1 +#define WITH_EXEC 1 +#define WITH_SYSTEM 1 +#define WITH_READLINE 1 +/* #undef WITH_TUN */ +#define WITH_PTY 1 +#define WITH_EXT2 1 +#define WITH_OPENSSL 1 +/* #undef WITH_FIPS */ +/* #undef OPENSSL_FIPS */ +#define WITH_LIBWRAP 1 +#define HAVE_TCPD_H 1 +#define HAVE_LIBWRAP 1 + +#define WITH_SYCLS 1 +#define WITH_FILAN 1 +#define WITH_RETRY 1 + +#define WITH_MSGLEVEL 0 + +#endif /* !defined(__config_h_included) */ diff --git a/Config/config.Tru64-5-1B.h b/Config/config.Tru64-5-1B.h new file mode 100644 index 0000000..9d0a516 --- /dev/null +++ b/Config/config.Tru64-5-1B.h @@ -0,0 +1,450 @@ +/* config.h. Generated by configure. */ +/* $Id: config.Tru64-5-1B.h,v 1.5 2006/07/13 21:35:43 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __config_h_included +#define __config_h_included 1 + +/* Define to empty if the keyword does not work. */ +/* #undef const */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define if your struct stat has st_blksize. */ +#define HAVE_ST_BLKSIZE 1 + +/* Define if your struct stat has st_blocks. */ +#define HAVE_ST_BLOCKS 1 + +/* Define if your struct stat has st_rdev. */ +#define HAVE_ST_RDEV 1 + +/* Define if you have the strftime function. */ +#define HAVE_STRFTIME 1 + +/* Define if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to `int' if doesn't define. */ +/* #undef mode_t */ + +/* Define to `long' if doesn't define. */ +/* #undef off_t */ + +/* Define to `int' if doesn't define. */ +/* #undef pid_t */ + +/* Define as the return type of signal handlers (int or void). */ +#define RETSIGTYPE void + +/* Define to `unsigned' if doesn't define. */ +/* #undef size_t */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ + +/* Define if you have the putenv function. */ +#define HAVE_PUTENV 1 + +/* Define if you have the select function. */ +#define HAVE_SELECT 1 + +/* Define if you have the poll function. */ +#define HAVE_POLL 1 + +/* Define if you have the socket function. */ +#define HAVE_SOCKET 1 + +/* Define if you have the strdup function. */ +#define HAVE_STRDUP 1 + +/* Define if you have the strerror function. */ +#define HAVE_STRERROR 1 + +/* Define if you have the strstr function. */ +#define HAVE_STRSTR 1 + +/* Define if you have the strtod function. */ +#define HAVE_STRTOD 1 + +/* Define if you have the strtol function. */ +#define HAVE_STRTOL 1 + +/* Define if you have the strtoul function. */ +#define HAVE_STRTOUL 1 + +/* Define if you have the uname function. */ +#define HAVE_UNAME 1 + +/* Define if you have the getpgid function. */ +#define HAVE_GETPGID 1 + +/* Define if you have the getsid function. */ +#define HAVE_GETSID 1 + +/* Define if you have the nanosleep function. */ +#define HAVE_NANOSLEEP 1 + +/* Define if you have the getaddrinfo function. */ +#define HAVE_GETADDRINFO 1 + +/* Define if you have the getipnodebyname function. */ +#define HAVE_GETIPNODEBYNAME 1 + +/* Define if you have the setgroups function. */ +#define HAVE_SETGROUPS 1 + +/* Define if you have the inet_aton function. */ +#define HAVE_INET_ATON 1 + +/* Define if you have the memrchr function. */ +/* #undef HAVE_MEMRCHR */ + +/* Define if you have the sigaction function */ +#define HAVE_SIGACTION 1 + +/* Define if you have the stat64 function */ +/* #undef HAVE_STAT64 */ + +/* Define if you have the fstat64 function */ +/* #undef HAVE_FSTAT64 */ + +/* Define if you have the lstat64 function */ +/* #undef HAVE_LSTAT64 */ + +/* Define if you have the lseek64 function */ +/* #undef HAVE_LSEEK64 */ + +/* Define if you have the truncate64 function */ +/* #undef HAVE_TRUNCATE64 */ + +/* Define if you have the ftruncate64 function */ +/* #undef HAVE_FTRUNCATE64 */ + +/* Define if you have the strtoll function */ +/* #undef HAVE_STRTOLL */ + +/* Define if you have the hstrerror function */ +#define HAVE_HSTRERROR 1 + +/* Define if you have the hstrerror prototype */ +/* #undef HAVE_PROTOTYPE_HSTRERROR */ + +/* Define if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYSLOG_H 1 + +/* Define if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if you have the header file. */ +#define HAVE_PWD_H 1 + +/* Define if you have the header file. */ +#define HAVE_GRP_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_STDINT_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_POLL_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UN_H 1 + +/* Define if you have the header file. */ +#define HAVE_PTY_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_SYSTM_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IP_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IP6_H 1 + +/* Define if you have the header file. */ +#define HAVE_RESOLV_H 1 + +/* Define if you have the header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define if you have the header file. */ +#define HAVE_NET_IF_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UTSNAME_H 1 + +/* Define if you have the header file. (AIX) */ +#define HAVE_SYS_SELECT_H 1 + +/* Define if you have the header file. (AIX) */ +#define HAVE_SYS_FILE_H 1 + +/* Define if you have the header file. (NetBSD, OpenBSD: openpty()) */ +/* #undef HAVE_UTIL_H */ + +/* Define if you have the header file. (FreeBSD: openpty()) */ +/* #undef HAVE_LIBUTIL_H */ + +/* Define if you have the header file. (stream opts on SunOS)*/ +#define HAVE_SYS_STROPTS_H 1 + +/* Define if you have the header file. */ +#define HAVE_REGEX_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_LINUX_EXT2_FS_H */ + +/* Define if you have the header file. */ +#define HAVE_READLINE_READLINE_H 1 + +/* Define if you have the header file. */ +#define HAVE_READLINE_HISTORY_H 1 + +/* Define if you have the readline library. */ +#define HAVE_LIBREADLINE 1 + +/* Define if you have the m library (-lm). */ +/* #undef HAVE_LIBM */ + +/* Define if you have the floor function */ +/* #undef HAVE_FLOOR */ + +/* some platforms need _XOPEN_EXTENDED_SOURCE to get syslog headers (AIX4.1) */ +/* #undef _XOPEN_EXTENDED_SOURCE */ + +/* fdset may have component fds_bits or __fds_bits */ +#define HAVE_FDS_BITS 1 + +/* Define if your struct termios has component c_ispeed */ +#define HAVE_TERMIOS_ISPEED 1 + +/* the offset of c_ispeed in struct termios - usable in an speed_t array. + Applies only when HAVE_TERMIOS_ISPEED is set */ +#define ISPEED_OFFSET 9 + +/* the offset of c_ospeed in struct termios - see ISPEED_OFFSET */ +#ifdef ISPEED_OFFSET +# define OSPEED_OFFSET (ISPEED_OFFSET+1) +#else +/* # undef OSPEED_OFFSET */ +#endif + +/* Define if your termios.h likes _SVID3 defined */ +/* #undef _SVID3 */ + +/* Define if you have struct timespec (e.g. for nanosleep) */ +#define HAVE_STRUCT_TIMESPEC 1 + +/* Define if you have struct linger */ +#define HAVE_STRUCT_LINGER 1 + +/* Define if your struct sockaddr has sa_len */ +/* #undef HAVE_STRUCT_SOCKADDR_SALEN */ + +/* there are several implementations of sockaddr_in6 */ +#define HAVE_IP6_SOCKADDR 0 + +/* Define if you have struct iovec */ +#define HAVE_STRUCT_IOVEC 1 + +/* define if your struct msghdr has msg_control */ +/* #undef HAVE_STRUCT_MSGHDR_MSGCONTROL */ + +/* define if your struct msghdr has msg_controllen */ +/* #undef HAVE_STRUCT_MSGHDR_MSGCONTROLLEN */ + +/* define if your struct msghdr has msg_flag */ +/* #undef HAVE_STRUCT_MSGHDR_MSGFLAGS */ + +/* define if your struct ip has ip_hl; otherwise assume ip_vhl */ +/* #undef HAVE_STRUCT_IP_IP_HL */ + +/* Define if you have the setenv function */ +#define HAVE_SETENV 1 + +/* Define if you have the flock function */ +#define HAVE_FLOCK 1 + +/* Define if you have the openpty function */ +#define HAVE_OPENPTY 1 + +/* Define if you have the grantpt function */ +#define HAVE_GRANTPT 1 + +/* Define if you have the unlockpt function */ +#define HAVE_UNLOCKPT 1 + +/* Define if you have the ptsname function */ +#define HAVE_PTSNAME 1 + +/* Define if you have the /dev/ptmx pseudo terminal multiplexer */ +#define HAVE_DEV_PTMX 1 + +/* Define if you have the /dev/ptc pseudo terminal multiplexer */ +/* #undef HAVE_DEV_PTC */ + +/* Define if you have the long long type */ +#define HAVE_TYPE_LONGLONG 1 + +/* is socklen_t already typedef'd? */ +/* #undef HAVE_TYPE_SOCKLEN */ + +/* Define if you have the struct stat64 type */ +/* #undef HAVE_TYPE_STAT64 */ + +/* Define if you have the struct off64_t type */ +/* #undef HAVE_TYPE_OFF64 */ + +/* is sighandler_t already typedef'd? */ +/* #undef HAVE_TYPE_SIGHANDLER */ + +/* is uint8_t already defined? */ +#define HAVE_TYPE_UINT8 1 + +/* is uint16_t already defined? */ +#define HAVE_TYPE_UINT16 1 + +/* is uint32_t already defined? */ +#define HAVE_TYPE_UINT32 1 + +/* Define if you have the printf "Z" modifier */ +/* #undef HAVE_FORMAT_Z */ + +/* Define the shift offset of the CRDLY mask */ +#define CRDLY_SHIFT 12 + +/* Define the shift offset of the TABDLY mask */ +#define TABDLY_SHIFT 10 + +/* Define the shift offset of the CSIZE mask */ +#define CSIZE_SHIFT 8 + +/* Define if you have tcpwrappers (libwrap, tcpd) and it declares hosts_allow_table */ +/* #undef HAVE_HOSTS_ALLOW_TABLE */ +#if defined(HAVE_HOSTS_ALLOW_TABLE) && HAVE_HOSTS_ALLOW_TABLE + #define HAVE_HOSTS_DENY_TABLE 1 +#else +/* #undef HAVE_HOSTS_DENY_TABLE */ +#endif + +/* 1..short, 3..int, 5..long; 2,4,6..unsigned */ +#define HAVE_BASIC_SIZE_T 6 /* unsigned long */ +#define HAVE_BASIC_MODE_T 4 /* unsigned int */ +#define HAVE_BASIC_PID_T 3 /* int */ +#define HAVE_BASIC_UID_T 4 /* unsigned int */ +#define HAVE_BASIC_GID_T 4 /* unsigned int */ +#define HAVE_BASIC_TIME_T 3 /* int */ +#define HAVE_BASIC_OFF64_T 0 /* unknown, taking default */ + +#define HAVE_BASIC_SOCKLEN_T 0 /* unknown, taking default */ + +#define HAVE_TYPEOF_ST_DEV 3 /* int */ +#define HAVE_TYPEOF_ST_INO 4 /* unsigned int */ +#define HAVE_TYPEOF_ST_NLINK 2 /* unsigned short */ +#define HAVE_TYPEOF_ST_SIZE 5 /* long */ +#define HAVE_TYPEOF_ST_BLKSIZE 5 /* long */ +#define HAVE_TYPEOF_ST_BLOCKS 5 /* long */ + +/* #undef HAVE_TYPEOF_ST64_DEV */ +/* #undef HAVE_TYPEOF_ST64_INO */ +/* #undef HAVE_TYPEOF_ST64_NLINK */ +/* #undef HAVE_TYPEOF_ST64_SIZE */ +/* #undef HAVE_TYPEOF_ST64_BLKSIZE */ +/* #undef HAVE_TYPEOF_ST64_BLOCKS */ + +/* #undef HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC */ + +#define HAVE_TYPEOF_RLIM_MAX 6 /* unsigned long */ + +/* Define if you have the /proc filesystem */ +#define HAVE_PROC_DIR 1 + +/* Define if you have the /proc/$$/fd directories */ +/* #undef HAVE_PROC_DIR_FD */ + +#define WITH_HELP 1 +#define WITH_STDIO 1 +#define WITH_FDNUM 1 +#define WITH_FILE 1 +#define WITH_CREAT 1 +#define WITH_GOPEN 1 +#define WITH_TERMIOS 1 +#define WITH_PIPE 1 +#define WITH_UNIX 1 +#define WITH_IP4 1 +#define WITH_IP6 1 +#define WITH_RAWIP 1 +#define WITH_TCP 1 +#define WITH_UDP 1 +#define WITH_LISTEN 1 +#define WITH_SOCKS4 1 +#define WITH_SOCKS4A 1 +#define WITH_PROXY 1 +#define WITH_EXEC 1 +#define WITH_SYSTEM 1 +#define WITH_READLINE 1 +#define WITH_PTY 1 +#define WITH_EXT2 1 +#define WITH_OPENSSL 1 +/* #undef WITH_FIPS */ +/* #undef OPENSSL_FIPS */ +/* #undef WITH_LIBWRAP */ +/* #undef HAVE_TCPD_H */ +/* #undef HAVE_LIBWRAP */ + +#define WITH_SYCLS 1 +#define WITH_FILAN 1 +#define WITH_RETRY 1 + +#define WITH_MSGLEVEL 0 + +#endif /* !defined(__config_h_included) */ diff --git a/DEVELOPMENT b/DEVELOPMENT new file mode 100644 index 0000000..3564ed8 --- /dev/null +++ b/DEVELOPMENT @@ -0,0 +1,205 @@ + +This file should help you to add new address types and address options to +socat. + +NOTE: +socat will in future releases be split into a library "libxio" containing all +the address stuff, useful also for many other purposes, and the socat main() +and data shuffler. If you intend to perform major changes to the xio part and +to publish them, please contact me before! + + +ADDING A NEW ADDRESS TYPE: + +* Create new files xio-newaddr.c and xio-newaddr.h + +* Create a new record of struct addrdesc in xio-newaddr.c, with declaration in xio-newaddr.h. + +* Make a new entry to addressnames[] in xioopen.c with the addresses main name +and maybe with alias names. Keep this array ASCII sorted, without uppercase +chars. + +* config.h.in: #undef WITH_NEWADDR + +* configure.in: Copy the disable part of, e.g., WITH_SOCKS4 and adapt it to +NEWADDR + +* In socat.c, add to socat_version + +* Write a function xioopen_newaddr() in xio-newaddr.c, declaration in +xio-newaddr.h +Do not forget the following option processing calls: +All groups: _xio_openlate() +Group FD: applyopts_cloexec() +Group NAMED: applyopts_file() for phases PREOPEN, OPEN, and FD + +* Describe a tested example in file EXAMPLES, and maybe in the socat manpage +source. + +* Try to define a test for this address type in test.sh + +* Update file CHANGES + + +ADDING A NEW ADDRESS OPTION: + +xioopen.c: + +* If this option depends on a #define that is probably not available on all +platforms, make all new code for this option dependent on the existence of this +C header define: +#ifdef PREFIX_NEWOPTION +... +#endif + +* Add an OPT_NEWOPTION to enum e_optcode in xioopts.h, preferably keeping +alphabetic order + +* Add a struct optdesc opt_newoption record in xio-newaddr.c and its +declaration in xio-newaddr.h. The complete structure definition must be in one +line without breaks for automatic docu extraction. +Build the record from the following components: +. A canonical default name (e.g. "newoption") +. A short, preferable name (e.g. "newopt") or NULL +. OPT_NEWOPTION (from enum e_optcode, see above) +. A group membership that restricts appliance of the new option to matching +address types (e.g., one of GROUP_ANY, GROUP_IP_TCP, GROUP_EXEC) +. A phase specification that positions this option within address processing. +Note that the function code can override this value. +. A representation type for option arguments (e.g., TYPE_INT, TYPE_STRING etc.; +use TYPE_BOOL if this option just triggers an action) +. A function or action definition for applying this option. If it does not use +one of the standard functions (open(), ioctl(), setsockopt()...), then use +OFUNC_SPEC (specific). + +* For the canonical name and all its aliases and abbreviations, add entries to +the array optionnames in xioopts.c. KEEP STRICT ALPHABETIC (ASCII) ORDER! +The entries must be embedded in an IF_... macro of their group for conditional +compiling. + +* For options using some predefined action (see OFUNC above), this might be +enough - test the option and document it in xio.help! +For OFUNC_SPEC, it might suffice to add another "case" to the OFUNC_SPEC branch +in applyopts() in xioopts.c. If you need more special handling, you should try +to understand the address specific functions and add your code there. + +* If you use system or low level C library calls or library calls that might +hang or induce problems, please invoke them with capitalized name; if no such +name is defined, add an appropriate debug function to sycls.c, and a header +entry and a wrapper "define" to sycls.h + +* Update file CHANGES + + +INFO ABOUT ADDRESS PHASES: + +Each option entry has a field specifying a default phase for its application. +Of course, the code that analyses and applies an address may override this +default phase. + +Depending on the type of address there are several major phase sequences: + + +OPEN addresses: + +PH_INIT retrieving info from original state +PH_EARLY before any other processing +PH_PREOPEN before file creation/opening (not UNIX sockets) +PH_OPEN during file creation/opening (not UNIX sockets) +PH_PASTOPEN past file creation/opening (not UNIX sockets) +PH_FD soon after FD creation or identification +PH_LATE FD is ready, before start of data loop +PH_LATE2 FD is ready, dropping privileges + + +SOCKET addresses: + +PH_INIT retrieving info from original state +PH_EARLY before any other processing +PH_PRESOCKET before socket call +PH_SOCKET for socket call +PH_PASTSOCKET after socket call +PH_FD soon after FD creation or identification +PH_PREBIND before socket bind() +PH_BIND during socket bind() +PH_PASTBIND past socket bind() +PH_PRECONNECT before connect() +PH_CONNECT during connect() +PH_PASTCONNECT after connect() +PH_CONNECTED phase common with listen +PH_LATE FD is ready, before start of data loop +PH_LATE2 FD is ready, dropping privileges + + +SOCKET with LISTEN and FORK: + +PH_INIT retrieving info from original state +PH_EARLY before any other processing +PH_PRESOCKET before socket call +PH_SOCKET for socket call +PH_PASTSOCKET after socket call +PH_PREBIND before socket bind() +PH_BIND during socket bind() +PH_PASTBIND past socket bind() +PH_PRELISTEN before listen() +PH_LISTEN during listen() +PH_PASTLISTEN after listen() +PH_PREACCEPT before accept() +PH_ACCEPT during accept() +PH_PASTACCEPT after accept() +PH_FD soon after FD creation or identification +PH_CONNECTED phase common with connect +PH_PREFORK before forking +PH_FORK during fork() +PH_PASTFORK after fork() +PH_LATE FD is ready, before start of data loop +PH_LATE2 FD is ready, dropping privileges + + +FD addresses: + +PH_INIT retrieving info from original state +PH_EARLY before any other processing +PH_FD soon after FD identification +PH_LATE FD is ready, before start of data loop +PH_LATE2 FD is ready, dropping privileges + + +EXEC addresses: + +PH_INIT retrieving info from original state +PH_EARLY before any other processing +PH_PREBIGEN before socketpair() pipe() openpty() +PH_BIGEN during socketpair() pipe() openpty() +PH_PASTBIGEN past socketpair() pipe() openpty() +PH_PASTSOCKET for socketpair() +PH_FD soon after FD creation or identification +PH_PREFORK before forking +PH_FORK during fork() +PH_PASTFORK after fork() +PH_LATE FD is ready, before start of data loop +PH_LATE2 FD is ready, dropping privileges +PH_PREEXEC before exec() or system() +PH_EXEC during exec() or system() + + +There are lots of semantic relations between group, phase, and func fields of +an option. + + +There exists something like an overall phase sequence: +PH_INIT # su-d.1 +PH_EARLY # chroot-early +PH_PREOPEN, PH_OPEN, PH_PASTOPEN # (chroot before/after?) +PH_PRESOCKET, PH_SOCKET, PH_PASTSOCKET # (su after (root for raw)?) +PH_PREBIGEN, PH_BIGEN, PH_PASTBIGEN # (chroot before/after (/dev..)?) +PH_FD +PH_PREBIND, PH_BIND, PH_PASTBIND # (su after(before?)) +PH_PRELISTEN, PH_LISTEN, PH_PASTLISTEN +PH_PRECONNECT, PH_CONNECT, PH_PASTCONNECT # (chroot before/after (AF_UNIX)?) +PH_PREACCEPT, PH_ACCEPT, PH_PASTACCEPT +PH_CONNECTED +PH_PREFORK, PH_FORK, PH_PASTFORK # (all before/after?) +PH_LATE # chroot +PH_LATE2 # su, su-d.2 +PH_PREEXEC, PH_EXEC # (all before) diff --git a/EXAMPLES b/EXAMPLES new file mode 100644 index 0000000..57286ea --- /dev/null +++ b/EXAMPLES @@ -0,0 +1,326 @@ + +// Examples for using socat (and filan) + + +//"$" means normal user, "#" requires privileges, "//" starts a comment + +/////////////////////////////////////////////////////////////////////////////// +// similar to netcat + +// connect to 10.1.1.1 on port 80 and relay to and from stdio +$ socat - TCP:10.1.1.1:80 # similar to "netcat 10.1.1.1 80" + +// listen on port 25, wait for an incoming connection, use CR+NL on this +// connection, relay data to and from stdio; +// then emulate a mailserver by hand :-) +# socat - TCP-LISTEN:25,crlf + +// listen on port 25, wait for an incoming connection, use CR+NL on this +// connection, relay data to and from stdio, but have line editing and history; +// then emulate a mailserver by hand :-) +# socat readline TCP-LISTEN:25,crlf + +// provide a transient history enabled front end to stupid line based +// interactive programs +$ socat readline exec:"nslookup",pty,ctty,setsid,echo=0 +// same works for ftp (but password is not hidden) + +// you may also use a file based history list +$ socat readline,history=.nslookup_hist exec:"nslookup",pty,ctty,setsid,echo=0 +// using ~ as abbreviation for $HOME does not work! + +// poor mans 'telnetd' replacement +# socat tcp-l:2023,reuseaddr,fork exec:/bin/login,pty,setsid,setpgid,stderr,ctty +// and here an appropriate client: +$ socat -,raw,echo=0 tcp:172.16.181.130:2023 +// use ssl with client and server certificate for improved security; +// replace /bin/login by /bin/bash when using SSL client authentication, can be +// run without root then + +/////////////////////////////////////////////////////////////////////////////// +// a very primitive HTTP/1.0 echo server (problems: sends reply headers before +// request; hangs if client does not shutdown - HTTP keep-alive) +// wait for a connection on port 8000; do not wait for request, but immediately +// start a shell that sends reply headers and an empty line; then echo all +// incoming data back to client +$ socat TCP-LISTEN:8000,crlf SYSTEM:"echo HTTP/1.0 200; echo Content-Type: text/plain; echo; cat" + +/////////////////////////////////////////////////////////////////////////////// +// for communicating with an attached modem, I had reasonable results with +// following command line. Required privileges depend on device mode. +// after leaving socat, type "sane". +// replace /dev/ttyS0 by the correct serial line or with /dev/modem +$ socat readline /dev/ttyS0,raw,echo=0,crlf +// or +$ socat readline /dev/ttyS0,raw,echo=0,crlf,nonblock +// then enter "at$" + +/////////////////////////////////////////////////////////////////////////////// +// relay TCP port 80 from everywhere (internet, intranet, dmz) through your +// firewall to your DMZ webserver (like plug-gw) +// listen on port 80; whenever a connection is made, fork a new process (parent +// process keeps accepting connections), su to nobody, and connect to +// www.dmz.mydomain.org on port 80. +// attention: this is a substitute for a reverse proxy without providing +// application level security. +# socat TCP-LISTEN:80,reuseaddr,fork,su=nobody TCP:www.dmz.mydomain.org:80 +// Note: parent process keeps running as root, su after forking + +/////////////////////////////////////////////////////////////////////////////// +// relay mail from your DMZ server through your firewall. +// accept connections only on dmz interface and allow connections only from +// smtp.dmz.mydomain.org. +// the advantages over plug-gw and other relays are: +// * you can bind to an IP address (even an alias), therefore enhance security +// * in your OS you can create several IP aliases and bind another socat daemon +// to each, making several application servers addressable +// * lots of options, like switching user, chroot, IP performance tuning +// * no need for inetd +# socat -lm -d -d TCP-LISTEN:25,bind=fw.dmz.mydomain.org,fork,su=nobody,range=smtp.dmz.mydomain.org/32 TCP:smtp.intra.mydomain.org:25 + +/////////////////////////////////////////////////////////////////////////////// +// convert line terminator in ascii streams, stdin to stdout +// use unidirectional mode, convert nl to crnl +$ socat -u - -,crlf +// or cr to nl +$ socat -u -,cr - + +// save piped data similar to 'tee': +// copies stdin to stdout, but writes everything to the file too +$ socat -,echo=0 open:/tmp/myfile,create,trunc,ignoreeof!!/tmp/myfile + +/////////////////////////////////////////////////////////////////////////////// +// intrusion testing + +// found an XWindow Server behind IP filters with FTP data hole? (you are +// lucky!) +// prepare your host: +# rm -f /tmp/.X11-unix/X1 +// relay a pseudo display :1 on your machine to victim:0 +# socat UNIX-LISTEN:/tmp/.X11-unix/X1,fork TCP:host.victim.org:6000,sp=20 & +// and try to take a screendump (must be very lucky - when server has not even +// host based authentication!) +# xwd -root -display :1 -silent >victim.xwd + +// you sit behind a socks firewall that has IP filters but lazily allows socks +// connections to loopback and has only host based X11 security. +// like above, but from your inside client: +# socat UNIX-LISTEN:/tmp/.X11-unix/X1,fork SOCKS4:firewall:loopback:6000 +// or for the HTTP proxy: +# socat UNIX-LISTEN:/tmp/.X11-unix/X1,fork PROXY:firewall:loopback:6000 + +/////////////////////////////////////////////////////////////////////////////// +// forms of stdin with stdout, all equivalent +$ socat echo - +$ socat echo STDIO +$ socat echo STDIN!!STDOUT +$ socat echo STDIO!!STDIO +$ socat echo -!!- +$ socat echo FD:0!!FD:1 +$ socat echo 0!!1 +$ socat echo /dev/stdin!!/dev/stdout // if your OS provides these + +/////////////////////////////////////////////////////////////////////////////// +// some echo address examples +$ socat - PIPE +$ socat - PIPE:/tmp/pipi // other version of echo +$ socat - PIPE:/tmp/pipi,nonblock!!/tmp/pipi // other version of echo +$ socat - EXEC:/bin/cat // another echo +$ socat - SYSTEM:/bin/cat // another echo +$ socat - TCP:loopback:7 // if inetd echo/TCP service activated +$ socat - UDP:loopback:7 // if inetd echo/UDP service activated +$ socat - /tmp/hugo,trunc,ignoreeof!!/tmp/hugo // with delay +$ socat - UDP:loopback:2000,bind=:2000 // self "connection" +$ socat - TCP:loopback:2000,bind=:2000 // Linux bug? +# socat - IP:loopback:222 // raw protocol, self "connected" (attention, +// Linux might drop packets with less than 8 bytes payload) + +/////////////////////////////////////////////////////////////////////////////// +// unidirectional data transfer +$ socat -u - - +// like "tail -f", but start with showing all file contents +$ socat -u FILE:/var/log/syslog.debug,ignoreeof - +// like "tail -f", but do not show existing file contents +$ socat -u FILE:/var/log/syslog.debug,ignoreeof,seek-end - +// write to new file, create with given permission and group (must be member) - race condition with group!!! +$ socat -u - CREATE:/tmp/outfile1,group=floppy,perm=0640 +// +// for an existing file /tmp/outfile1 +# socat -u - FILE:/tmp/outfile1,group=floppy,perm=0700,user=4321 + + +/////////////////////////////////////////////////////////////////////////////// +// file handling +$ socat - FILE:/tmp/outfile1,ignoreeof!!FILE:/tmp/outfile1,append // prints outfile1, then echoes input and protocols into file (appends to old data) + +/////////////////////////////////////////////////////////////////////////////// +// unix socket handling + +// create a listening unix socket +$ rm -f /tmp/mysocket; socat UNIX-LISTEN:/tmp/mysocket - +// from another terminal, connect to this socket +$ socat UNIX:/tmp/mysocket - +// then transfer data bidirectionally + + +/////////////////////////////////////////////////////////////////////////////// +// transport examples + +// socks relay (externally socksify applications); +// your ssh client and OS are not socksified, but you want to pass a socks +// server with ssh: +$ socat TCP-LISTEN:10022,fork SOCKS4:socks.mydomain.org:ssh-serv:22 +$ ssh -p 10022 loopback +// or better define a ProxyCommand in ~/.ssh/config: +ProxyCommand socat - SOCKS:socks.mydomain.org:%h:%p +// and with proxy: +ProxyCommand socat - PROXY:proxy.mydomain.org:%h:%p,proxyport=8000 + +/////////////////////////////////////////////////////////////////////////////// +// application examples + +// run sendmail daemon with your favorite network options +# socat TCP-LISTEN:25,fork,ip-ttl=4,ip-tos=7,tcp-maxseg=576 EXEC:"/usr/sbin/sendmail -bs",nofork + +// local mail delivery over UNIX socket - no SUID program required +# socat UNIX-LISTEN:/tmp/postoffice,fork,perm-early=0666 EXEC:"/usr/sbin/sendmail -bs" +$ socat - /tmp/postoffice + +/////////////////////////////////////////////////////////////////////////////// +// uses of filan +// see what your operating system opens for you +$ filan +// or if that was too detailled +$ filan -s +// see what file descriptors are passed via exec function +$ socat - EXEC:filan,nofork +$ socat - EXEC:filan +$ socat - EXEC:filan,pipes,stderr +$ socat - EXEC:filan,pipes +$ socat - EXEC:filan,pty +// see what's done by your shell and with option "pipes" +$ socat - SYSTEM:filan,pipes +// see if gdb gives you an equivalent environment or opens some files for your program +$ gdb ./filan +(gdb) r +(gdb) r -s + +/////////////////////////////////////////////////////////////////////////////// +// want to use chat from the ppp package? +// note: some OS's do not need "-e" for echo to print control characters +// note: chat might send bytes one by one +// with AIX, a similar program is available under the name "pppdial" +$ socat -d -d system:'/usr/sbin/chat "220 " "HELO loopback" "250 " "MAIL FROM: " "250 " "RCPT TO: root" "250 " "DATA" "354 " "test1'$(echo -e "\r.")'" "250 " "QUIT"',pty,echo=0,cr tcp:localhost:25,crlf,nodelay + +////////////////////////////////////////////////////////////////////////////// +// IP6 + +# socat readline TCP6:::1:21 # if your inetd/ftp is listening on ip6 + + +/////////////////////////////////////////////////////////////////////////////// +// application server solutions +// run a program (here: /bin/sh) chrooted, unprivileged; +// parent process stays in real / running as root +# socat -d -d - EXEC:/bin/sh,chroot=/home/sandbox,su=sandbox,pty + +// make a program available on the network chrooted, unprivileged; +// parent process stays in / running as root +// script path is already chrooted +# ./socat -lm -d -d TCP-LISTEN:5555,fork EXEC:/bin/myscript,chroot=/home/sandbox,su=sandbox,pty,stderr +// to avoid terminal problems, you might - instead of telnet - connect using +$ socat -,icanon=0,echo=0 tcp:target:5555; reset + + +// access local display from ssh server, when ssh port forwarding is disabled +// socat must be installed on ssh server host +// might have to use xauth... +// this example is one-shot, because ',' cannot be passed to remote socat +xterm1$ socat -d -d exec:"ssh target ~/bin/socat -d -d unix-l:/tmp/.X11-unix/X1 -" unix:/tmp/.X11-unix/X0 +xterm2$ ssh target +target$ DISPLAY=:1 myxapplication + +// touch with perms: +// no race condition for perms (applied with creat() call) +$ socat -u /dev/null creat:/tmp/tempfile,perm=0600 + +// touch with owner and perms: +// race condition before changing owner, but who cares - only root may access +# socat -u /dev/null creat:/tmp/tempfile,user=user1,perm=0600 + +// invoke an interactive ssh with exec +// first example passes control chars (^C etc.) to remote server as usual +socat -,echo=0,raw exec:'ssh server',pty,setsid,ctty +// second example interprets control chars on local command line +socat -,echo=0,icanon=0 exec:'ssh server',pty,setsid,ctty +// afterwards, type "reset"! + +// convince ssh to provide an "interactive" shell to your script +// 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 +(sleep 10; echo "ls"; sleep 1) |socat - exec:'ssh server',pty,setsid +// 3) from script +(echo PASSWORD; echo ls; sleep 1) |./socat - exec:'ssh server',pty,setsid,ctty + + +// download with proxy CONNECT +// use echo -e if required for \n +$ (echo -e "CONNECT 128.129.130.131:80 HTTP/1.0\n"; sleep 5; echo -e "GET +/download/file HTTP/1.0\n"; sleep 10) |socat -d -d -t 3600 - tcp:proxy:8080,crlf + +// retrieve a file from an sshd site with sourceforge style entry menu; +// fill in your personal values; cat lets you enter your password (will be +// visible on screen) +$ (sleep 10; read pass; echo $pass; sleep 10; echo M; sleep 5; echo cat FILENAME; sleep 10) |./socat -d -d -ly - EXEC:'ssh -c 3des -l USER cf.sourceforge.net',pty,setsid,ctty |tee FILENAME + +// multicast community on local network: start the following command on all +// participating hosts; like a conference call: +# socat -d -d -d -d - udp-datagram:224.0.0.2:6666,bind=:6666,ip-add-membership=224.0.0.2:eth0,bindtodevice=eth0 +// or +$ socat -d -d -d -d - udp-datagram:224.0.0.2:6666,bind=:6666,ip-add-membership=224.0.0.2:eth0 +// possible reasons for failure: +// iptables or other filters (open your filters as required) +// packets leave via wrong interface (set route: ...) +// socket bound to specific address + +=============================================================================== + +// not tested, just ideas, or have problems + + +// traverse firewall for making internal telnet server accessible for outside +// telnet client, when only outbound traffic (syn-filter) is allowed: +// on external client run "double server". this process waits for a +// connection from localhost on port 10023, and, when it is established, waits +// for a connection from anywhere to port 20023: +ext$ socat -d TCP-LISTEN:10023,range=localhost TCP-LISTEN:20023 +// on internal server run double client: +int$ socat -d TCP:localhost:23 TCP:extclient:10023 +// or, with socks firewall: +int$ socat -d TCP:localhost:23 SOCKS:socksserver:extclient:10023 +// login with: +ext$ telnet localhost 20023 + +// you can make a double server capable of handling multiple instances: +ext$ socat -d TCP-LISTEN:10023,range=localhost,fork TCP-LISTEN:20023,reuseaddr + +// access remote display via ssh, when ssh port forwarding is disabled +$ socat -d -d EXEC:"ssh target socat - UNIX:/tmp/.X11-unix/X0" TCP-LISTEN:6030 +$ xclock -display localhost:30 + +// relay multiple webserver addresses through your firewall into your DMZ: +// make IP aliases on your firewall, and then: +# socat -d -d TCP-L:80,bind=fw-addr1,fork TCP:dmz-www1:80 +# socat -d -d TCP-L:80,bind=fw-addr2,fork TCP:dmz-www2:80 +// and for improved security: +# socat -d -d TCP-L:80,bind=fw-addr3,su=nobody,fork TCP:dmz-www3:80 + +// pass an arbitrary IP protocol through your firewall (answers won't work) +# socat -d -d IP:0.0.0.0:150,bind=fwnonsec IP:sec-host:150,bind=fwsec + +// pass an unsupported IP protocol through your firewall, point to point +// end points see firewall interfaces as IP peers! +# socat -d -d IP:nonsec-host:150,bind=fwnonsec IP:sec-host:150,bind=fwsec +// note that, for IPsec, you might face problems that are known with NAT diff --git a/FAQ b/FAQ new file mode 100644 index 0000000..66f2009 --- /dev/null +++ b/FAQ @@ -0,0 +1,85 @@ + +Q: What is the clue of socat? + +A: socat probably doesn't have any clue. It is more an attempt to smoothly +integrate similar I/O features that are usually handled differently under +UNIX. + + +Q: What does the prefix XIO mean? + +A: XIO means "extended input/output". It is a library/API that provides a +common way for handling files, sockets and other forms of I/O. Its advantage is +that the application may reduce its I/O to open / read+write / close calls, +while the user controls all I/O details (and even basic process properties) by +packing options into the filename string. This is the basic part of socat. + + +Q: Is there a Windows port of socat available? + +A: Try with Cygwin from http://www.cygwin.com/, or upgrade to Linux. + + +Q: I succeeded to configure and make socat, but ./test.sh says something +like: +./test.sh: No such file or directory + +A: You need a bash shell, and its location must be correctly specified in the +first line of test.sh, e.g. /usr/local/bin/bash instead of /bin/bash. + + +Q: configure disables readline / openssl / libwrap support because it does not +find an include file / the library. How can I tell configure where these files +are? + +A: For include locations, use the environment variable CPPFLAGS, for library +locations use LIBS, e.g.: + export CPPFLAGS="-I/home/user/ssl/include" + export LIBS="-L/home/user/ssl/lib" +On some systems (SunOS), you might also need to set LD_LIBRARY_PATH: + export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/home/user/ssl/lib" +Then try again: + make distclean; ./configure; make + + +Q: I succeeded to make socat, but the test.sh script fails for many tests. +Is my socat build corrupt? + +A: Probably your socat program is ok; the tests have been developed on Linux +2.4, and there they usually succeed. +But the following OS differences result in errors on non Linux systems: + * Linux allows to bind a socket to any address of range 127.0.0.0/8, not + only 127.0.0.1. Some tests are built on this feature, but they might fail on + other systems. + * Your OS might have no IP6 implementation + * MacOS X has some difficulties, e.g. distinguishing sockets and pipes. + * the OpenSSL tests require OpenSSL support by socat, must have openssl in + $PATH, and "openssl s_server ..." needs enough entropy to generate a key. + + +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 +"set +H" and add this line to your (bash) profile. + + +Q: On Solaris, socat was built successfully, but when started, it gets killed +with something like "ld.so.1: ./socat: fatal: libreadline.so.4: open failed: no +such file or directory" + +A: The configure script finds your libreadline, but the runtime loader +doesn't. Add the directory where the library resides to your LD_LIBRARY_PATH +variable, e.g.: + LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/sfw/lib/ + make distclean; ./configure; make + + +Q: On Solaris, socat was built successfully, but when started, an assertion +fails: "xioinitialize.c:25: failed assertion `3 << opt_crdly.arg3 == CRDLY' + +A: Probably, in a second attempt you set the correct LD_LIBARY_PATH for socat, +but it had not been set during the ./configure run, or you did not "make clean" +before running configure. Try it again: + make distclean; ./configure; make diff --git a/FILES b/FILES new file mode 100644 index 0000000..247e738 --- /dev/null +++ b/FILES @@ -0,0 +1,82 @@ + +The socat distribution contains the following files: + +* README: an introduction to socat + +* FILES: a navigator through the socat distribution (this file) + +* EXAMPLES: a collection of simple examples how to use socat. + +* COPYING: what you and others are allowed to do with socat. + +* PORTING: instructions and tips if you want to try socat on a new platform. + +* BUGREPORTS: instructions what to do with problems and contributions. + +* SECURITY: tips if you want to use socat in a security relevant environment. + +* DEVELOPMENT: infos for programmers + +* VERSION: the version of the socat distribution, for inclusion during +compilation + +* CHANGES: what happened since first public release + +* socat.1: man page of socat +* socat.html: html version of man page +* xio.help: reference manual of the address definitions (xioopen function) + +* daemon.sh: example shell script for running socat as TCP relay daemon +* ftp.sh: example shell based ftp client, using socat for transport +* mail.sh: example shell based smtp client, for execution by socat + +* gatherinfo.sh: shell script for gathering info about platform and socat +implementation + +* server.pem: a self signed test cerificate, for self test only + + +The source code system: + +* configure: the autoconf generated configurator script + +* Makefile.in: the Makefile source input to configure + +* config.h.in: the config.h source input to configure + +* Config/config..h: sample config.h for platform. +* Config/Makefile.: sample Makefile for platform. +Copy the appropriate files to ./config.h and ./Makefile if configure fails + +* socat.c: the main C source, including option parsing, general control, and +the data shuffler + +* xio-*.c, xio-*.h: the source of the different address type implementations +with all their modes and options + +* xio*.c, xio*.h: the source of the xio API and xio utilities + +* filan.c, filan.h: file descriptor analyzer function + +* dalan.c, dalan.h: data language, a most primitive subset of what should +become a language for describing/generating all kinds of binary data. + +* error.c, error.h: the logging subsystem + +* sycls.c, sycls.h: explicit system call and C library trace functions +* sslcls.c, sslcls.h: explicit openssl call trace functions + +* xioconfig.h: ensures some dependencies between configure WITH defines; to be +included immediately after config.h + +* sysutils.c, sysutils.h: some more general system (socket, IP) related +functions, e.g. converting socket addresses to human readable form + +* utils.c, utils.h: useful additions to C library; currently memdup, binary +search, and setenv. + +* mytypes.h: some types and macros I miss in C89 + +* test.sh: an incomplete attempt to automate tests of socat + +* compat.h: ensure some features that might be missing on some platforms diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..4d76144 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,177 @@ +# $Id: Makefile.in,v 1.114 2007/03/06 21:52:34 gerhard Exp $ +# Copyright Gerhard Rieger 2001-2007 +# Published under the GNU General Public License V.2, see file COPYING + +# note: @...@ forms are filled in by configure script + +SHELL = /bin/sh +AR = @AR@ +RANLIB = @RANLIB@ + +.SUFFIXES: .c .o + +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +BINDEST = @bindir@ + +MANDEST = @mandir@ + +srcdir = @srcdir@ +VPATH = @srcdir@ + +CC = @CC@ +CCOPTS = $(CCOPT) -Wall -Wno-parentheses + +SYSDEFS = @SYSDEFS@ +CPPFLAGS = -I. @CPPFLAGS@ +#0 INCLS = -I. @V_INCL@ +DEFS = @DEFS@ +LIBS = @LIBS@ +LDFLAGS = @LDFLAGS@ + +INSTALL = @INSTALL@ + +#OBJ = $(CSRC:.c=.o) $(GENSRC:.c=.o) @LIBOBJS@ + + +#0 CFLAGS = @CFLAGS@ $(CCOPTS) $(DEFS) $(INCLS) +CFLAGS = @CFLAGS@ $(CCOPTS) $(DEFS) $(CPPFLAGS) +CLIBS = $(LIBS) +#CLIBS = $(LIBS) -lm -lefence +XIOSRCS = xioinitialize.c xiohelp.c xioparam.c xiodiag.c xioopen.c xioopts.c \ + xiosignal.c xiosigchld.c xioread.c xiowrite.c \ + xiolayer.c xioshutdown.c xioclose.c xioexit.c \ + xio-process.c xio-fd.c xio-fdnum.c xio-stdio.c xio-pipe.c \ + xio-gopen.c xio-creat.c xio-file.c xio-named.c \ + xio-socket.c xio-listen.c xio-unix.c xio-ip.c xio-ip4.c xio-ip6.c xio-ipapp.c xio-tcp.c xio-socks.c xio-proxy.c xio-udp.c \ + xio-rawip.c \ + xio-progcall.c xio-exec.c xio-system.c xio-termios.c xio-readline.c \ + xio-pty.c xio-openssl.c \ + xio-ascii.c xiolockfile.c xio-tcpwrap.c xio-ext2.c xio-tun.c +XIOOBJS = $(XIOSRCS:.c=.o) +UTLSRCS = error.c dalan.c procan.c hostan.c fdname.c sysutils.c utils.c nestlex.c @FILAN@ @SYCLS@ @SSLCLS@ +UTLOBJS = $(UTLSRCS:.c=.o) +CFILES = $(XIOSRCS) $(UTLSRCS) socat.c procan_main.c filan_main.c +OFILES = $(CFILES:.c=.o) +PROGS = socat procan filan + +HFILES = sycls.h sslcls.h error.h dalan.h procan.h filan.h hostan.h sysincludes.h xio.h xioopen.h sysutils.h utils.h nestlex.h compat.h \ + xioconfig.h mytypes.h xioopts.h xiodiag.h xiohelp.h xiosysincludes.h \ + xiomodes.h xiolayer.h xio-process.h xio-fd.h xio-fdnum.h xio-stdio.h \ + xio-named.h xio-file.h xio-creat.h xio-gopen.h xio-pipe.h xio-socket.h \ + xio-listen.h xio-unix.h xio-rawip.h xio-ip.h xio-ip4.h xio-ip6.h \ + xio-ipapp.h xio-tcp.h xio-udp.h xio-socks.h xio-proxy.h xio-progcall.h xio-exec.h \ + xio-system.h xio-termios.h xio-readline.h \ + xio-pty.h xio-openssl.h \ + xio-ascii.h xiolockfile.h xio-tcpwrap.h xio-ext2.h xio-tun.h + + +DOCFILES = README README.FIPS CHANGES FILES EXAMPLES PORTING SECURITY DEVELOPMENT doc/socat.1 doc/socat.html doc/xio.help FAQ BUGREPORTS COPYING COPYING.OpenSSL doc/dest-unreach.css doc/socat-openssltunnel.html doc/socat-multicast.html doc/socat-tun.html +SHFILES = daemon.sh mail.sh ftp.sh readline.sh +TESTFILES = test.sh socks4echo.sh proxyecho.sh gatherinfo.sh readline-test.sh \ + proxy.sh socks4a-echo.sh testcert.conf +OSFILES = Config/Makefile.Linux-2-6-16 Config/config.Linux-2-6-16.h \ + Config/Makefile.AIX-5-1 Config/config.AIX-5-1.h \ + Config/Makefile.SunOS-5-8 Config/config.SunOS-5-8.h \ + Config/Makefile.HP-UX-B-11-11 Config/config.HP-UX-B-11-11.h \ + Config/Makefile.FreeBSD-6-1 Config/config.FreeBSD-6-1.h \ + Config/Makefile.NetBSD-2-0-2 Config/config.NetBSD-2-0-2.h \ + Config/Makefile.OpenBSD-3-8 Config/config.OpenBSD-3-8.h \ + Config/Makefile.Tru64-5-1B Config/config.Tru64-5-1B.h + + +all: progs + +progs: $(PROGS) + +depend: $(CFILES) $(HFILES) + makedepend $(SYSDEFS) $(CFILES) + +socat: socat.o libxio.a + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ socat.o libxio.a $(CLIBS) + +PROCAN_OBJS=procan_main.o procan.o hostan.o error.o sycls.o sysutils.o utils.o +procan: $(PROCAN_OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(PROCAN_OBJS) $(CLIBS) + +filan: filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o $(CLIBS) + +libxio.a: $(XIOOBJS) $(UTLOBJS) + $(AR) r $@ $(XIOOBJS) $(UTLOBJS) + $(RANLIB) $@ + +doc: doc/xio.help +# + +strip: progs + strip $(PROGS) + +install: progs doc/socat.1 + mkdir -p $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 socat $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 procan $(DESTDIR)$(BINDEST) + $(INSTALL) -m 755 filan $(DESTDIR)$(BINDEST) + mkdir -p $(DESTDIR)$(MANDEST)/man1 + $(INSTALL) -m 644 doc/socat.1 $(DESTDIR)$(MANDEST)/man1/ + +uninstall: + rm -f $(DESTDIR)$(BINDEST)/socat + rm -f $(DESTDIR)$(BINDEST)/procat + rm -f $(DESTDIR)$(BINDEST)/filan + rm -f $(DESTDIR)$(MANDEST)/man1/socat.1 + +# make a GNU-zipped tar ball of the source files +dist: socat.tar.gz socat.tar.bz2 + +socat.tar.gz: socat.tar + gzip -9 socat.tar.gz + +socat.tar.bz2: socat.tar + bzip2 -9 socat.tar.bz2 + +VERSION = `sed 's/"//g' VERSION` +TARDIR = socat-$(VERSION) +socat.tar: configure.in configure Makefile.in config.h.in install-sh VERSION $(CFILES) $(HFILES) $(DOCFILES) $(SHFILES) $(OSFILES) $(TESTFILES) socat.spec + if [ ! -d $(TARDIR) ]; then mkdir $(TARDIR); fi + tar cf - $+ |(cd $(TARDIR); tar xf -) + tar cvf socat.tar $(TARDIR) + rm -f $(TARDIR)/COPYING # write protected + rm -r $(TARDIR) + +clean: + rm -f *.o libxio.a socat procan filan \ + socat.tar socat.tar.Z socat.tar.gz socat.tar.bz2 \ + socat.out compile.log test.log + +# remove all files that are generated from the original socat distribution +# note that Makefile is also removed, so you have to start with ./configure +# again +distclean: clean + rm -f config.status config.cache config.log config.h Makefile + rm -rf autom4te.cache + +info: socat + uname -a >socat.out + ./socat -V >>socat.out + ./socat -hh >>socat.out + +# perform some tests on socat +test: progs + ./test.sh + +cert: + # prepare critical files with correct permissions to avoid race cond + >cert.key + >cert.pem + chmod 600 cert.key cert.pem + # generate a private key + openssl genrsa -out cert.key 1024 + # generate a self signed cert + openssl req -new -key cert.key -x509 -days 3653 -out cert.crt + # ...enter fields + # generate the pem file + cat cert.key cert.crt >cert.pem + #echo use cert.pem on requestors side, i.e. with option cert=cert.pem + #echo use cert.crt on checkers side, i.e. with option cafile=cert.crt diff --git a/PORTING b/PORTING new file mode 100644 index 0000000..549df69 --- /dev/null +++ b/PORTING @@ -0,0 +1,72 @@ + +DEVELOPMENT PLATFORMS + +Primary development platform for socat is currently SuSE Linux 8.2 with +a 2.4.20 kernel. New features are then ported to the non-Linux platforms on the +Sourceforge compile farm (per July 2003: SunOS 5.8 with gcc, and MacOS X 10.2), +and AIX 5.1 with gcc. But due to limited time resources and restricted +(non-root) access to these systems I cannot extensively test socat there. + + +PORTING STEPS + +If you want to port socat to another operating system you will typically go +through two phases: First, you might just try to compile and run the actual +socat distribution (passive phase). Then, you should see if your platform +has some nice features that are not yet used in socat, and add code for +supporting them (active phase). At last, I encourage you to send me your +changes so I can integrate them into the main socat distribution. + + +PASSIVE PHASE: + +* Generate Makefile and config.h: + . If you have gcc, then just invoke "./configure". + . If you use another C compiler, configure might not work properly; + You will have to adapt config.h and Makefile manually. + Change compiler options or defines to use all features of the operating + system (not only ANSI-C; e.g. HP-UX: -Ae!) + Some practical config..h examples have been included in the + Config directory of the source that might serve as starting point. + +* Try to "make" socat; correct the errors. If some constants are undefined, + please disable these parts option-dependent, not platform-dependent (use + #ifdef TCP_OPTION instead of #if MY_OS) + +* If you have big troubles compiling socat then try configure with options + --disable-filan --disable-sycls; this excludes some of the most system + dependent parts. + +* After successful compilation and linking, run "make test" and try some + examples. + + +ACTIVE PHASE: + +* Check the man pages of your operating system for open(2), fcntl(2), + setsockopt(2), ioctl(2), socket(7), ip(7), tcp(7), termios etc. and the + include files where you find the definitions of existing options, for new + options and implement them - again option-dependent. + Places to add code for the new options: + . 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 + . 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, + tcpopts) + . socat.html, socat.1, xio.help: write a short documentation and tell which + platform and version implements this option + +* problems may occur especially: + . with 16 or 64 bit systems + . if snprintf() etc. is missing + . on UNIX emulations, e.g. Cygwin + + +INTEGRATION + +* If you ported socat to another platform: + To let other people participate please send the modified files or a patch + file and the files generated by ./gatherinfo.sh to socat@dest-unreach.org. diff --git a/README b/README new file mode 100644 index 0000000..a30bf66 --- /dev/null +++ b/README @@ -0,0 +1,272 @@ + +about +----- + +socat is a relay for bidirectional data transfer between two independent data +channels. Each of these data channels may be a file, pipe, device (serial line +etc. or a pseudo terminal), a socket (UNIX, IP4, IP6 - raw, UDP, TCP), an +SSL socket, proxy CONNECT connection, a file descriptor (stdin etc.), the GNU +line editor (readline), a program, or a combination of two of these. +These modes include generation of "listening" sockets, named pipes, and pseudo +terminals. + +socat can be used, e.g., as TCP port forwarder (one-shot or daemon), as an +external socksifier, for attacking weak firewalls, as a shell interface to UNIX +sockets, IP6 relay, for redirecting TCP oriented programs to a serial line, to +logically connect serial lines on different computers, or to establish a +relatively secure environment (su and chroot) for running client or server +shell scripts with network connections. + +Many options are available to refine socats behaviour: +terminal parameters, open() options, file permissions, file and process owners, +basic socket options like bind address, advanced socket options like IP source +routing, linger, TTL, TOS (type of service), or TCP performance tuning. + +More capabilities, like daemon mode with forking, client address check, +"tail -f" mode, some stream data processing (line terminator conversion), +choosing sockets, pipes, or ptys for interprocess communication, debug and +trace options, logging to syslog, stderr or file, and last but not least +precise error messages make it a versatile tool for many different purposes. + +In fact, many of these features already exist in specialized tools; but until +now, there does not seem to exists another tool that provides such a generic, +flexible, simple and almost comprehensive (UNIX) byte stream connector. + + +packages +-------- + +before bothering with compilers, dependencies and include files, you might +try to get a binary distribution that matches your platform. Have a look at +the projects home page for actual information regarding socat binary +distributions. + + +platforms +--------- + +socat 1.6.0 was compiled and more or less successfully tested under the +following operating systems: + +SuSE Linux 10.1 on x86 +AIX 5.2 on PPC with gcc +Solaris 9 on Sparc with gcc +FreeBSD 6.1 on x86 +HP-UX B 11.11 on PA-RISC with gcc + +tests on Tru64 can no longer be performed because HP testdrive has taken down +these hosts. + +tests on Mac OS X can no longer be performed because the Sourceforge +compilefarm was discontinued. + +tests on NetBSD and OpenBSD can no longer be performed for the above reasons. + +Some versions of socat have been reported to successfully compile under older +Linux versions back to RedHat 2.1 (kernel 1.2.13, gcc 2.7.0), under AIX 4.1 and +4.3, SunOS 5.7-5.8, FreeBSD 4.2 - 4.9, MacOS X 10.1, Cygwin, Solaris 8 on x86, +OSR 5.0.6, NetBSD 1.6.1 and 2.0.2, OpenBSD 3.4 and 3.8, Tru64 5.1B, and Mac OS +X 10.1-10.2. + +It might well compile and run under other UNIX like operating systems. + + +install +------- + +Get the tarball and extract it: + gtar xzf socat.tar.gz + cd socat-1.6.0.0 + ./configure + make + su + make install # installs socat, filan, and procan in /usr/local/bin + +For compiling socat, gcc (or egc) is recommended. +If gcc is not available, the configure script will fail to determine +some features; then you'd better begin with one of the Makefiles and config.h's +from the Config directory. + +If you have problems with the OpenSSL library, you can apply the option +"--disable-openssl" to configure. + +If you have problems with the readline library or (n)curses, you can apply the +option "--disable-readline" to configure. + +If you have problems with the tcp wrappers library, you can apply the option +"--disable-libwrap" to configure. + +If you still get errors or a tremendous amount of warnings you can exclude +the features for system call tracing and file descriptor analyzing by +applying the options "--disable-sycls --disable-filan" to configure. + +You still need the functions vsnprintf and snprintf that are in the GNU libc, +but might not be available with some proprietary libc's. + +The configure script looks for headers and libraries of openssl, readline, and +tcp wrappers in the OS'es standard places and in the subdirectories include/ +and lib/ of the following places: + /sw/ + /usr/local/ + /opt/freeware/ + /usr/sfw/ +and for openssl also in: + /usr/local/ssl/ +In case of unexpected behaviour it is important to understand that configure +first searches for the appropriate include file and then expects to find the +library in the associated lib directory. That means, when e.g. a OpenSSL +installation resides under /usr/local and there is a symbolic link from +/usr/include/ssl/ssl.h to /usr/local/ssl/include/ssl/ssl.h, configure will find +the /usr/include/... header and will therefore expect libssl in /usr/lib +instead of /usr/local/... + +If configure does not find a header file or library but you know where it is, +you can specify additional search locations, e.g.: + export LIBS="-L$HOME/lib" + export CPPFLAGS="-I$HOME/include" +before running configure and make. + +For other operating systems, if socat does not compile without errors, refer to +the file PORTING. + + +platform specifics - redhat +--------------------------- + +On RedHat Linux 9.0, including openssl/ssl.h might fail due to problems with +the krb5-devel package. configure reacts with disabling openssl integration. +To solve this issue, help cpp to find the krb5.h include file: +CPPFLAGS="-I/usr/kerberos/include" ./configure + + +platform specifics - aix +------------------------ + +The flock() prototype is not available but the function is. Thus, to enable the +socat flock options, run configure and then change in config.h the line +/* #undef HAVE_FLOCK */ +to +#define HAVE_FLOCK 1 +and continue the build process. + +When using the OpenSSL rpm provided by IBM, configure might need the +environment variable setting: +LIBS="-L/opt/freeware/lib" + +When using the OpenSSL bundle provided by IBM, egd needs to be installed too +to get enough entropy. + +socat compiles not only with gcc, but also with xlc. Just adapt the Makefile: +replace gcc by /usr/vac/bin/xlc and remove gcc specific options +"-Wall -Wno-parentheses". + +When linking with the OpenSSL library provided by IBM, errors may occur: +ld: 0711-317 ERROR: Undefined symbol: .__umoddi3 +In this case, you need to link with libgcc or compile libcrypt yourself using +xlc, or disable SSL (in config.h, undefine WITH_OPENSSL and recompile) + +The score of test.sh can be improved by uncommenting MISCDELAY=1 in this +script. + + +platform specifics - solaris +---------------------------- + +If libreadline or libssl are in a directory not searched by the loader per +default, e.g. /opt/sfw/lib, you must add this directory to $LD_LIBRARY_PATH, +for running both configure and the socat executables, e.g.: +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/sfw/lib + +For some shell scripts, it is preferable to have /usr/xpg4/bin at a prominent +position in $PATH. + + +platform specifics - hp-ux +-------------------------- + +Shutting down the write channel of a UNIX domain socket does not seem to +trigger an EOF on the other socket. This makes problems with the exec and +system addresses. + +This OS provides the type "long long", but not the strtoll() function to read +data into a long long variable. + +UNIX domain sockets are only supported with SOCK_STREAM, not with datagrams +(see man 7 unix). + +With UDP sockets it seems to happen that the select() call reports available +data (or EOF) but a subsequent read() call hangs. + + +platform specifics - tru64 +-------------------------- + +When the use of the readline address fails with an error like: +socat: /sbin/loader: Fatal Error: Reference to unresolvable symbol "tgetent" in ".../libreadline.so.4" +and you still want to use shared libraries, try the following workaround: +$ make distclean; LIBS="-static" ./configure +remove the "-static" occurrence in Makefile +$ make + + +documentation +------------- + +These files reside in the doc subdirectory: + +socat.1 is the man page, socat.html is the HTML based man page. It is actual, +but describes only the more useful options. + +xio.help is an older, but more exact description in text form; with socat +version 1.6.0 it is outdated. + +doc/socat-openssltunnel.html is a simple tutorial for a private SSL connection. +doc/socat-multicast.html is a short tutorial for multicast and broadcast +communications. +doc/socat-tun shows how to build a virtual network between two hosts. + + +license +------- + +socat is distributed under the terms of the GNU GPL; +except for install-sh, which is copyright MIT, with its own license; + +In addition, as a special exception, the copyright holder +gives permission to link the code of this program with +any version of the OpenSSL library which is distributed +under a license identical to that listed in the included +COPYING.OpenSSL file, and distribute linked combinations +including the two. You must obey the GNU General Public +License in all respects for all of the code used other +than OpenSSL. If you modify this file, you may extend this +exception to your version of the file, but you are not +obligated to do so. If you do not wish to do so, delete +this exception statement from your version. + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2 of the License + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + +contact +------- + +For questions, bug reports, ideas, contributions etc. please contact +socat@dest-unreach.org + +For socat source distribution, bug fixes, and latest news see + http://www.dest-unreach.org/socat/ + +www.socat.org is an alternate site providing the same contents. + diff --git a/README.FIPS b/README.FIPS new file mode 100644 index 0000000..0452844 --- /dev/null +++ b/README.FIPS @@ -0,0 +1,67 @@ + +David Acker has patched socat to add OpenSSL FIPS. +See http://oss-institute.org/fips-faq.html and +http://linuxdevices.com/news/NS4742716157.html for more information. + +The patch that is integrated into socat 1.5 does the following: + +Add support for LDFLAGS in Makefile. LDFLAGS can be specified on the +configure command line and then will be carried over into the make. + +Add fips support. Requires OpenSSL 0.9.7j-fips-dev from +http://www.openssl.org/source/OpenSSL-fips-1.0.tar.gz built with fips +support turned on. use ./Configure fips [os-arc], for example +./Configure fips linux-pentium + +The LDFLAGS is needed to point a build against a library +located in a non-standard location. For example, if you download and +build openssl manually, it gets installed in /usr/local/ssl by default. + +The FIPS support patches involve adding an option to enable/disable fips +in configure (enabled by default), checking the system for FIPS support +during configure, and then adding a fips option to socats openssl address +to turn on fips mode. The openssl binary uses an environment variable +instead of a command line flag. +FIPS mode requires both a compile time flag of OPENSSL_FIPS and a +runtime call of FIPS_mode_set(1). Fips mode requires building with the +fipsld script provided by OpenSSL. FIPS tracks the pid of the process that +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 build openssl +download OpenSSL 0.9.7j-fips-dev from +http://www.openssl.org/source/OpenSSL-fips-1.0.tar.gz +tar xzf OpenSSL-fips-1.0.tar.gz +cd openssl +./Configure fips linux-pentium +make +make test +(become root) +make install +This leaves an install in /usr/local/ssl + +To build socat: +setup directory with socat 1.5 or higher. +cd socat-1.5.0.0 +./configure CPPFLAGS=-I/usr/local/ssl/include/ LDFLAGS=-L/usr/local/ssl/lib/ FIPSLD=/usr/local/ssl/bin/fipsld +make +(become root) +make install + +To run tests we make sure the new openssl is used: + +export PATH=/usr/local/ssl/bin:$PATH +./test.sh fips + +There are two tests in test.sh that depend on fips: + +OPENSSL_FIPS_BOTHAUTH performs a SSL client to server connection with +certificate based authentication in both directions. If it works FIPS mode +seems to be ok. + +OPENSSL_FIPS_SECURITY generates a certificaet/key pair without fips support. It +then tries a SSL connection in "normal" mode which is expected to work. In the +second phase it uses fips mode with these credentials which is expected to +fail. If so, the test succeeded. diff --git a/SECURITY b/SECURITY new file mode 100644 index 0000000..0e10075 --- /dev/null +++ b/SECURITY @@ -0,0 +1,41 @@ + +Tips for using socat in secured environments: + +* Configure socat to only enable the required features, e.g. to protect your + filesystem from any accesses through socat: + make distclean + ./configure --disable-file --disable-creat --disable-gopen \ + --disable-pipe --disable-unix --disable-exec --disable-system + use "socat -V" to see what features are still enabled; see + ./configure --help for more options to disable + +* Do NOT install socat SUID root or so when you have untrusted users or +unprivileged daemons on your machine, because the full install of socat can +override arbitrary files and execute arbitrary programs! + +* Set logging to "-d -d" (in special cases even higher) + +* With files, protect against symlink attacks with nofollow (Linux), and +avoid accessing files in world-writable directories like /tmp + +* When listening, use bind option (except UNIX domain sockets) + +* When listening, use range option (currently only for IP4 sockets) + +* 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 + +* When starting programs with socat, consider using the chroot option (this +requires root, so use the substuser option too). + +* Start socat as root only if required; if so, use substuser option +Note: starting a SUID program after applying substuser or setuid gives the +process the SUID owner, which might give root privileges again. + +* Socat, like netcat, is what intruders like to have on their victims machine: +once they have gained a toehold they try to establish a versatile connection +back to their attack base, and they want to attack other systems. For both +purposes, socat could be helpful. Therefore, it might be useful to install +socat with owner/permissions root:socatgrp/750, and to make all trusted users +members of group socatgrp. diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..32c65da --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +"1.6.0.0" diff --git a/compat.h b/compat.h new file mode 100644 index 0000000..21f4200 --- /dev/null +++ b/compat.h @@ -0,0 +1,640 @@ +/* $Id: compat.h,v 1.32 2006/06/19 20:28:52 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __compat_h_included +#define __compat_h_included 1 + +/*****************************************************************************/ +/* I dont like this system dependent part, but it would be quit a challenge for + configure */ + +/* define if the following does not work: + socket() + connect() -> Connection refused + connect() -> ok + instead, it needs close() and socket() between the two connect() attmpts: */ +#if __FreeBSD__ || __APPLE__ || _AIX || __hpux__ || __osf__ +# undef SOCKET_CAN_RECOVER +#else +# define SOCKET_CAN_RECOVER 1 +#endif + +/* define if stat() says that pipes are sockets */ +#if __APPLE__ +# define PIPE_STATES_SOCKET 1 +#else +# undef PIPE_STATES_SOCKET +#endif + +/*****************************************************************************/ + +/* substitute some features that might be missing on some platforms */ + +#ifndef SHUT_RD +# define SHUT_RD 0 +#endif +#ifndef SHUT_WR +# define SHUT_WR 1 +#endif +#ifndef SHUT_RDWR +# define SHUT_RDWR 2 +#endif + +#ifndef MIN +# define MIN(x,y) ((x)<=(y)?(x):(y)) +#endif + +#ifndef MAX +# define MAX(x,y) ((x)>=(y)?(x):(y)) +#endif + +/* O_ASYNC: Linux 2.2.10 */ +#if !defined(O_ASYNC) && defined(FASYNC) +# define O_ASYNC FASYNC +#endif + +/* NGROUPS not defined on Solaris */ +#if !defined(NGROUPS) && defined(NGROUPS_MAX) +# define NGROUPS NGROUPS_MAX +#endif + +/* UNIX_PATH_MAX: AIX 4.3.3 */ +#ifndef UNIX_PATH_MAX +# define UNIX_PATH_MAX 104 /*! why 104? Linux: 108 ! */ +#endif + + +/* SOL_IP: AIX 4.3.3 */ +#ifndef SOL_IP +# define SOL_IP 0 +#endif + +/* SOL_TCP: AIX 4.3.3 */ +#ifndef SOL_TCP +# define SOL_TCP IPPROTO_TCP +#endif + +/* POSIX.1 doesn't seem to know sockets */ +#ifndef S_ISSOCK +# define S_ISSOCK(fmode) 0 +#endif + +#if defined(IPPROTO_IPV6) && !defined(SOL_IPV6) +# define SOL_IPV6 IPPROTO_IPV6 +#endif + +/* all unsigned */ +#if !defined(HAVE_BASIC_SIZE_T) || !HAVE_BASIC_SIZE_T +# undef HAVE_BASIC_SIZE_T +# define HAVE_BASIC_SIZE_T 6 +#endif +#if HAVE_BASIC_SIZE_T==2 +# define SIZET_MAX USHRT_MAX +# define SSIZET_MIN SHRT_MIN +# define SSIZET_MAX SHRT_MAX +# define F_Zd "%hd" +# define F_Zu "%hu" +#elif HAVE_BASIC_SIZE_T==4 +# define SIZET_MAX UINT_MAX +# define SSIZET_MIN INT_MIN +# define SSIZET_MAX INT_MAX +# define F_Zd "%d" +# define F_Zu "%u" +#elif HAVE_BASIC_SIZE_T==6 +# define SIZET_MAX ULONG_MAX +# define SSIZET_MIN LONG_MIN +# define SSIZET_MAX LONG_MAX +# define F_Zd "%ld" +# define F_Zu "%lu" +#elif HAVE_BASIC_SIZE_T==8 +# define SIZET_MAX ULLONG_MAX +# define SSIZET_MIN LLONG_MIN +# define SSIZET_MAX LLONG_MAX +# define F_Zd "%Ld" +# define F_Zu "%Lu" +#else +# error "HAVE_BASIC_SIZE_T is out of range:" HAVE_BASIC_SIZE_T +#endif +#if HAVE_FORMAT_Z +# undef F_Zd +# undef F_Zu +# define F_Zd "%Zd" +# define F_Zu "%Zu" +#endif + + +/* mode_t is always unsigned; default: unsigned int */ +#if !defined(HAVE_BASIC_MODE_T) || !HAVE_BASIC_MODE_T +# undef HAVE_BASIC_MODE_T +# define HAVE_BASIC_MODE_T 4 +#endif +#ifndef F_mode +# if HAVE_BASIC_MODE_T==1 || HAVE_BASIC_MODE_T==2 +#define F_mode "0%03ho" +# elif HAVE_BASIC_MODE_T==3 || HAVE_BASIC_MODE_T==4 +#define F_mode "0%03o" +# elif HAVE_BASIC_MODE_T==5 || HAVE_BASIC_MODE_T==6 +#define F_mode "0%03lo" +# else +#error "HAVE_BASIC_MODE_T is out of range:" HAVE_BASIC_MODE_T +# endif +#endif + + +/* default: unsigned int */ +#if !defined(HAVE_BASIC_PID_T) || !HAVE_BASIC_PID_T +# undef HAVE_BASIC_PID_T +# define HAVE_BASIC_PID_T 4 +#endif +#ifndef F_pid +# if HAVE_BASIC_PID_T==1 +#define F_pid "%hd" +# elif HAVE_BASIC_PID_T==2 +#define F_pid "%hu" +# elif HAVE_BASIC_PID_T==3 +#define F_pid "%d" +# elif HAVE_BASIC_PID_T==4 +#define F_pid "%u" +# elif HAVE_BASIC_PID_T==5 +#define F_pid "%ld" +# elif HAVE_BASIC_PID_T==6 +#define F_pid "%lu" +# else +#error "HAVE_BASIC_PID_T is out of range:" HAVE_BASIC_PID_T +# endif +#endif + + +/* default: unsigned int */ +#if !defined(HAVE_BASIC_UID_T) || !HAVE_BASIC_UID_T +# undef HAVE_BASIC_UID_T +# define HAVE_BASIC_UID_T 4 +#endif +#ifndef F_uid +# if HAVE_BASIC_UID_T==1 +#define F_uid "%hd" +# elif HAVE_BASIC_UID_T==2 +#define F_uid "%hu" +# elif HAVE_BASIC_UID_T==3 +#define F_uid "%d" +# elif HAVE_BASIC_UID_T==4 +#define F_uid "%u" +# elif HAVE_BASIC_UID_T==5 +#define F_uid "%ld" +# elif HAVE_BASIC_UID_T==6 +#define F_uid "%lu" +# else +#error "HAVE_BASIC_UID_T is out of range:" HAVE_BASIC_UID_T +# endif +#endif + + +/* default: unsigned int */ +#if !defined(HAVE_BASIC_GID_T) || !HAVE_BASIC_GID_T +# undef HAVE_BASIC_GID_T +# define HAVE_BASIC_GID_T 4 +#endif +#ifndef F_gid +# if HAVE_BASIC_GID_T==1 +#define F_gid "%hd" +# elif HAVE_BASIC_GID_T==2 +#define F_gid "%hu" +# elif HAVE_BASIC_GID_T==3 +#define F_gid "%d" +# elif HAVE_BASIC_GID_T==4 +#define F_gid "%u" +# elif HAVE_BASIC_GID_T==5 +#define F_gid "%ld" +# elif HAVE_BASIC_GID_T==6 +#define F_gid "%lu" +# else +#error "HAVE_BASIC_GID_T is out of range:" HAVE_BASIC_GID_T +# endif +#endif + + +/* all signed; default: long */ +#if !defined(HAVE_BASIC_TIME_T) || !HAVE_BASIC_TIME_T +# undef HAVE_BASIC_TIME_T +# define HAVE_BASIC_TIME_T 5 +#endif +#ifndef F_time +# if HAVE_BASIC_TIME_T==1 +#define F_time "%hd" +# elif HAVE_BASIC_TIME_T==2 +#define F_time "%hu" +# elif HAVE_BASIC_TIME_T==3 +#define F_time "%d" +# elif HAVE_BASIC_TIME_T==4 +#define F_time "%u" +# elif HAVE_BASIC_TIME_T==5 +#define F_time "%ld" +# elif HAVE_BASIC_TIME_T==6 +#define F_time "%lu" +# else +#error "HAVE_BASIC_TIME_T is out of range:" HAVE_BASIC_TIME_T +# endif +#endif + + +/* default: int */ +#if !defined(HAVE_BASIC_SOCKLEN_T) || !HAVE_BASIC_SOCKLEN_T +# undef HAVE_BASIC_SOCKLEN_T +# define HAVE_BASIC_SOCKLEN_T 3 +#endif +#ifndef F_socklen +# if HAVE_BASIC_SOCKLEN_T==1 +#define F_socklen "%hd" +# elif HAVE_BASIC_SOCKLEN_T==2 +#define F_socklen "%hu" +# elif HAVE_BASIC_SOCKLEN_T==3 +#define F_socklen "%d" +# elif HAVE_BASIC_SOCKLEN_T==4 +#define F_socklen "%u" +# elif HAVE_BASIC_SOCKLEN_T==5 +#define F_socklen "%ld" +# elif HAVE_BASIC_SOCKLEN_T==6 +#define F_socklen "%lu" +# else +#error "HAVE_BASIC_SOCKLEN_T is out of range:" HAVE_BASIC_SOCKLEN_T +# endif +#endif + +/* might be checked in later versions */ +#ifndef F_off +#define F_off "%ld" +#endif + +/* default: long long */ +#if !defined(HAVE_BASIC_OFF64_T) || !HAVE_BASIC_OFF64_T +# undef HAVE_BASIC_OFF64_T +# define HAVE_BASIC_OFF64_T 7 +#endif +#ifndef F_off64 +# if HAVE_BASIC_OFF64_T==1 +#define F_off64 "%hd" +# elif HAVE_BASIC_OFF64_T==2 +#define F_off64 "%hu" +# elif HAVE_BASIC_OFF64_T==3 +#define F_off64 "%d" +# elif HAVE_BASIC_OFF64_T==4 +#define F_off64 "%u" +# elif HAVE_BASIC_OFF64_T==5 +#define F_off64 "%ld" +# elif HAVE_BASIC_OFF64_T==6 +#define F_off64 "%lu" +# elif HAVE_BASIC_OFF64_T==7 +#define F_off64 "%Ld" +# elif HAVE_BASIC_OFF64_T==8 +#define F_off64 "%Lu" +# else +#error "HAVE_BASIC_OFF64_T is out of range:" HAVE_BASIC_OFF64_T +# endif +#endif + + +/* all unsigned; default: unsigned long */ +#if !defined(HAVE_TYPEOF_ST_DEV) || !HAVE_TYPEOF_ST_DEV +# undef HAVE_TYPEOF_ST_DEV +# define HAVE_TYPEOF_ST_DEV 6 +#endif +#ifndef F_st_dev +# if HAVE_TYPEOF_ST_DEV==1 +#define F_st_dev "%hd" +# elif HAVE_TYPEOF_ST_DEV==2 +#define F_st_dev "%hu" +# elif HAVE_TYPEOF_ST_DEV==3 +#define F_st_dev "%d" +# elif HAVE_TYPEOF_ST_DEV==4 +#define F_st_dev "%u" +# elif HAVE_TYPEOF_ST_DEV==5 +#define F_st_dev "%ld" +# elif HAVE_TYPEOF_ST_DEV==6 +#define F_st_dev "%lu" +# elif HAVE_TYPEOF_ST_DEV==7 +#define F_st_dev "%Ld" +# elif HAVE_TYPEOF_ST_DEV==8 +#define F_st_dev "%Lu" +# else +#error "HAVE_TYPEOF_ST_DEV is out of range:" HAVE_TYPEOF_ST_DEV +# endif +#endif + +/* all unsigned; default; unsigned long */ +#if !defined(HAVE_TYPEOF_ST_INO) || !HAVE_TYPEOF_ST_INO +# undef HAVE_TYPEOF_ST_INO +# define HAVE_TYPEOF_ST_INO 6 +#endif +#ifndef F_st_ino +# if HAVE_TYPEOF_ST_INO==1 +#define F_st_ino "%hd" +# elif HAVE_TYPEOF_ST_INO==2 +#define F_st_ino "%hu" +# elif HAVE_TYPEOF_ST_INO==3 +#define F_st_ino "%d" +# elif HAVE_TYPEOF_ST_INO==4 +#define F_st_ino "%u" +# elif HAVE_TYPEOF_ST_INO==5 +#define F_st_ino "%ld" +# elif HAVE_TYPEOF_ST_INO==6 +#define F_st_ino "%lu" +# elif HAVE_TYPEOF_ST_INO==7 /* Cygwin 1.5 */ +#define F_st_ino "%Ld" +# elif HAVE_TYPEOF_ST_INO==8 +#define F_st_ino "%Lu" +# else +#error "HAVE_TYPEOF_ST_INO is out of range:" HAVE_TYPEOF_ST_INO +# endif +#endif + +/* all unsigned; default; unsigned long long */ +#if !defined(HAVE_TYPEOF_ST64_INO) || !HAVE_TYPEOF_ST64_INO +# undef HAVE_TYPEOF_ST64_INO +# define HAVE_TYPEOF_ST64_INO 8 +#endif +#ifndef F_st64_ino +# if HAVE_TYPEOF_ST64_INO==1 +#define F_st64_ino "%hd" +# elif HAVE_TYPEOF_ST64_INO==2 +#define F_st64_ino "%hu" +# elif HAVE_TYPEOF_ST64_INO==3 +#define F_st64_ino "%d" +# elif HAVE_TYPEOF_ST64_INO==4 +#define F_st64_ino "%u" +# elif HAVE_TYPEOF_ST64_INO==5 +#define F_st64_ino "%ld" +# elif HAVE_TYPEOF_ST64_INO==6 +#define F_st64_ino "%lu" +# elif HAVE_TYPEOF_ST64_INO==7 +#define F_st64_ino "%Ld" +# elif HAVE_TYPEOF_ST64_INO==8 +#define F_st64_ino "%Lu" +# else +#error "HAVE_TYPEOF_ST64_INO is out of range:" HAVE_TYPEOF_ST64_INO +# endif +#endif + +/* default: unsigned short */ +#if !defined(HAVE_TYPEOF_ST_NLINK) || !HAVE_TYPEOF_ST_NLINK +# undef HAVE_TYPEOF_ST_NLINK +# define HAVE_TYPEOF_ST_NLINK 2 +#endif +#ifndef F_st_nlink +# if HAVE_TYPEOF_ST_NLINK==1 +#define F_st_nlink "%hd" +# elif HAVE_TYPEOF_ST_NLINK==2 +#define F_st_nlink "%hu" +# elif HAVE_TYPEOF_ST_NLINK==3 +#define F_st_nlink "%d" +# elif HAVE_TYPEOF_ST_NLINK==4 +#define F_st_nlink "%u" +# elif HAVE_TYPEOF_ST_NLINK==5 +#define F_st_nlink "%ld" +# elif HAVE_TYPEOF_ST_NLINK==6 +#define F_st_nlink "%lu" +# else +#error "HAVE_TYPEOF_ST_NLINK is out of range:" HAVE_TYPEOF_ST_NLINK +# endif +#endif + +/* all signed; default: long */ +#if !defined(HAVE_TYPEOF_ST_SIZE) || !HAVE_TYPEOF_ST_SIZE +# undef HAVE_TYPEOF_ST_SIZE +# define HAVE_TYPEOF_ST_SIZE 5 +#endif +#ifndef F_st_size +# if HAVE_TYPEOF_ST_SIZE==1 +#define F_st_size "%hd" +# elif HAVE_TYPEOF_ST_SIZE==2 +#define F_st_size "%hu" +# elif HAVE_TYPEOF_ST_SIZE==3 +#define F_st_size "%d" +# elif HAVE_TYPEOF_ST_SIZE==4 +#define F_st_size "%u" +# elif HAVE_TYPEOF_ST_SIZE==5 +#define F_st_size "%ld" +# elif HAVE_TYPEOF_ST_SIZE==6 +#define F_st_size "%lu" +# elif HAVE_TYPEOF_ST_SIZE==7 +#define F_st_size "%Ld" +# elif HAVE_TYPEOF_ST_SIZE==8 +#define F_st_size "%Lu" +# else +#error "HAVE_TYPEOF_ST_SIZE is out of range:" HAVE_TYPEOF_ST_SIZE +# endif +#endif + +/* all signed; default: long long */ +#if !defined(HAVE_TYPEOF_ST64_SIZE) || !HAVE_TYPEOF_ST64_SIZE +# undef HAVE_TYPEOF_ST64_SIZE +# define HAVE_TYPEOF_ST64_SIZE 7 +#endif +#ifndef F_st64_size +# if HAVE_TYPEOF_ST64_SIZE==1 +#define F_st64_size "%hd" +# elif HAVE_TYPEOF_ST64_SIZE==2 +#define F_st64_size "%hu" +# elif HAVE_TYPEOF_ST64_SIZE==3 +#define F_st64_size "%d" +# elif HAVE_TYPEOF_ST64_SIZE==4 +#define F_st64_size "%u" +# elif HAVE_TYPEOF_ST64_SIZE==5 +#define F_st64_size "%ld" +# elif HAVE_TYPEOF_ST64_SIZE==6 +#define F_st64_size "%lu" +# elif HAVE_TYPEOF_ST64_SIZE==7 +#define F_st64_size "%Ld" +# elif HAVE_TYPEOF_ST64_SIZE==8 +#define F_st64_size "%Lu" +# else +#error "HAVE_TYPEOF_ST64_SIZE is out of range:" HAVE_TYPEOF_ST64_SIZE +# endif +#endif + +/* very different results; default: long */ +#if !defined(HAVE_TYPEOF_ST_BLKSIZE) || !HAVE_TYPEOF_ST_BLKSIZE +# undef HAVE_TYPEOF_ST_BLKSIZE +# define HAVE_TYPEOF_ST_BLKSIZE 5 +#endif +#ifndef F_st_blksize +# if HAVE_TYPEOF_ST_BLKSIZE==1 +#define F_st_blksize "%hd" +# elif HAVE_TYPEOF_ST_BLKSIZE==2 +#define F_st_blksize "%hu" +# elif HAVE_TYPEOF_ST_BLKSIZE==3 +#define F_st_blksize "%d" +# elif HAVE_TYPEOF_ST_BLKSIZE==4 +#define F_st_blksize "%u" +# elif HAVE_TYPEOF_ST_BLKSIZE==5 +#define F_st_blksize "%ld" +# elif HAVE_TYPEOF_ST_BLKSIZE==6 +#define F_st_blksize "%lu" +# else +#error "HAVE_TYPEOF_ST_BLKSIZE is out of range:" HAVE_TYPEOF_ST_BLKSIZE +# endif +#endif + +/* default: long */ +#if !defined(HAVE_TYPEOF_ST_BLOCKS) || !HAVE_TYPEOF_ST_BLOCKS +# undef HAVE_TYPEOF_ST_BLOCKS +# define HAVE_TYPEOF_ST_BLOCKS 5 +#endif +#ifndef F_st_blocks +# if HAVE_TYPEOF_ST_BLOCKS==1 +#define F_st_blocks "%hd" +# elif HAVE_TYPEOF_ST_BLOCKS==2 +#define F_st_blocks "%hu" +# elif HAVE_TYPEOF_ST_BLOCKS==3 +#define F_st_blocks "%d" +# elif HAVE_TYPEOF_ST_BLOCKS==4 +#define F_st_blocks "%u" +# elif HAVE_TYPEOF_ST_BLOCKS==5 +#define F_st_blocks "%ld" +# elif HAVE_TYPEOF_ST_BLOCKS==6 +#define F_st_blocks "%lu" +# elif HAVE_TYPEOF_ST_BLOCKS==7 +#define F_st_blocks "%Ld" +# elif HAVE_TYPEOF_ST_BLOCKS==8 +#define F_st_blocks "%Lu" +# else +#error "HAVE_TYPEOF_ST_BLOCKS is out of range:" HAVE_TYPEOF_ST_BLOCKS +# endif +#endif + +/* default: long long */ +#if !defined(HAVE_TYPEOF_ST64_BLOCKS) || !HAVE_TYPEOF_ST64_BLOCKS +# undef HAVE_TYPEOF_ST64_BLOCKS +# define HAVE_TYPEOF_ST64_BLOCKS 7 +#endif +#ifndef F_st64_blocks +# if HAVE_TYPEOF_ST64_BLOCKS==1 +#define F_st64_blocks "%hd" +# elif HAVE_TYPEOF_ST64_BLOCKS==2 +#define F_st64_blocks "%hu" +# elif HAVE_TYPEOF_ST64_BLOCKS==3 +#define F_st64_blocks "%d" +# elif HAVE_TYPEOF_ST64_BLOCKS==4 +#define F_st64_blocks "%u" +# elif HAVE_TYPEOF_ST64_BLOCKS==5 +#define F_st64_blocks "%ld" +# elif HAVE_TYPEOF_ST64_BLOCKS==6 +#define F_st64_blocks "%lu" +# elif HAVE_TYPEOF_ST64_BLOCKS==7 +#define F_st64_blocks "%Ld" +# elif HAVE_TYPEOF_ST64_BLOCKS==8 +#define F_st64_blocks "%Lu" +# else +#error "HAVE_TYPEOF_ST64_BLOCKS is out of range:" HAVE_TYPEOF_ST64_BLOCKS +# endif +#endif + + +/* at least for Linux */ +#define F_tv_sec "%ld" + +/* default: long */ +#if !defined(HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC) || !HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC +# undef HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC +# define HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC 5 +#endif +#ifndef F_tv_usec +# if HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC==1 +#define F_tv_usec "%06hd" +# elif HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC==2 +#define F_tv_usec "%06hu" +# elif HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC==3 +#define F_tv_usec "%06d" +# elif HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC==4 +#define F_tv_usec "%06u" +# elif HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC==5 +#define F_tv_usec "%06ld" +# elif HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC==6 +#define F_tv_usec "%06lu" +# elif HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC==7 +#define F_tv_usec "%06Ld" +# elif HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC==8 +#define F_tv_usec "%06Lu" +# else +#error "HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC is out of range:" HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC +# endif +#endif + +/* default: long */ +#if !defined(HAVE_TYPEOF_RLIM_MAX) || !HAVE_TYPEOF_RLIM_MAX +# undef HAVE_TYPEOF_RLIM_MAX +# define HAVE_TYPEOF_RLIM_MAX 5 +#endif +#ifndef F_rlim_max +# if HAVE_TYPEOF_RLIM_MAX==1 +#define F_rlim_max "hd" +# elif HAVE_TYPEOF_RLIM_MAX==2 +#define F_rlim_max "hu" +# elif HAVE_TYPEOF_RLIM_MAX==3 +#define F_rlim_max "d" +# elif HAVE_TYPEOF_RLIM_MAX==4 +#define F_rlim_max "u" +# elif HAVE_TYPEOF_RLIM_MAX==5 +#define F_rlim_max "ld" +# elif HAVE_TYPEOF_RLIM_MAX==6 +#define F_rlim_max "lu" +# elif HAVE_TYPEOF_RLIM_MAX==7 +#define F_rlim_max "Ld" +# elif HAVE_TYPEOF_RLIM_MAX==8 +#define F_rlim_max "Lu" +# else +#error "HAVE_TYPEOF_RLIM_MAX is out of range:" HAVE_TYPEOF_RLIM_MAX +# endif +#endif + +/* Cygwin 1.3.22 has the prototypes, but not the type... */ +#ifndef HAVE_TYPE_STAT64 +# undef HAVE_STAT64 +# undef HAVE_FSTAT64 +# undef HAVE_LSTAT64 +#endif +#ifndef HAVE_TYPE_OFF64 +# undef HAVE_LSEEK64 +# undef HAVE_FTRUNCATE64 +#endif + +#if !defined(NETDB_INTERNAL) && defined(h_NETDB_INTERNAL) +# define NETDB_INTERNAL h_NETDB_INTERNAL +#endif + +#if !HAVE_PROTOTYPE_HSTRERROR +/* with MacOSX this is char * */ +extern const char *hstrerror(int); +#endif + +/*****************************************************************************/ +/* here are the declarations of compat.c */ + +#if !HAVE_SIGACTION +struct sigaction { + void (*sa_handler)(int); + void (*sa_sigaction)(int, siginfo_t *, void *); + sigset_t sa_mask; + int sa_flags; +} ; +struct siginfo { + int si_signo; + int si_errno; + int si_code; + pid_t si_pid; + uid_t si_uid; + int si_status; + /*clock_t si_utime;*/ + /*clock_t si_stime;*/ + sigval_t si_value; + int si_int; + void *si_ptr; + void *si_addr; + /*int si_band;*/ + /*int si_fd;*/ +} ; +extern int sigaction(int signum, const struct sigaction *act, + struct sigaction *oldact); +#endif /* !HAVE_SIGACTION */ + +#endif /* !defined(__compat_h_included) */ diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..1dabea2 --- /dev/null +++ b/config.h.in @@ -0,0 +1,484 @@ +/* $Id: config.h.in,v 1.63 2007/03/06 21:00:16 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __config_h_included +#define __config_h_included 1 + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define to `int' if doesn't define. */ +#undef gid_t + +/* Define if your struct stat has st_blksize. */ +#undef HAVE_ST_BLKSIZE + +/* Define if your struct stat has st_blocks. */ +#undef HAVE_ST_BLOCKS + +/* Define if your struct stat has st_rdev. */ +#undef HAVE_ST_RDEV + +/* Define if you have the strftime function. */ +#undef HAVE_STRFTIME + +/* Define if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define to `int' if doesn't define. */ +#undef mode_t + +/* Define to `long' if doesn't define. */ +#undef off_t + +/* Define to `int' if doesn't define. */ +#undef pid_t + +/* Define as the return type of signal handlers (int or void). */ +#undef RETSIGTYPE + +/* Define to `unsigned' if doesn't define. */ +#undef size_t + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Define to `int' if doesn't define. */ +#undef uid_t + +/* Define if you have the putenv function. */ +#undef HAVE_PUTENV + +/* Define if you have the select function. */ +#undef HAVE_SELECT + +/* Define if you have the poll function. */ +#undef HAVE_POLL + +/* Define if you have the socket function. */ +#undef HAVE_SOCKET + +/* Define if you have the strdup function. */ +#undef HAVE_STRDUP + +/* Define if you have the strerror function. */ +#undef HAVE_STRERROR + +/* Define if you have the strstr function. */ +#undef HAVE_STRSTR + +/* Define if you have the strtod function. */ +#undef HAVE_STRTOD + +/* Define if you have the strtol function. */ +#undef HAVE_STRTOL + +/* Define if you have the strtoul function. */ +#undef HAVE_STRTOUL + +/* Define if you have the uname function. */ +#undef HAVE_UNAME + +/* Define if you have the getpgid function. */ +#undef HAVE_GETPGID + +/* Define if you have the getsid function. */ +#undef HAVE_GETSID + +/* Define if you have the nanosleep function. */ +#undef HAVE_NANOSLEEP + +/* Define if you have the getaddrinfo function. */ +#undef HAVE_GETADDRINFO + +/* Define if you have the getipnodebyname function. */ +#undef HAVE_GETIPNODEBYNAME + +/* Define if you have the setgroups function. */ +#undef HAVE_SETGROUPS + +/* Define if you have the inet_aton function. */ +#undef HAVE_INET_ATON + +/* Define if you have the memrchr function. */ +#undef HAVE_MEMRCHR + +/* Define if you have the sigaction function */ +#undef HAVE_SIGACTION + +/* Define if you have the stat64 function */ +#undef HAVE_STAT64 + +/* Define if you have the fstat64 function */ +#undef HAVE_FSTAT64 + +/* Define if you have the lstat64 function */ +#undef HAVE_LSTAT64 + +/* Define if you have the lseek64 function */ +#undef HAVE_LSEEK64 + +/* Define if you have the truncate64 function */ +#undef HAVE_TRUNCATE64 + +/* Define if you have the ftruncate64 function */ +#undef HAVE_FTRUNCATE64 + +/* Define if you have the strtoll function */ +#undef HAVE_STRTOLL + +/* Define if you have the hstrerror function */ +#undef HAVE_HSTRERROR + +/* Define if you have the inet_ntop function */ +#undef HAVE_INET_NTOP + +/* Define if you have the hstrerror prototype */ +#undef HAVE_PROTOTYPE_HSTRERROR + +/* Define if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define if you have the header file. */ +#undef HAVE_SYSLOG_H + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define if you have the header file. */ +#undef HAVE_PWD_H + +/* Define if you have the header file. */ +#undef HAVE_GRP_H + +/* Define if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_POLL_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_UIO_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_UN_H + +/* Define if you have the header file. */ +#undef HAVE_PTY_H + +/* Define if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define if you have the header file. */ +#undef HAVE_NETINET_IN_SYSTM_H + +/* Define if you have the header file. */ +#undef HAVE_NETINET_IP_H + +/* Define if you have the header file. */ +#undef HAVE_NETINET_TCP_H + +/* Define if you have the header file. */ +#undef HAVE_NETINET_IP6_H + +/* Define if you have the header file. */ +#undef HAVE_ARPA_NAMESER_H + +/* Define if you have the header file. */ +#undef HAVE_RESOLV_H + +/* Define if you have the header file. */ +#undef HAVE_TERMIOS_H + +/* Define if you have the header file. */ +#undef HAVE_NET_IF_H + +/* Define if you have the header file. */ +#undef HAVE_LINUX_IF_TUN_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_UTSNAME_H + +/* Define if you have the header file. (AIX) */ +#undef HAVE_SYS_SELECT_H + +/* Define if you have the header file. (AIX) */ +#undef HAVE_SYS_FILE_H + +/* Define if you have the header file. (NetBSD, OpenBSD: openpty()) */ +#undef HAVE_UTIL_H + +/* Define if you have the header file. (FreeBSD: openpty()) */ +#undef HAVE_LIBUTIL_H + +/* Define if you have the header file. (stream opts on SunOS)*/ +#undef HAVE_SYS_STROPTS_H + +/* Define if you have the header file. */ +#undef HAVE_REGEX_H + +/* Define if you have the header file. */ +#undef HAVE_LINUX_FS_H + +/* Define if you have the header file. */ +#undef HAVE_LINUX_EXT2_FS_H + +/* Define if you have the header file. */ +#undef HAVE_READLINE_READLINE_H + +/* Define if you have the header file. */ +#undef HAVE_READLINE_HISTORY_H + +/* Define if you have the readline library. */ +#undef HAVE_LIBREADLINE + +/* Define if you have the m library (-lm). */ +#undef HAVE_LIBM + +/* Define if you have the floor function */ +#undef HAVE_FLOOR + +/* some platforms need _XOPEN_EXTENDED_SOURCE to get syslog headers (AIX4.1) */ +#undef _XOPEN_EXTENDED_SOURCE + +/* fdset may have component fds_bits or __fds_bits */ +#undef HAVE_FDS_BITS + +/* Define if your struct termios has component c_ispeed */ +#undef HAVE_TERMIOS_ISPEED + +/* the offset of c_ispeed in struct termios - usable in an speed_t array. + Applies only when HAVE_TERMIOS_ISPEED is set */ +#undef ISPEED_OFFSET + +/* the offset of c_ospeed in struct termios - see ISPEED_OFFSET */ +#ifdef ISPEED_OFFSET +# define OSPEED_OFFSET (ISPEED_OFFSET+1) +#else +# undef OSPEED_OFFSET +#endif + +/* Define if your termios.h likes _SVID3 defined */ +#undef _SVID3 + +/* Define if you have struct timespec (e.g. for nanosleep) */ +#undef HAVE_STRUCT_TIMESPEC + +/* Define if you have struct linger */ +#undef HAVE_STRUCT_LINGER + +/* Define if you have struct ip_mreq */ +#undef HAVE_STRUCT_IP_MREQ + +/* Define if you have struct ip_mreqn */ +#undef HAVE_STRUCT_IP_MREQN + +/* Define if you have struct ipv6_mreq */ +#undef HAVE_STRUCT_IPV6_MREQ + +/* Define if you have struct ifreq */ +#undef HAVE_STRUCT_IFREQ + +/* Define if you have struct ifreq.ifr_index */ +#undef HAVE_STRUCT_IFREQ_IFR_INDEX + +/* Define if you have struct ifreq.ifr_ifindex */ +#undef HAVE_STRUCT_IFREQ_IFR_IFINDEX + +/* Define if your struct sockaddr has sa_len */ +#undef HAVE_STRUCT_SOCKADDR_SALEN + +/* there are several implementations of sockaddr_in6 */ +#undef HAVE_IP6_SOCKADDR + +/* Define if you have struct iovec */ +#undef HAVE_STRUCT_IOVEC + +/* define if your struct msghdr has msg_control */ +#undef HAVE_STRUCT_MSGHDR_MSGCONTROL + +/* define if your struct msghdr has msg_controllen */ +#undef HAVE_STRUCT_MSGHDR_MSGCONTROLLEN + +/* define if your struct msghdr has msg_flag */ +#undef HAVE_STRUCT_MSGHDR_MSGFLAGS + +/* define if your struct ip has ip_hl; otherwise assume ip_vhl */ +#undef HAVE_STRUCT_IP_IP_HL + +/* Define if you have the setenv function */ +#undef HAVE_SETENV + +/* Define if you have the flock function */ +#undef HAVE_FLOCK + +/* Define if you have the openpty function */ +#undef HAVE_OPENPTY + +/* Define if you have the grantpt function */ +#undef HAVE_GRANTPT + +/* Define if you have the unlockpt function */ +#undef HAVE_UNLOCKPT + +/* Define if you have the ptsname function */ +#undef HAVE_PTSNAME + +/* Define if you have the /dev/ptmx pseudo terminal multiplexer */ +#undef HAVE_DEV_PTMX + +/* Define if you have the /dev/ptc pseudo terminal multiplexer */ +#undef HAVE_DEV_PTC + +/* Define if you have the long long type */ +#undef HAVE_TYPE_LONGLONG + +/* is socklen_t already typedef'd? */ +#undef HAVE_TYPE_SOCKLEN + +/* Define if you have the struct stat64 type */ +#undef HAVE_TYPE_STAT64 + +/* Define if you have the struct off64_t type */ +#undef HAVE_TYPE_OFF64 + +/* is sighandler_t already typedef'd? */ +#undef HAVE_TYPE_SIGHANDLER + +/* is uint8_t already defined? */ +#undef HAVE_TYPE_UINT8 + +/* is uint16_t already defined? */ +#undef HAVE_TYPE_UINT16 + +/* is uint32_t already defined? */ +#undef HAVE_TYPE_UINT32 + +/* is uint64_t already defined? */ +#undef HAVE_TYPE_UINT64 + +/* Define if you have the printf "Z" modifier */ +#undef HAVE_FORMAT_Z + +/* Define the shift offset of the CRDLY mask */ +#undef CRDLY_SHIFT + +/* Define the shift offset of the TABDLY mask */ +#undef TABDLY_SHIFT + +/* Define the shift offset of the CSIZE mask */ +#undef CSIZE_SHIFT + +/* Define if you have tcpwrappers (libwrap, tcpd) and it declares hosts_allow_table */ +#undef HAVE_HOSTS_ALLOW_TABLE +#if defined(HAVE_HOSTS_ALLOW_TABLE) && HAVE_HOSTS_ALLOW_TABLE +# define HAVE_HOSTS_DENY_TABLE 1 +#else +# undef HAVE_HOSTS_DENY_TABLE +#endif + +/* 1..short, 3..int, 5..long; 2,4,6..unsigned */ +#undef HAVE_BASIC_SIZE_T +#undef HAVE_BASIC_MODE_T +#undef HAVE_BASIC_PID_T +#undef HAVE_BASIC_UID_T +#undef HAVE_BASIC_GID_T +#undef HAVE_BASIC_TIME_T +#undef HAVE_BASIC_OFF64_T + +#undef HAVE_BASIC_SOCKLEN_T + +#undef HAVE_TYPEOF_ST_DEV +#undef HAVE_TYPEOF_ST_INO +#undef HAVE_TYPEOF_ST_NLINK +#undef HAVE_TYPEOF_ST_SIZE +#undef HAVE_TYPEOF_ST_BLKSIZE +#undef HAVE_TYPEOF_ST_BLOCKS + +#undef HAVE_TYPEOF_ST64_DEV +#undef HAVE_TYPEOF_ST64_INO +#undef HAVE_TYPEOF_ST64_NLINK +#undef HAVE_TYPEOF_ST64_SIZE +#undef HAVE_TYPEOF_ST64_BLKSIZE +#undef HAVE_TYPEOF_ST64_BLOCKS + +#undef HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC + +#undef HAVE_TYPEOF_RLIM_MAX + +/* Define if you have the /proc filesystem */ +#undef HAVE_PROC_DIR + +/* Define if you have the /proc/$$/fd directories */ +#undef HAVE_PROC_DIR_FD + +#undef WITH_HELP +#undef WITH_STDIO +#undef WITH_FDNUM +#undef WITH_FILE +#undef WITH_CREAT +#undef WITH_GOPEN +#undef WITH_TERMIOS +#undef WITH_PIPE +#undef WITH_UNIX +#undef WITH_ABSTRACT_UNIXSOCKET +#undef WITH_IP4 +#undef WITH_IP6 +#undef WITH_RAWIP +#undef WITH_TCP +#undef WITH_UDP +#undef WITH_LISTEN +#undef WITH_SOCKS4 +#undef WITH_SOCKS4A +#undef WITH_PROXY +#undef WITH_EXEC +#undef WITH_SYSTEM +#undef WITH_READLINE +#undef WITH_TUN +#undef WITH_PTY +#undef WITH_EXT2 +#undef WITH_OPENSSL +#undef WITH_FIPS +#undef OPENSSL_FIPS +#undef WITH_LIBWRAP +#undef HAVE_TCPD_H +#undef HAVE_LIBWRAP + +#undef WITH_SYCLS +#undef WITH_FILAN +#undef WITH_RETRY + +#undef WITH_MSGLEVEL + +#endif /* !defined(__config_h_included) */ diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..bf51c6a --- /dev/null +++ b/configure.in @@ -0,0 +1,1459 @@ +nl $Id: configure.in,v 1.108 2007/03/06 21:00:28 gerhard Exp $ +dnl Copyright Gerhard Rieger 2001-2007 +dnl Published under the GNU General Public License V.2, see file COPYING + +dnl Process this file with autoconf to produce a configure script. +AC_INIT(socat.c) + +AC_CONFIG_HEADER(config.h) + +if test -f /usr/xpg4/bin/fgrep; then + FGREP=/usr/xpg4/bin/fgrep # Solaris +else + FGREP=fgrep +fi + +# find out which defines gcc passes to cpp, so makedepend does not run into +# (harmless) "error architecture not supported" +AC_MSG_CHECKING(which defines needed for makedepend) +__cpp_defs=`gcc -v -E - &1 |$FGREP -e '/cpp ' -e '/cc1 '` +SYSDEFS=`aa=; for a in $__cpp_defs + do case "$a" in -D*) aa="$aa $a";; esac; done; echo "$aa"` +AC_SUBST(SYSDEFS) +AC_MSG_RESULT($SYSDEFS) + + +# this must come before AC_PROG_CC +if test -z "$CFLAGS"; then + # if CFLAGS is not set, we preset it to -O + # with this setting, we prevent autoconf from defaulting to "-g -O2" + export CFLAGS=-O +fi + +dnl Checks for programs. +AC_PROG_INSTALL(install) +AC_PROG_CC +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 +# fail +AC_LANG_COMPILER_REQUIRE() + +if test "$GCC" = yes; then + CFLAGS="$CFLAGS -D_GNU_SOURCE" +fi +export CFLAGS + + +dnl Checks for header files. +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS(fcntl.h limits.h strings.h sys/param.h sys/ioctl.h sys/time.h syslog.h unistd.h) +AC_CHECK_HEADERS(pwd.h grp.h stdint.h sys/types.h sys/poll.h sys/socket.h sys/uio.h sys/stat.h netdb.h sys/un.h) +AC_CHECK_HEADERS(pty.h) +AC_CHECK_HEADERS(netinet/in.h netinet/in_systm.h netinet/ip.h netinet/tcp.h) +AC_CHECK_HEADERS(netinet6/in6.h) # found on OpenBSD, used for IPV6_* +AC_CHECK_HEADERS(arpa/nameser.h resolv.h) +AC_CHECK_HEADERS(termios.h net/if.h linux/if_tun.h) +AC_CHECK_HEADERS(sys/utsname.h sys/select.h sys/file.h) +AC_CHECK_HEADERS(util.h libutil.h sys/stropts.h regex.h) +AC_CHECK_HEADERS(linux/fs.h linux/ext2_fs.h) + + +dnl Check for extra socket library (for Solaris) +AC_CHECK_FUNC(hstrerror, , AC_CHECK_LIB(resolv, hstrerror, [LIBS="$LIBS -lresolv"; AC_DEFINE(HAVE_HSTRERROR)])) +AC_CHECK_FUNC(gethostent, , AC_CHECK_LIB(nsl, gethostent)) +AC_CHECK_FUNC(setsockopt, , AC_CHECK_LIB(socket, setsockopt)) + + +dnl Check for hstrerror prototype +AC_MSG_CHECKING(for hstrerror prototype) +AC_CACHE_VAL(sc_cv_have_prototype_hstrerror, +[CFLAGS1="$CFLAGS"; CFLAGS="-Werror -O0 $CFLAGS1"; + AC_TRY_COMPILE([#include ],[hstrerror();], + [sc_cv_have_prototype_hstrerror=no], + [sc_cv_have_prototype_hstrerror=yes]); + CFLAGS="$CFLAGS1"]) +if test $sc_cv_have_prototype_hstrerror = yes; then + AC_DEFINE(HAVE_PROTOTYPE_HSTRERROR) +fi +AC_MSG_RESULT($sc_cv_have_prototype_hstrerror) + + +AC_MSG_CHECKING(whether to include help) +AC_ARG_ENABLE(help, [ --disable-help disable help], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_HELP) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_HELP) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING(whether to include STDIO support) +AC_ARG_ENABLE(stdio, [ --disable-stdio disable STDIO support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_STDIO) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_STDIO) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING(whether to include FD-number support) +AC_ARG_ENABLE(fdnum, [ --disable-fdnum disable FD-number support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_FDNUM) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_FDNUM) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING(whether to include direct file support) +AC_ARG_ENABLE(file, [ --disable-file disable direct file support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_FILE) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_FILE) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING(whether to include direct create support) +AC_ARG_ENABLE(creat, [ --disable-creat disable direct create support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_CREAT) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_CREAT) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING(whether to include gopen support) +AC_ARG_ENABLE(gopen, [ --disable-gopen disable open for UNIX socket support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_GOPEN) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_GOPEN) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING(whether to include explicit pipe support) +AC_ARG_ENABLE(pipe, [ --disable-pipe disable pipe support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_PIPE) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_PIPE) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING(whether to include explicit termios support) +AC_ARG_ENABLE(termios, [ --disable-termios disable termios support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_TERMIOS) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_TERMIOS) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING(whether to include UNIX socket support) +AC_ARG_ENABLE(unix, [ --disable-unix disable UNIX domain socket support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_UNIX) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_UNIX) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING(whether to include abstract UNIX socket support) +AC_ARG_ENABLE(abstract_unixsocket, [ --disable-abstract-unixsocket disable abstract UNIX domain socket support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_ABSTRACT_UNIXSOCKET) AC_MSG_RESULT(yes);; + esac], + [ case "`uname`" in + Linux) + AC_DEFINE(WITH_ABSTRACT_UNIXSOCKET) AC_MSG_RESULT(yes);; + *) + AC_MSG_RESULT(no);; + esac]) + +AC_MSG_CHECKING(whether to include IPv4 support) +AC_ARG_ENABLE(ip4, [ --disable-ip4 disable IPv4 support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_IP4) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_IP4) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING(whether to include IPv6 support) +AC_ARG_ENABLE(ip6, [ --disable-ip6 disable IPv6 support], + [case "$enableval" in + no) AC_MSG_RESULT(no); WITH_IP6= ;; + *) AC_MSG_RESULT(yes); WITH_IP6=1 ;; + esac], + [ AC_MSG_RESULT(yes); WITH_IP6=1 ]) +if test "$WITH_IP6"; then + AC_CHECK_HEADERS([netinet/ip6.h], + [AC_DEFINE(HAVE_NETINET_IP6_H) AC_DEFINE(WITH_IP6)], + [AC_MSG_WARN([include file netinet/ip6.h not found, disabling IP6])]) +fi + +AC_MSG_CHECKING(whether to include raw IP support) +AC_ARG_ENABLE(rawip, [ --disable-rawip disable raw IP support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_RAWIP) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_RAWIP) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING(whether to include TCP support) +AC_ARG_ENABLE(tcp, [ --disable-tcp disable TCP support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_TCP) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_TCP) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING(whether to include UDP support) +AC_ARG_ENABLE(udp, [ --disable-udp disable UDP support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_UDP) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_UDP) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING(whether to include listen support) +AC_ARG_ENABLE(listen, [ --disable-listen disable listen support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_LISTEN) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_LISTEN) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING(whether to include socks4 support) +AC_ARG_ENABLE(socks4, [ --disable-socks4 disable socks4 support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_SOCKS4) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_SOCKS4) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING(whether to include socks4a support) +AC_ARG_ENABLE(socks4a, [ --disable-socks4a disable socks4a support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_SOCKS4A) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_SOCKS4A) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING(whether to include proxy connect support) +AC_ARG_ENABLE(proxy, [ --disable-proxy disable proxy connect support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_PROXY) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_PROXY) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING(whether to include exec support) +AC_ARG_ENABLE(exec, [ --disable-exec disable exec support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_EXEC) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_EXEC) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING([whether to include system (shell) support]) +AC_ARG_ENABLE(system, [ --disable-system disable system (shell) support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_SYSTEM) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_SYSTEM) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING(whether to include pty address support) +AC_ARG_ENABLE(pty, [ --disable-pty disable pty support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_PTY) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_PTY) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING(whether to include ext2 fs attributes support) +AC_ARG_ENABLE(ext2, [ --disable-ext2 disable ext2 fs attributes support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_EXT2) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_EXT2) AC_MSG_RESULT(yes)]) + +AC_MSG_CHECKING(whether to include readline support) +AC_ARG_ENABLE(readline, [ --disable-readline disable readline support], + [case "$enableval" in + no) AC_MSG_RESULT(no); WITH_READLINE= ;; + *) AC_MSG_RESULT(yes); WITH_READLINE=1 ;; + esac], + [AC_MSG_RESULT(yes); WITH_READLINE=1 ]) + +# check if we find the components of GNU readline +if test -n "$WITH_READLINE"; then + # first, we need to find the include file + AC_MSG_NOTICE(checking for components of readline) + #AC_CHECK_HEADERS(readline/readline.h readline/history.h) + AC_CACHE_VAL(sc_cv_have_readline_h, + [AC_TRY_COMPILE([#include /* FreeBSD needs "FILE *" */ +#include +#include ],[;], + [sc_cv_have_readline_h=yes; READLINE_ROOT=""; ], + [sc_cv_have_readline_h=no + for D in "/sw" "/usr/local" "/opt/freeware" "/usr/sfw"; do + I="$D/include" + i="$I/readline/readline.h" + if test -r "$i"; then + #V_INCL="$V_INCL -I$I/" + CPPFLAGS="$CPPFLAGS -I$I" + AC_MSG_NOTICE(found $i) + sc_cv_have_readline_h=yes; READLINE_ROOT="$D" + break; + fi + done]) + ]) + if test "$sc_cv_have_readline_h" = "yes"; then + AC_DEFINE(HAVE_READLINE_READLINE_H) + AC_DEFINE(HAVE_READLINE_HISTORY_H) + fi + AC_MSG_NOTICE(checked for readline.h... $sc_cv_have_readline_h) +fi # end checking for readline.h +# +if test -n "$WITH_READLINE" -a "$sc_cv_have_readline_h" = yes; then + # next, we search for the readline library (libreadline.*) + AC_MSG_CHECKING(for libreadline) + AC_CACHE_VAL(sc_cv_have_libreadline, + [ LIBS0="$LIBS" + if test -n "$READLINE_ROOT"; then + L="$READLINE_ROOT/lib"; LIBS="$LIBS0 -L$L -lreadline" + else + LIBS="$LIBS0 -lreadline" + fi + AC_TRY_LINK([#include /* FreeBSD needs FILE * */ +#include +#include ], + [readline(NULL)], + [sc_cv_have_libreadline='yes'], + [sc_cv_have_libreadline='no' + LIBS1="$LIBS" + LIBS="$LIBS -lcurses" + AC_TRY_LINK([#include /* FreeBSD needs FILE * */ +#include +#include ], + [readline(NULL)], + [sc_cv_have_libreadline='yes'], + [sc_cv_have_libreadline='no' + LIBS="$LIBS1 -lncurses" # eg for SuSE52 + AC_TRY_LINK([#include /* FreeBSD needs FILE * */ +#include +#include ], + [readline(NULL)], + [sc_cv_have_libreadline='yes'], + [sc_cv_have_libreadline='no']) + ])] + ) + if test "$sc_cv_have_libreadline" != 'yes'; then + LIBS="$LIBS0" + fi + ] +#! missing libcurses dependency; missing freeware places +# # we test if libcurses is available and if it can be used without further libs +# AC_CHECK_LIB(ncurses, main, , AC_CHECK_LIB(curses, main)) # some Linux work with this +# # we test if readline can be used without further libs +# AC_CHECK_LIB(readline, readline) +# # we see if using_history() is already in $LIBS; if not, we try it with curses +# AC_CHECK_FUNC(using_history, , AC_CHECK_LIB(history, using_history,,, -lcurses)) +#fi + ) + if test "$sc_cv_have_libreadline" = 'yes'; then + AC_DEFINE(HAVE_LIBREADLINE) + fi + AC_MSG_RESULT($sc_cv_have_libreadline) +fi +# +if test -n "$WITH_READLINE"; then + if test "$sc_cv_have_readline_h" = "yes" -a "$sc_cv_have_libreadline" = "yes"; then + AC_DEFINE(WITH_READLINE) + else + AC_MSG_WARN([not all components of readline found, disabling it]); + fi +fi + +AC_MSG_CHECKING(whether to include openssl support) +AC_ARG_ENABLE(openssl, [ --disable-openssl disable OpenSSL support], + [ case "$enableval" in + no) AC_MSG_RESULT(no); WITH_OPENSSL= ;; + *) AC_MSG_RESULT(yes); WITH_OPENSSL=1 ;; + esac], + [ AC_MSG_RESULT(yes); WITH_OPENSSL=1 ]) +# +if test -n "$WITH_OPENSSL"; then + AC_MSG_NOTICE(checking for components of OpenSSL) + # first, we need to find the include file + AC_CACHE_VAL(sc_cv_have_openssl_ssl_h, + [AC_TRY_COMPILE([#include ],[;], + [sc_cv_have_openssl_ssl_h=yes; OPENSSL_ROOT=""; ], + [sc_cv_have_openssl_ssl_h=no + for D in "/sw" "/usr/local" "/opt/freeware" "/usr/sfw" "/usr/local/ssl"; 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_ROOT="$D" + break; + fi + done]) + ]) + if test "$sc_cv_have_openssl_ssl_h" = "yes"; then + AC_DEFINE(HAVE_OPENSSL_SSL_H) + fi + AC_MSG_NOTICE(checked for openssl/ssl.h... $sc_cv_have_openssl_ssl_h) +fi # end checking for openssl/ssl.h +# +if test -n "$WITH_OPENSSL" -a "$sc_cv_have_openssl_ssl_h" = 'yes'; then + # next, we search for the openssl library (libssl.*) + # interesting: Linux only requires -lssl, FreeBSD requires -lssl -lcrypto + # Note, version OpenSSL 0.9.7j requires -lcrypto even on Linux. + AC_MSG_CHECKING(for libssl) + AC_CACHE_VAL(sc_cv_have_libssl, + [ LIBS0="$LIBS" + if test -n "$OPENSSL_ROOT"; then + L="$OPENSSL_ROOT/lib"; LIBS="$LIBS -L$L -lssl" + else + LIBS="$LIBS -lssl" + fi + AC_TRY_LINK([#include ], + [SSL_library_init();ERR_error_string()], + [sc_cv_have_libssl='yes'], + [ LIBS="$LIBS -lcrypto" + AC_TRY_LINK([#include ], + [SSL_library_init()], + [sc_cv_have_libssl='yes'], + [sc_cv_have_libssl='no']) + ]) + if test "$sc_cv_have_libssl" != 'yes'; then + LIBS="$LIBS0" + fi + ] + ) + if test "$sc_cv_have_libssl" = 'yes'; then + AC_DEFINE(HAVE_LIBSSL) + fi + AC_MSG_RESULT($sc_cv_have_libssl) +fi +# +# # a possible location for openssl (on Sourceforge/Solaris) +# AC_CHECK_FILE(/usr/local/ssl/lib, LIBS="$LIBS -L/usr/local/ssl/lib/") +# # sometimes on Solaris: +# AC_CHECK_FILE(/pkgs/lib, LIBS="$LIBS -L/pkgs/lib/") +# # for AIX 5.1 with Linux toolbox: +# AC_CHECK_FILE(/opt/freeware/lib, LIBS="$LIBS -L/opt/freeware/lib/") +# +# AC_CHECK_LIB(crypto, main) +# AC_CHECK_LIB(ssl, main) +# +# # MacOSX has openssl includes in another directory +# if test -d /sw/include/; then +# V_INCL="$V_INCL -I/sw/include" +# # and Solaris at sourceforge here: +# elif test -d /usr/local/ssl/include/; then +# V_INCL="$V_INCL -I/usr/local/ssl/include" +# # and AIX 5.1 with Linux toolbox: +# elif test -d /opt/freeware/include; then +# V_INCL="$V_INCL -I/opt/freeware/include" +# fi +#fi +if test -n "$WITH_OPENSSL"; then + if test "$sc_cv_have_openssl_ssl_h" = "yes" -a "$sc_cv_have_libssl" = "yes"; then + AC_DEFINE(WITH_OPENSSL) + else + AC_MSG_WARN([not all components of OpenSSL found, disabling it]); + fi +fi + +# check for fips support +AC_MSG_CHECKING(whether to include openssl fips support) +AC_ARG_ENABLE(fips, [ --disable-fips disable OpenSSL FIPS support], + [ case "$enableval" in + no) AC_MSG_RESULT(no); WITH_FIPS= ;; + *) AC_MSG_RESULT(yes); WITH_FIPS=1 ;; + esac], + [ AC_MSG_RESULT(yes); WITH_FIPS=1 ]) + +if test -n "$WITH_FIPS"; then + if test -n "$WITH_OPENSSL"; then + if test "$sc_cv_have_openssl_ssl_h" != "yes" -o "$sc_cv_have_libssl" != "yes"; then + AC_MSG_WARN([not all components of OpenSSL found, disabling FIPS]); + WITH_FIPS= + fi + else + AC_MSG_WARN([must enable OpenSSL to enable FIPS; use --enable-openssl]); + fi +fi + +if test -n "$WITH_FIPS"; then + AC_MSG_NOTICE(checking for components of OpenSSL FIPS) + # first, we need to find the include file + AC_CACHE_VAL(sc_cv_have_openssl_fips_h, + [AC_TRY_COMPILE([#define OPENSSL_FIPS +#include ],[;], + [sc_cv_have_openssl_fips_h=yes; ], + [sv_cv_have_openssl_fips_h=no + if test -n "$OPENSSL_ROOT"; then + I="$OPENSSL_ROOT/include" + i="$I/openssl/fips.h" + if test -r "$i"; then + AC_MSG_NOTICE(found $i) + sc_cv_have_openssl_fips_h=yes; + fi + fi + ] + )] + ) + if test "$sv_cv_have_openssl_fips_h" = "yes"; then + AC_DEFINE(HAVE_OPENSSL_FIPS_H) + fi + AC_MSG_NOTICE(checked for openssl/fips.h... $sc_cv_have_openssl_ssl_h) +fi + +if test -n "$WITH_FIPS" -a "$sc_cv_have_openssl_fips_h" = 'yes'; then + # check for the libcrypto library with fips support + AC_MSG_CHECKING(for libcrypto with FIPS support) + AC_CACHE_VAL(sc_cv_have_libcrypto, + [ LIBS0="$LIBS" + echo $LIBS | grep -q "\-lcrypto" + if test $? -ne 0; then + if test -n "$OPENSSL_ROOT"; then + L="$OPENSSL_ROOT/lib"; LIBS="$LIBS -L$L -lcrypto" + else + LIBS="$LIBS -lcrypto" + fi + fi + AC_TRY_LINK([#define OPENSSL_FIPS +#include +#include ], + [int res = FIPS_mode_set(1);], + [sc_cv_have_libcrypto='yes'], + [sc_cv_have_libcrypto='no'] + ) + if test "$sc_cv_have_libcrypto" != 'yes'; then + LIBS="$LIBS0" + fi + ] + ) + if test "$sc_cv_have_libcrypto" = 'yes'; then + AC_DEFINE(HAVE_LIBCRYPTO) + fi + AC_MSG_RESULT($sc_cv_have_libcrypto) +fi + +if test -n "$WITH_FIPS"; then + if test "$sc_cv_have_openssl_fips_h" = 'yes' -a "$sc_cv_have_libcrypto" = 'yes'; then + AC_DEFINE(WITH_FIPS) + AC_DEFINE(OPENSSL_FIPS) + else + AC_MSG_WARN([not all components of OpenSSL FIPS found, disabling it]); + fi +fi + +AC_MSG_CHECKING(whether to include tun/tap address support) +AC_ARG_ENABLE(tun, [ --disable-tun disable TUN/TAP support], + [case "$enableval" in + no) AC_MSG_RESULT(no); WITH_TUN= ;; + *) AC_MSG_RESULT(yes); WITH_TUN=1 ;; + esac], + [AC_MSG_RESULT(yes); WITH_TUN=1 ]) + +# +if test -n "$WITH_TUN"; then + if test `uname` != Linux; then + AC_MSG_NOTICE(only on Linux) + else + AC_DEFINE(WITH_TUN) + fi +fi + +AC_MSG_CHECKING(whether to include system call tracing) +AC_ARG_ENABLE(sycls, [ --disable-sycls disable system call tracing], + [case "$enableval" in + no) SYCLS=""; SSLCLS=""; AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_SYCLS) + SYCLS="sycls.c"; SSLCLS="sslcls.c"; AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_SYCLS) + SYCLS="sycls.c"; SSLCLS="sslcls.c"; AC_MSG_RESULT(yes)]) +AC_SUBST(SYCLS) +AC_SUBST(SSLCLS) + +AC_MSG_CHECKING(whether to include file descriptor analyzer) +AC_ARG_ENABLE(filan, [ --disable-filan disable file descriptor analyzer], + [case "$enableval" in + no) FILAN=""; AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_FILAN) FILAN="filan.c"; AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_FILAN) FILAN="filan.c"; AC_MSG_RESULT(yes)]) +AC_SUBST(FILAN) + +AC_MSG_CHECKING(whether to include retry support) +AC_ARG_ENABLE(retry, [ --disable-retry disable retry support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_RETRY) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_RETRY) AC_MSG_RESULT(yes)]) + +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 + debug) AC_DEFINE(WITH_MSGLEVEL,0) AC_MSG_RESULT(debug);; + info) AC_DEFINE(WITH_MSGLEVEL,1) AC_MSG_RESULT(info);; + notice) AC_DEFINE(WITH_MSGLEVEL,2) AC_MSG_RESULT(notice);; + warn) AC_DEFINE(WITH_MSGLEVEL,3) AC_MSG_RESULT(warn);; + error) AC_DEFINE(WITH_MSGLEVEL,4) AC_MSG_RESULT(error);; + fatal) AC_DEFINE(WITH_MSGLEVEL,5) AC_MSG_RESULT(fatal);; + *) AC_DEFINE(WITH_MSGLEVEL,0) AC_MSG_RESULT(debug);; + esac], + [AC_DEFINE(WITH_MSGLEVEL,0) AC_MSG_RESULT(debug)]) + +#AC_SUBST(V_INCL) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_UID_T +AC_TYPE_MODE_T +AC_TYPE_OFF_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_STRUCT_ST_BLKSIZE +AC_STRUCT_ST_BLOCKS +AC_STRUCT_ST_RDEV +AC_HEADER_TIME + +dnl Check for extra realtime library (for Solaris) +AC_CHECK_FUNC(nanosleep, AC_DEFINE(HAVE_NANOSLEEP), AC_CHECK_LIB(rt, nanosleep, [LIBS="-lrt $LIBS"; AC_DEFINE(HAVE_NANOSLEEP)])) +#AC_CHECK_FUNC(nanosleep, , AC_CHECK_LIB(rt, nanosleep)) + +dnl Checks for library functions. +AC_PROG_GCC_TRADITIONAL +AC_FUNC_MEMCMP +AC_TYPE_SIGNAL +AC_FUNC_STRFTIME +AC_CHECK_FUNCS(putenv select poll socket strdup strerror strstr strtod strtol) +AC_CHECK_FUNCS(strtoul uname getpgid getsid getaddrinfo) +AC_CHECK_FUNCS(getipnodebyname setgroups inet_aton memrchr) + +AC_CHECK_FUNCS(grantpt unlockpt ptsname) + + +AC_MSG_CHECKING(for long long) +AC_CACHE_VAL(sc_cv_type_longlong, +[AC_TRY_COMPILE([],[long long s;], +[sc_cv_type_longlong=yes], +[sc_cv_type_longlong=no])]) +if test $sc_cv_type_longlong = yes; then + AC_DEFINE(HAVE_TYPE_LONGLONG) +fi +AC_MSG_RESULT($sc_cv_type_longlong) + +# following builtin macro does not check unistd.h and sys/socket.h where +# socklen_t might be defined +#AC_CHECK_TYPE(socklen_t, int) +# +AC_MSG_CHECKING(for socklen_t) +AC_CACHE_VAL(sc_cv_type_socklen, +[AC_TRY_COMPILE([#include +#include +#include ],[socklen_t s;], +[sc_cv_type_socklen=yes], +[sc_cv_type_socklen=no])]) +if test $sc_cv_type_socklen = yes; then + AC_DEFINE(HAVE_TYPE_SOCKLEN) +fi +AC_MSG_RESULT($sc_cv_type_socklen) + +AC_MSG_CHECKING(for struct stat64) +AC_CACHE_VAL(sc_cv_type_stat64, +[AC_TRY_COMPILE([#include ],[struct stat64 s;], +[sc_cv_type_stat64=yes], +[sc_cv_type_stat64=no])]) +if test $sc_cv_type_stat64 = yes; then + AC_DEFINE(HAVE_TYPE_STAT64) +fi +AC_MSG_RESULT($sc_cv_type_stat64) + +AC_MSG_CHECKING(for off64_t) +AC_CACHE_VAL(sc_cv_type_off64, +[AC_TRY_COMPILE([#include ],[off64_t s;], +[sc_cv_type_off64=yes], +[sc_cv_type_off64=no])]) +if test $sc_cv_type_off64 = yes; then + AC_DEFINE(HAVE_TYPE_OFF64) +fi +AC_MSG_RESULT($sc_cv_type_off64) + +AC_MSG_CHECKING(for sighandler_t) +AC_CACHE_VAL(sc_cv_type_sighandler, +[AC_TRY_COMPILE([#include ],[sighandler_t s;], +[sc_cv_type_sighandler=yes], +[sc_cv_type_sighandler=no])]) +if test $sc_cv_type_sighandler = yes; then + AC_DEFINE(HAVE_TYPE_SIGHANDLER) +fi +AC_MSG_RESULT($sc_cv_type_socklen) + +AC_MSG_CHECKING(for uint8_t) +AC_CACHE_VAL(sc_cv_type_uint8, +[AC_TRY_COMPILE([#include +#if HAVE_STDINT_H +#include +#endif +/* Tru64 has uint8_t etc from netdb.h */ +#if HAVE_NETDB_H +#include +#endif +#include ],[uint8_t s;], +[sc_cv_type_uint8=yes], +[sc_cv_type_uint8=no])]) +if test $sc_cv_type_uint8 = yes; then + AC_DEFINE(HAVE_TYPE_UINT8) +fi +AC_MSG_RESULT($sc_cv_type_uint8) + +AC_MSG_CHECKING(for uint16_t) +AC_CACHE_VAL(sc_cv_type_uint16, +[AC_TRY_COMPILE([#include +#if HAVE_STDINT_H +#include +#endif +/* Tru64 has uint16_t etc from netdb.h */ +#if HAVE_NETDB_H +#include +#endif +#include ],[uint16_t s;], +[sc_cv_type_uint16=yes], +[sc_cv_type_uint16=no])]) +if test $sc_cv_type_uint16 = yes; then + AC_DEFINE(HAVE_TYPE_UINT16) +fi +AC_MSG_RESULT($sc_cv_type_uint16) + +AC_MSG_CHECKING(for uint32_t) +AC_CACHE_VAL(sc_cv_type_uint32, +[AC_TRY_COMPILE([#include +#if HAVE_STDINT_H +#include +#endif +/* Tru64 has uint32_t etc from netdb.h */ +#if HAVE_NETDB_H +#include +#endif +#include ],[uint32_t s;], +[sc_cv_type_uint32=yes], +[sc_cv_type_uint32=no])]) +if test $sc_cv_type_uint32 = yes; then + AC_DEFINE(HAVE_TYPE_UINT32) +fi +AC_MSG_RESULT($sc_cv_type_uint32) + +AC_MSG_CHECKING(for uint64_t) +AC_CACHE_VAL(sc_cv_type_uint64, +[AC_TRY_COMPILE([#include +#if HAVE_STDINT_H +#include +#endif +/* Tru64 has uint32_t etc from netdb.h */ +#if HAVE_NETDB_H +#include +#endif +#include ],[uint64_t s;], +[sc_cv_type_uint64=yes], +[sc_cv_type_uint64=no])]) +if test $sc_cv_type_uint64 = yes; then + AC_DEFINE(HAVE_TYPE_UINT64) +fi +AC_MSG_RESULT($sc_cv_type_uint64) + +### AIX 4.1 needs _XOPEN_EXTENDED_SOURCE for syslog headers, +# but then gets problems with 3rd arg of getsockaddr... +#AC_MSG_CHECKING(for _XOPEN_EXTENDED_SOURCE requirement) +#CFLAGS="-Werror -Wall" +#AC_TRY_COMPILE([#include ], +#[syslog(0," ");], +#[AC_MSG_RESULT(no)], +#[AC_MSG_RESULT(required); AC_DEFINE(_XOPEN_EXTENDED_SOURCE)]) + + +### fds_bits + +AC_MSG_CHECKING(for fdset->fds_bits) +AC_TRY_COMPILE([#include +#if HAVE_SYS_SELECT_H +#include +#endif], +[fd_set s; s.fds_bits[0]=0;], +[AC_MSG_RESULT(yes); AC_DEFINE(HAVE_FDS_BITS)], +[AC_MSG_RESULT(no);]) + +### struct termios .c_ispeed +AC_MSG_CHECKING(for termios.c_ispeed) +AC_CACHE_VAL(sc_cv_termios_ispeed, +[AC_TRY_COMPILE([#include ], +[struct termios t; t.c_ispeed=0;], +[sc_cv_termios_ispeed=yes], +[sc_cv_termios_ispeed=no])]) +if test $sc_cv_termios_ispeed = yes; then + AC_DEFINE(HAVE_TERMIOS_ISPEED) +fi +AC_MSG_RESULT($sc_cv_termios_ispeed) + +if test $sc_cv_termios_ispeed = yes; then +AC_MSG_CHECKING(for offset of c_ispeed in struct termios) +LIBS1="$LIBS"; LIBS="" # avoid libwrap allow_severity undefined +AC_CACHE_VAL(ac_cv_ispeed_offset, + [conftestspeedoff="conftestspeedoff.out" + AC_TRY_RUN([ + #include + #include + #include + #include + main(){ + struct termios t; + FILE *f; + if ((f=fopen("$conftestspeedoff","w"))==NULL){ + fprintf(stderr,"\\"$conftestspeedoff\\": %s\n",strerror(errno)); exit(-1); + } + fprintf(f, "%d", ((char*)&t.c_ispeed-(char*)&t)/sizeof(speed_t)); + exit(0); + } + ], + [ac_cv_ispeed_offset=`cat $conftestspeedoff`], + [ac_cv_ispeed_offset=-1], + [ac_cv_ispeed_offset=-1] #! +)]) +LIBS="$LIBS1" +AC_MSG_RESULT($ac_cv_ispeed_offset) + if test $ac_cv_ispeed_offset -ge 0; then + AC_DEFINE_UNQUOTED(ISPEED_OFFSET, $ac_cv_ispeed_offset) + fi +fi + +# there is another issue with termios: OSR requires "#define _SVID3 ..." +# for reasonable termios support. We check this situation using IMAXBEL +AC_MSG_CHECKING(if _SVID3 is helpful) +AC_CACHE_VAL(ac_cv_svid3, + [AC_TRY_COMPILE([#include ], + [int i=IMAXBEL], + [ac_cv_svid3=no], + [AC_TRY_COMPILE([#define _SVID3 1 +#include ], + [int i=IMAXBEL], + [ac_cv_svid3=yes], + [ac_cv_svid3=no] + )] +)]) +if test $ac_cv_svid3 = yes; then + AC_DEFINE(_SVID3) +fi +AC_MSG_RESULT($ac_cv_svid3) + + +# struct timespec +AC_MSG_CHECKING(for struct timespec) +AC_CACHE_VAL(sc_cv_struct_timespec, +[AC_TRY_COMPILE([#include +#if HAVE_SYS_TIME_H +#include +#endif],[struct timespec s;], +[sc_cv_struct_timespec=yes], +[sc_cv_struct_timespec=no])]) +if test $sc_cv_struct_timespec = yes; then + AC_DEFINE(HAVE_STRUCT_TIMESPEC) +fi +AC_MSG_RESULT($sc_cv_struct_timespec) + + +# struct linger; FreeBSD requires sys/types.h for sys/socket.h +AC_MSG_CHECKING(for struct linger) +AC_CACHE_VAL(sc_cv_struct_linger, +[AC_TRY_COMPILE([#include +#include ],[struct linger s;], +[sc_cv_struct_linger=yes], +[sc_cv_struct_linger=no])]) +if test $sc_cv_struct_linger = yes; then + AC_DEFINE(HAVE_STRUCT_LINGER) +fi +AC_MSG_RESULT($sc_cv_struct_linger) + + +# struct ip_mreq (for multicasting options) +AC_MSG_CHECKING(for struct ip_mreq) +AC_CACHE_VAL(sc_cv_struct_ip_mreq, +[AC_TRY_COMPILE([#include +#include +#include ],[struct ip_mreq s;], +[sc_cv_struct_ip_mreq=yes], +[sc_cv_struct_ip_mreq=no])]) +if test $sc_cv_struct_ip_mreq = yes; then + AC_DEFINE(HAVE_STRUCT_IP_MREQ) +fi +AC_MSG_RESULT($sc_cv_struct_ip_mreq) + +# struct ip_mreqn (for multicasting options) +AC_MSG_CHECKING(for struct ip_mreqn) +AC_CACHE_VAL(sc_cv_struct_ip_mreqn, +[AC_TRY_COMPILE([#include +#include +#include ],[struct ip_mreqn s;], +[sc_cv_struct_ip_mreqn=yes], +[sc_cv_struct_ip_mreqn=no])]) +if test $sc_cv_struct_ip_mreqn = yes; then + AC_DEFINE(HAVE_STRUCT_IP_MREQN) +fi +AC_MSG_RESULT($sc_cv_struct_ip_mreqn) + +# struct ipv6_mreq (for multicasting options) +AC_MSG_CHECKING(for struct ipv6_mreq) +AC_CACHE_VAL(sc_cv_struct_ipv6_mreq, +[AC_TRY_COMPILE([#include +#include +#include ],[struct ipv6_mreq s;], +[sc_cv_struct_ipv6_mreq=yes], +[sc_cv_struct_ipv6_mreq=no])]) +if test $sc_cv_struct_ipv6_mreq = yes; then + AC_DEFINE(HAVE_STRUCT_IPV6_MREQ) +fi +AC_MSG_RESULT($sc_cv_struct_ipv6_mreq) + + +# struct ifreq (for network interfaces) +AC_MSG_CHECKING(for struct ifreq) +AC_CACHE_VAL(sc_cv_struct_ifreq, +[AC_TRY_COMPILE([#include +#include +#include ],[struct ifreq s;], +[sc_cv_struct_ifreq=yes], +[sc_cv_struct_ifreq=no])]) +if test $sc_cv_struct_ifreq = yes; then + AC_DEFINE(HAVE_STRUCT_IFREQ) +fi +AC_MSG_RESULT($sc_cv_struct_ifreq) + +# struct ifreq.ifr_index +# on most systems that have struct ifreq +AC_MSG_CHECKING(for struct ifreq.ifr_index) +AC_CACHE_VAL(sc_cv_struct_ifreq_ifr_index, +[AC_TRY_COMPILE([#include +#include +#include ], +[struct ifreq ir;ir.ifr_index=0;], +[sc_cv_struct_ifreq_ifr_index=yes], +[sc_cv_struct_ifreq_ifr_index=no])]) +if test $sc_cv_struct_ifreq_ifr_index = yes; then + AC_DEFINE(HAVE_STRUCT_IFREQ_IFR_INDEX) +fi +AC_MSG_RESULT($sc_cv_struct_ifreq_ifr_index) + +# struct ifreq.ifr_ifindex +# Linux has ifr_ifindex instead of ifr_index +AC_MSG_CHECKING(for struct ifreq.ifr_ifindex) +AC_CACHE_VAL(sc_cv_struct_ifreq_ifr_ifindex, +[AC_TRY_COMPILE([#include +#include +#include ], +[struct ifreq ir;ir.ifr_ifindex=0;], +[sc_cv_struct_ifreq_ifr_ifindex=yes], +[sc_cv_struct_ifreq_ifr_ifindex=no])]) +if test $sc_cv_struct_ifreq_ifr_ifindex = yes; then + AC_DEFINE(HAVE_STRUCT_IFREQ_IFR_IFINDEX) +fi +AC_MSG_RESULT($sc_cv_struct_ifreq_ifr_ifindex) + + +# some systems have a sa_len field in struct sockaddr and we need to support it +# so we can compare sockaddrs simply with memcmp +AC_MSG_CHECKING(for struct sockaddr.sa_len) +AC_CACHE_VAL(sc_cv_struct_sockaddr_salen, +[AC_TRY_COMPILE([#include +#include ], +[struct sockaddr sa;sa.sa_len=0;], +[sc_cv_struct_sockaddr_salen=yes], +[sc_cv_struct_sockaddr_salen=no])]) +if test $sc_cv_struct_sockaddr_salen = yes; then + AC_DEFINE(HAVE_STRUCT_SOCKADDR_SALEN) +fi +AC_MSG_RESULT($sc_cv_struct_sockaddr_salen) + +### IP6 sockaddr_in6 + +AC_MSG_CHECKING(for component names of sockaddr_in6) +AC_TRY_COMPILE([#include +#include ], +[struct sockaddr_in6 sa6;sa6.sin6_addr.s6_addr[0]=0;], +[AC_MSG_RESULT(s6_addr); + AC_DEFINE(HAVE_IP6_SOCKADDR, 0)], +[AC_TRY_COMPILE([#include +#include ], + [struct sockaddr_in6 sa6;sa6.sin6_addr.u6_addr.u6_addr16[0]=0;], + [AC_MSG_RESULT(u6_addr.u6_addr16); + AC_DEFINE(HAVE_IP6_SOCKADDR, 1)], + [AC_TRY_COMPILE([#include +#include ], + [struct sockaddr_in6 sa6;sa6.sin6_addr.u6_addr16[0]=0;], + [AC_MSG_RESULT(u6_addr16); AC_DEFINE(HAVE_IP6_SOCKADDR, 2)], + [AC_TRY_COMPILE([#include +#include ], + [struct sockaddr_in6 sa6;sa6.sin6_addr.in6_u.u6_addr16[0]=0;], + [AC_MSG_RESULT(in6_u.u6_addr16); + AC_DEFINE(HAVE_IP6_SOCKADDR, 3)], + [AC_TRY_COMPILE([#include +#include ], + [struct sockaddr_in6 sa6;sa6.sin6_addr._S6_un._S6_u32[0]=0;], + [AC_MSG_RESULT(_S6_un._S6_u32); + AC_DEFINE(HAVE_IP6_SOCKADDR, 4)], + [AC_TRY_COMPILE([#include +#include ], + [struct sockaddr_in6 sa6;sa6.sin6_addr.__u6_addr.__u6_addr32[0]=0;], + [AC_MSG_RESULT(__u6_addr.__u6_addr32); + AC_DEFINE(HAVE_IP6_SOCKADDR, 5)], + + [AC_MSG_RESULT([none or unknown])] +)])])])])]) + +dnl Check for struct iovec +AC_MSG_CHECKING(for struct iovec) +AC_CACHE_VAL(sc_cv_struct_iovec, +[AC_TRY_COMPILE([#include ],[struct iovec s;], +[sc_cv_struct_iovec=yes], +[sc_cv_struct_iovec=no])]) +if test $sc_cv_struct_iovec = yes; then + AC_DEFINE(HAVE_STRUCT_IOVEC) +fi +AC_MSG_RESULT($sc_cv_struct_iovec) + +dnl check for msg_control in struct msghdr +AC_MSG_CHECKING(for struct msghdr.msg_control) +AC_CACHE_VAL(sc_cv_struct_msghdr_msgcontrol, +[AC_TRY_COMPILE([#include +#include ], +[struct msghdr s;s.msg_control=0;], +[sc_cv_struct_msghdr_msgcontrol=yes], +[sc_cv_struct_msghdr_msgcontrol=no])]) +if test $sc_cv_struct_msghdr_msgcontrol = yes; then + AC_DEFINE(HAVE_STRUCT_MSGHDR_MSGCONTROL) +fi +AC_MSG_RESULT($sc_cv_struct_msghdr_msgcontrol) + +dnl check for msg_controllen in struct msghdr +AC_MSG_CHECKING(for struct msghdr.msg_controllen) +AC_CACHE_VAL(sc_cv_struct_msghdr_msgcontrollen, +[AC_TRY_COMPILE([#include +#include ], +[struct msghdr s;s.msg_controllen=0;], +[sc_cv_struct_msghdr_msgcontrollen=yes], +[sc_cv_struct_msghdr_msgcontrollen=no])]) +if test $sc_cv_struct_msghdr_msgcontrollen = yes; then + AC_DEFINE(HAVE_STRUCT_MSGHDR_MSGCONTROLLEN) +fi +AC_MSG_RESULT($sc_cv_struct_msghdr_msgcontrollen) + +dnl check for msg_flags in struct msghdr +AC_MSG_CHECKING(for struct msghdr.msgflags) +AC_CACHE_VAL(sc_cv_struct_msghdr_msgflags, +[AC_TRY_COMPILE([#include +#include ], +[struct msghdr s;s.msg_flags=0;], +[sc_cv_struct_msghdr_msgflags=yes], +[sc_cv_struct_msghdr_msgflags=no])]) +if test $sc_cv_struct_msghdr_msgflags = yes; then + AC_DEFINE(HAVE_STRUCT_MSGHDR_MSGFLAGS) +fi +AC_MSG_RESULT($sc_cv_struct_msghdr_msgflags) + +dnl check for ip_hl in struct ip +AC_MSG_CHECKING(for struct ip.ip_hl) +AC_CACHE_VAL(sc_cv_struct_ip_ip_hl, +[AC_TRY_COMPILE([#include +#include +#include +#include ], +[struct ip s;s.ip_hl=0;], +[sc_cv_struct_ip_ip_hl=yes], +[sc_cv_struct_ip_ip_hl=no])]) +if test $sc_cv_struct_ip_ip_hl = yes; then + AC_DEFINE(HAVE_STRUCT_IP_IP_HL) +fi +AC_MSG_RESULT($sc_cv_struct_ip_ip_hl) + + +dnl Library function checks + +dnl Check sigaction() +AC_CHECK_FUNC(sigaction, AC_DEFINE(HAVE_SIGACTION)) + +dnl Check for 64bit versions of system calls +AC_CHECK_FUNC(stat64, AC_DEFINE(HAVE_STAT64)) +AC_CHECK_FUNC(fstat64, AC_DEFINE(HAVE_FSTAT64)) +AC_CHECK_FUNC(lstat64, AC_DEFINE(HAVE_LSTAT64)) +AC_CHECK_FUNC(lseek64, AC_DEFINE(HAVE_LSEEK64)) +AC_CHECK_FUNC(truncate64, AC_DEFINE(HAVE_TRUNCATE64)) +AC_CHECK_FUNC(ftruncate64, AC_DEFINE(HAVE_FTRUNCATE64)) + +AC_CHECK_FUNC(strtoll, AC_DEFINE(HAVE_STRTOLL)) +AC_CHECK_FUNC(hstrerror, AC_DEFINE(HAVE_HSTRERROR)) +AC_CHECK_FUNC(inet_ntop, AC_DEFINE(HAVE_INET_NTOP)) + +#if test "$ac_cv_func_hstrerror" = "yes"; then +# AC_MSG_CHECKING(if _XOPEN_SOURCE_EXTENDED is helpful) +# AC_CACHE_VAL(ac_cv_xopen_source_extended, +# [AC_TRY_COMPILE([#include ], +# [hstrerror()], +# [ac_cv_xopen_source_extended=no], +# [AC_TRY_COMPILE([#define _XOPEN_SOURCE_EXTENDED 1 +## include ], +# [hstrerror()], +# [ac_cv_xopen_source_extended=yes], +# [ac_cv_xopen_source_extended=no] +# )] +# )]) +# if test $ac_cv_xopen_source_extended = yes; then +# AC_DEFINE(_XOPEN_SOURCE_EXTENDED) +# fi +# AC_MSG_RESULT($ac_cv_xopen_source_extended) +#fi + +dnl Search for openpty() +# MacOS +AC_CHECK_FUNC(openpty, AC_DEFINE(HAVE_OPENPTY)) +# AIX +AC_CHECK_LIB(bsd, openpty, + [LIBS="-lbsd $LIBS"; AC_DEFINE(HAVE_OPENPTY)]) +# Linux 2.4 +AC_CHECK_LIB(util, openpty, + [LIBS="-lutil $LIBS"; AC_DEFINE(HAVE_OPENPTY)]) + +dnl Search for flock() +# with Linux it's in libc, with AIX in libbsd +AC_CHECK_FUNC(flock, AC_DEFINE(HAVE_FLOCK), + AC_CHECK_LIB(bsd, flock, [LIBS="-lbsd $LIBS"])) + +dnl Search for setenv() +AC_CHECK_FUNC(setenv, AC_DEFINE(HAVE_SETENV), + AC_CHECK_LIB(isode, setenv, [LIBS="-lisode $LIBS"])) + + +dnl Run time checks + + +AC_MSG_CHECKING(if printf has Z modifier) +AC_CACHE_VAL(ac_cv_have_z_modifier, +[AC_TRY_RUN([ +#include +main(){ +char s[16]; +sprintf(s,"%Zu",1); +exit(strcmp(s,"1")); +}], +[ac_cv_have_z_modifier=yes], +[ac_cv_have_z_modifier=no], +[ac_cv_have_z_modifier=no])]) +if test $ac_cv_have_z_modifier = yes; then + AC_DEFINE(HAVE_FORMAT_Z) +fi +AC_MSG_RESULT($ac_cv_have_z_modifier) + + +dnl find the number of bits we must shift a value to match the given mask +dnl (e.g., mask 0x00f0 requires shifting with 4) +## NOTE: some platforms only need on '\' to escape '"' in string constant +define(AC_SHIFT_OFFSET,[ +AC_CACHE_CHECK(shift offset of $1, $2, +[LIBS1="$LIBS"; LIBS="" # avoid libwrap allow_severity undefined + conftestoffset="conftestoffset.out" + AC_TRY_RUN([ + #include + #include + #include + #include + main(){ + unsigned int i,n=$1; + FILE *f; + if ((f=fopen("$conftestoffset","w"))==NULL){ + fprintf(stderr,"\\"$conftestoffset\\": %s\n",strerror(errno)); exit(-1); + } + if (n==0) {fprintf(stderr,"$1 is 0 (impossible!)\n"); exit(1);} + i=0; while (!(n&1)) { + n>>=1; ++i; } + fprintf(f, "%u", i); + exit(0); + } + ], + [$2=`cat $conftestoffset`], + [$2=-1], + [AC_MSG_RESULT(please determine $1_SHIFT manually)] +) + LIBS="$LIBS1"]) +AC_DEFINE_UNQUOTED($1_SHIFT, ${$2}) +]) + +AC_SHIFT_OFFSET(CRDLY, sc_cv_sys_crdly_shift) +AC_SHIFT_OFFSET(TABDLY, sc_cv_sys_tabdly_shift) +AC_SHIFT_OFFSET(CSIZE, sc_cv_sys_csize_shift) + + +dnl find what physical type (basic C type) is equivalent to the given type. +dnl arg1: include file(s) +dnl arg2: type name +dnl arg3: output variable +dnl arg4: cache variable (might be constructed automatically) +dnl output values: 1..short, 2..unsigned short, 3..int, 4..u-int, +dnl 5..long, 6..u-long; others not yet supported +define(AC_BASIC_TYPE,[ +AC_CACHE_CHECK(for equivalent simple type of $2, $4, +[CFLAGS1="$CFLAGS"; CFLAGS="-Werror -O0 $CFLAGS1" + AC_TRY_COMPILE([$1],[$2 u; short v; &u==&v;], + [$4="1 /* short */"], + [AC_TRY_COMPILE([$1],[$2 u; unsigned short v; &u==&v;], + [$4="2 /* unsigned short */"], + [AC_TRY_COMPILE([$1],[$2 u; int v; &u==&v;], + [$4="3 /* int */"], + [AC_TRY_COMPILE([$1],[$2 u; unsigned int v; &u==&v;], + [$4="4 /* unsigned int */"], + [AC_TRY_COMPILE([$1],[$2 u; long v; &u==&v;], + [$4="5 /* long */"], + [AC_TRY_COMPILE([$1],[$2 u; unsigned long v; &u==&v;], + [$4="6 /* unsigned long */"], + [AC_TRY_COMPILE([$1],[$2 u; long long v; &u==&v;], + [$4="7 /* long long */"], + [AC_TRY_COMPILE([$1],[$2 u; unsigned long long v; &u==&v;], + [$4="8 /* unsigned long long */"], + [$4="0 /* unknown, taking default */" +]) ]) ]) ]) ]) ]) ]) ]) + CFLAGS="$CFLAGS1" ]) +AC_DEFINE_UNQUOTED($3, ${$4}) +]) + +dnl find what physical type (basic C type) describes the given struct or union +dnl component. +dnl arg1: include file(s); must declare the structure type +dnl arg2: struct name (e.g., "struct stat") +dnl arg3: variable or component (e.g., "st_ino") +dnl arg4: output variable, values see AC_BASIC_TYPE +dnl arg5: cache variable (might be constructed automatically) +define(AC_TYPEOF_COMPONENT,[ +AC_CACHE_CHECK(for basic type of $2.$3, $5, +[CFLAGS1="$CFLAGS"; CFLAGS="-Werror -O0 $CFLAGS1" +AC_TRY_COMPILE([$1],[$2 u;short v; &u.$3==&v;], +[$5="1 /* short */"], +[AC_TRY_COMPILE([$1],[$2 u; unsigned short v; &u.$3==&v;], + [$5="2 /* unsigned short */"], + [AC_TRY_COMPILE([$1],[$2 u; int v; &u.$3==&v;], + [$5="3 /* int */"], + [AC_TRY_COMPILE([$1],[$2 u; unsigned int v; &u.$3==&v;], + [$5="4 /* unsigned int */"], + [AC_TRY_COMPILE([$1],[$2 u; long v; &u.$3==&v;], + [$5="5 /* long */"], + [AC_TRY_COMPILE([$1],[$2 u; unsigned long v; &u.$3==&v;], + [$5="6 /* unsigned long */"], + [AC_TRY_COMPILE([$1],[$2 u; long long v; &u.$3==&v;], + [$5="7 /* long long */"], + [AC_TRY_COMPILE([$1],[$2 u; unsigned long long v; &u.$3==&v;], + [$5="8 /* unsigned long long */"], + [$5="0 /* unknown, taking default */" +]) ]) ]) ]) ]) ]) ]) ]) + CFLAGS="$CFLAGS1" ]) +AC_DEFINE_UNQUOTED($4, ${$5}) +]) + +AC_BASIC_TYPE([#include ], size_t, HAVE_BASIC_SIZE_T, sc_cv_type_sizet_basic) +AC_BASIC_TYPE([#include +#include +#include ], mode_t, HAVE_BASIC_MODE_T, sc_cv_type_modet_basic) +AC_BASIC_TYPE([#include +#include ], pid_t, HAVE_BASIC_PID_T, sc_cv_type_pidt_basic) +AC_BASIC_TYPE([#include +#include ], uid_t, HAVE_BASIC_UID_T, sc_cv_type_uidt_basic) +AC_BASIC_TYPE([#include +#include ], gid_t, HAVE_BASIC_GID_T, sc_cv_type_gidt_basic) + +AC_BASIC_TYPE([#include ], time_t, HAVE_BASIC_TIME_T, + sc_cv_type_timet_basic) + +# this is questionable, might fail on some systems +AC_BASIC_TYPE([#include +#include +#include ], socklen_t, HAVE_BASIC_SOCKLEN_T, + sc_cv_type_socklent_basic) + +AC_BASIC_TYPE([#include +#include ], off64_t, HAVE_BASIC_OFF64_T, sc_cv_type_off64_basic) + +# oh god, __dev_t in Linux 2.4 is struct{int[2];}, not handled here yet. +AC_TYPEOF_COMPONENT([#include ], struct stat, st_dev, HAVE_TYPEOF_ST_DEV, sc_cv_type_stat_stdev_basic) +AC_TYPEOF_COMPONENT([#include ], struct stat, st_ino, HAVE_TYPEOF_ST_INO, sc_cv_type_stat_stino_basic) +AC_TYPEOF_COMPONENT([#include ], struct stat, st_nlink, HAVE_TYPEOF_ST_NLINK, sc_cv_type_stat_stnlink_basic) +AC_TYPEOF_COMPONENT([#include ], struct stat, st_size, HAVE_TYPEOF_ST_SIZE, sc_cv_type_stat_stsize_basic) +AC_TYPEOF_COMPONENT([#include ], struct stat, st_blksize, HAVE_TYPEOF_ST_BLKSIZE, sc_cv_type_stat_stblksize_basic) +AC_TYPEOF_COMPONENT([#include ], struct stat, st_blocks, HAVE_TYPEOF_ST_BLOCKS, sc_cv_type_stat_stblocks_basic) +# +if test "$ac_cv_func_stat64" = yes; then +AC_TYPEOF_COMPONENT([#include ], struct stat64, st_dev, HAVE_TYPEOF_ST64_DEV, sc_cv_type_stat64_stdev_basic) +AC_TYPEOF_COMPONENT([#include ], struct stat64, st_ino, HAVE_TYPEOF_ST64_INO, sc_cv_type_stat64_stino_basic) +AC_TYPEOF_COMPONENT([#include ], struct stat64, st_nlink, HAVE_TYPEOF_ST64_NLINK, sc_cv_type_stat64_stnlink_basic) +AC_TYPEOF_COMPONENT([#include ], struct stat64, st_size, HAVE_TYPEOF_ST64_SIZE, sc_cv_type_stat64_stsize_basic) +AC_TYPEOF_COMPONENT([#include ], struct stat64, st_blksize, HAVE_TYPEOF_ST64_BLKSIZE, sc_cv_type_stat64_stblksize_basic) +AC_TYPEOF_COMPONENT([#include ], struct stat64, st_blocks, HAVE_TYPEOF_ST64_BLOCKS, sc_cv_type_stat64_stblocks_basic) +fi + +AC_TYPEOF_COMPONENT([#include ], struct timeval, tv_usec, HAVE_TYPEOF_STRUCT_TIMEVAL_TVUSEC, sc_cv_type_struct_timeval_tvusec) + +AC_TYPEOF_COMPONENT([#include +#include +#include ], +struct rlimit, rlim_max, HAVE_TYPEOF_RLIM_MAX, sc_cv_type_rlimit_rlimmax_basic) + +### snprintf, vsnprintf + + +AC_MSG_CHECKING(for /dev/ptmx) +if test -c /dev/ptmx; then + AC_DEFINE(HAVE_DEV_PTMX, 1) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) + AC_MSG_CHECKING(for /dev/ptc) + if test -c /dev/ptc; then + AC_DEFINE(HAVE_DEV_PTC) + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi +fi + +AC_MSG_CHECKING(for /proc) +if test -d /proc; then + AC_DEFINE(HAVE_PROC_DIR, 1) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +AC_MSG_CHECKING(for /proc/*/fd) +if test -d /proc/$$/fd; then + AC_DEFINE(HAVE_PROC_DIR_FD, 1) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +dnl "tcpd" "tcpwrappers" +# on some platforms, raw linking with libwrap fails because allow_severity and +# deny_severity are not explicitely defined. Thus we put the libwrap part to +# the end +AC_MSG_CHECKING(whether to include libwrap support) +AC_ARG_ENABLE(libwrap, [ --disable-libwrap disable libwrap support], + [ case "$enableval" in + no) AC_MSG_RESULT(no); WITH_LIBWRAP= ;; + *) AC_MSG_RESULT(yes); WITH_LIBWRAP=1 ;; + esac], + [ AC_MSG_RESULT(yes); WITH_LIBWRAP=1 ]) +# +# check if we find the components of libwrap ("tcpd" "tcpwrappers") +if test -n "$WITH_LIBWRAP"; then + AC_MSG_NOTICE(checking for components of libwrap) + # first, we need to find the include file + AC_CACHE_VAL(sc_cv_have_tcpd_h, + [AC_TRY_COMPILE([#include +#include ],[;], + [sc_cv_have_tcpd_h=yes; LIBWRAP_ROOT=""], + [sc_cv_have_tcpd_h=no + for D in "/sw" "/usr/local" "/opt/freeware" "/usr/sfw"; do + I="$D/include" + i="$I/tcpd.h" + if test -r "$i"; then + #V_INCL="$V_INCL -I$I" + CPPFLAGS="$CPPFLAGS -I$I" + AC_MSG_NOTICE(found $i) + sc_cv_have_tcpd_h=yes; LIBWRAP_ROOT="$D" + break; + fi + done]) + ]) + if test "$sc_cv_have_tcpd_h" = "yes"; then + AC_DEFINE(HAVE_TCPD_H) + fi + AC_MSG_NOTICE(checked for tcpd.h... $sc_cv_have_tcpd_h) +fi # end checking for tcpd.h +if test -n "$WITH_LIBWRAP" -a "$sc_cv_have_tcpd_h" = yes; then + # next, we search for the wrap library (libwrap.*) + AC_MSG_CHECKING(for libwrap) + AC_CACHE_VAL(sc_cv_have_libwrap, + [ LIBS0="$LIBS" + if test -n "$LIBWRAP_ROOT"; then + L="$LIBWRAP_ROOT/lib"; LIBS="-L$L -lwrap $LIBS" + else + LIBS="-lwrap $LIBS" + fi + AC_TRY_LINK([#include +#include +int allow_severity,deny_severity;],[hosts_access(0)], + [sc_cv_have_libwrap='yes'], + [sc_cv_have_libwrap='no' + LIBS="$LIBS -lnsl" # RedHat73 + AC_TRY_LINK([#include +#include +int allow_severity,deny_severity;],[hosts_access(0)], + [sc_cv_have_libwrap='yes'], + [sc_cv_have_libwrap='no']) + ] + ) + if test "$sc_cv_have_libwrap" != 'yes'; then + LIBS="$LIBS0" + fi + ] + ) + if test "$sc_cv_have_libwrap" = 'yes'; then + AC_DEFINE(HAVE_LIBWRAP) + fi + AC_MSG_RESULT($sc_cv_have_libwrap) +fi +# +if test -n "$WITH_LIBWRAP"; then + if test "$sc_cv_have_tcpd_h" = "yes" -a "$sc_cv_have_libwrap" = "yes"; then + AC_DEFINE(WITH_LIBWRAP) + else + AC_MSG_WARN([not all components of tcp wrappers found, disabling it]); + fi +fi + +# check of hosts_allow_table +if test -n "$WITH_LIBWRAP"; then + AC_MSG_CHECKING(checking for hosts_allow_table) + AC_CACHE_VAL(sc_cv_have_hosts_allow_table, + [AC_TRY_COMPILE([#include +#include ],[hosts_allow_table="";], + [sc_cv_have_hosts_allow_table=yes], + [sc_cv_have_hosts_allow_table=no])]) + if test $sc_cv_have_hosts_allow_table = yes; then + AC_DEFINE(HAVE_HOSTS_ALLOW_TABLE) + fi + AC_MSG_RESULT($sc_cv_have_hosts_allow_table) +fi # test -n "$WITH_LIBWRAP" + + +if test "$GCC" = yes; then + CFLAGS="$CFLAGS" +fi + +# FIPS support requires compiling with fipsld. +# fipsld requires the FIPSLD_CC variable to be set to the original CC. +# This check must be done after all other checks that require compiling +# so that fipsld is not used by the configure script itself. +if test -n "$WITH_FIPS"; then + if test "$sc_cv_have_openssl_fips_h" = 'yes' -a "$sc_cv_have_libcrypto" = 'yes'; then + FIPSLD_CC=$CC + if test "${FIPSLD+set}" != set ; then + FIPSLD=fipsld + fi + CC="FIPSLD_CC=$CC $FIPSLD" + fi +fi +AC_SUBST(FIPSLD_CC) + +AC_OUTPUT(Makefile) diff --git a/daemon.sh b/daemon.sh new file mode 100755 index 0000000..fd7aa14 --- /dev/null +++ b/daemon.sh @@ -0,0 +1,34 @@ +#! /bin/sh +# $Id: daemon.sh,v 1.4 2001/10/29 09:52:47 gerhard Exp $ +# Copyright Gerhard Rieger 2001 +# Published under the GNU General Public License V.2, see file COPYING + +# This script assumes that you create group daemon1 and user daemon1 before. +# they need only the right to exist (no login etc.) + +# Note: this pid file mechanism is not robust! + +# You will adapt these variables +USER=daemon1 +GROUP=daemon1 +INIF=fwnonsec.domain.org +OUTIF=fwsec.domain.org +TARGET=w3.intra.domain.org +INPORT=80 +DSTPORT=80 +# +INOPTS="fork,setgid=$GROUP,setuid=$USER" +OUTOPTS= +PIDFILE=/var/run/socat-$INPORT.pid +OPTS="-d -d -lm" # notice to stderr, then to syslog +SOCAT=/usr/local/bin/socat + +if [ "$1" = "start" -o -z "$1" ]; then + + $SOCAT $OPTS tcp-l:$INPORT,bind=$INIF,$INOPTS tcp:$TARGET:$DSTPORT,bind=$OUTIF,$OUTOPTS $PIDFILE + +elif [ "$1" = "stop" ]; then + + /bin/kill $(/bin/cat $PIDFILE) +fi diff --git a/dalan.c b/dalan.c new file mode 100644 index 0000000..2313ee2 --- /dev/null +++ b/dalan.c @@ -0,0 +1,224 @@ +/* $Id: dalan.c,v 1.8 2004/06/20 21:49:11 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2004 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* idea of a low level data description language. currently only a most + primitive subset exists. */ + +#include +#include +#include +#include "dalan.h" + +/* test structure to find maximal alignment */ +static struct { + char a; + long double b; +} maxalign; + +/* test structure to find minimal alignment */ +static struct { + char a; + char b; +} minalign; + +/* test union to find kind of byte ordering */ +static union { + char a[2]; + short b; +} byteorder = { "01" }; + +struct dalan_opts_s dalan_opts = { + sizeof(int), + sizeof(short), + sizeof(long), + sizeof(char), + sizeof(float), + sizeof(double) +} ; + +/* fill the dalan_opts structure with machine dependent defaults values. */ +static void _dalan_dflts(struct dalan_opts_s *dlo) { + dlo->c_int = sizeof(int); + dlo->c_short = sizeof(short); + dlo->c_long = sizeof(long); + dlo->c_char = sizeof(char); + dlo->c_float = sizeof(float); + dlo->c_double = sizeof(double); + dlo->maxalign = (char *)&maxalign.b-&maxalign.a; + dlo->minalign = &minalign.b-&minalign.a; + dlo->byteorder = (byteorder.b!=7711); +} + +/* allocate a new dalan_opts structure, fills it with machine dependent + defaults values, and returns the pointer. */ +struct dalan_opts_s *dalan_props(void) { + struct dalan_opts_s *dlo; + dlo = malloc(sizeof(struct dalan_opts_s)); + if (dlo == NULL) { + return NULL; + } + _dalan_dflts(dlo); + return dlo; +} + +void dalan_init(void) { + _dalan_dflts(&dalan_opts); +} + +/* read data description from line, write result to data; do not write + so much data that *p exceeds n ! + return 0 on success, + -1 if the data was cut due to n limit, + 1 if a syntax error occurred + *p is a global data counter; especially it must be used when calculating + alignment. On successful return from the function *p must be actual! +*/ +int dalan(const char *line, char *data, size_t *p, size_t n) { + int align, mask, i, x; + size_t p1 = *p; + char c; + + fputs(line, stderr); fputc('\n', stderr); + while (c = *line++) { + switch (c) { + case ' ': + case '\t': + case '\r': + case '\n': + break; + case ',': + align = 2; + while (*line == ',') { + align <<= 1; + ++line; + } + mask = align - 1; /* create the bitmask */ + i = (align - (p1 & mask)) & mask; + while (i && p1= n) { *p = p1; return -1; } + data[p1++] = c; + continue; + } + if (c == '"') + break; + } + break; + case '\'': + switch (c = *line++) { + case '\0': fputs("unterminated character\n", stderr); + return 1; + case '\'': fputs("error in character\n", stderr); + return 1; + case '\\': + if (!(c = *line++)) { + fputs("continuation line not implemented\n", stderr); + return 1; + } + switch (c) { + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'f': c = '\f'; break; + case 'b': c = '\b'; break; + case 'a': c = '\a'; break; +#if 0 + case 'e': c = '\e'; break; +#else + case 'e': c = '\033'; break; +#endif + } + /* PASSTHROUGH */ + default: + if (p1 >= n) { *p = p1; return -1; } + data[p1++] = c; + break; + } + if (*line != '\'') { + fputs("error in character termination\n", stderr); + *p = p1; return 1; + } + ++line; + break; +#if LATER + case '0': + c = *line++; + if (c == 'x') { + /* hexadecimal */ ; + } else if (isdigit(c&0xff)) { + /* octal */ + } else { + /* it was only 0 */ + } + break; +#endif /* LATER */ + case 'x': + /* expecting hex data, must be an even number of digits!! */ + while (true) { + c = *line; + if (isdigit(c&0xff)) { + x = (c-'0') << 4; + } else if (isxdigit(c&0xff)) { + x = ((c&0x07) + 9) << 4; + } else + break; + ++line; + c = *line; + if (isdigit(c&0xff)) { + x |= (c-'0'); + } else if (isxdigit(c&0xff)) { + x |= (c&0x07) + 9; + } else { + fputs("odd number of hexadecimal digits\n", stderr); + *p = p1; return 1; + } + ++line; + if (p1 >= n) { *p = p1; return -1; } + data[p1++] = x; + } + break; + case 'A': case 'a': + case 'C': case 'c': + default: fprintf(stderr, "syntax error in \"%s\"\n", line-1); + return 1; + } + } + *p = p1; return 0; +} diff --git a/dalan.h b/dalan.h new file mode 100644 index 0000000..5d8c44e --- /dev/null +++ b/dalan.h @@ -0,0 +1,30 @@ +/* $Id: dalan.h,v 1.3 2001/06/30 14:02:39 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __dalan_h_included +#define __dalan_h_included 1 + +#include "mytypes.h" + +/* machine properties and command line options */ +struct dalan_opts_s { + int c_int; /* natural int size / C int size */ + int c_short; /* C short size */ + int c_long; /* C long size */ + int c_char; /* C char size */ + int c_float; /* C float size */ + int c_double; /* C double size */ + int maxalign; /* maximal alignment (double after char) */ + int minalign; /* minimal alignment (char after char) */ + int byteorder; /* 0: Motorola, network, big endian; 1: Intel, little + endian */ +} ; + +extern struct dalan_opts_s dalan_opts; + +extern void dalan_init(void); +extern struct dalan_opts_s *dalan_props(void); +extern int dalan(const char *line, char *data, size_t *p, size_t n); + +#endif /* !defined(__dalan_h_included) */ diff --git a/doc/dest-unreach.css b/doc/dest-unreach.css new file mode 100644 index 0000000..b5dd82f --- /dev/null +++ b/doc/dest-unreach.css @@ -0,0 +1,15 @@ + + +dest-unreach.org stylesheet + + + + + diff --git a/doc/socat-multicast.html b/doc/socat-multicast.html new file mode 100644 index 0000000..fc31f7b --- /dev/null +++ b/doc/socat-multicast.html @@ -0,0 +1,340 @@ + + +IP Multicasting with Socat + + + + + +

IP Multicasting with Socat

+ +

Introduction

+

+Multicasting (and broadcasting which is also discussed in this article) +provides a means to direct a single packet to more than one host. Special +addresses are defined for this purpose and are handled specially by network +adapters, networking hardware, and IP stacks. +

+

+IPv4 specifications provide broadcasting and multicasting; IPv6 provides +multicasting but replaces broadcasting by special multicast modes. UNIX domain +sockets do not know broadcasting or multicasting. +

+

+The following examples use UDP/IPv4 only. However, they can easily be +adapted for raw IPv4 sockets. IPv6 multicasting has not yet been successfully +used with socat; please contact the author if you have positive experiences or +ideas that go beyond IPV6_ADD_MEMBERSHIP. +

+

+All multicast examples presented in this document use multicast address +224.1.0.1; it can be replaced by any valid IPv4 multicast address (except +all-systems). +

+

+We assume a local network with address 192.168.10.0 and mask 255.255.255.0; an +eventual "client" has 192.168.10.1, example "server" and example peer have +192.168.10.2 in all examples. Change these addresses and mask to your own +requirements. +

+

+All the following examples work bidirectionally except when otherwise noticed. +For "clients" we just use STDIO, and for "servers" we use EXEC:hostname which +ingores its input but shows us which host the reply comes from. Replace these +addresses with what is appropriate for you (e.g. shell script +invokations). Port 6666 can be replaced with any other port (but for ports < +1024 root privilege might be required). +

+

+Different kinds of broadcast addresses exist: 255.255.255.255 is local network +only; for the IPv4 network 192.168.10.0/24 the "official" broadcast address +is 192.168.10.255; the network address 192.168.10.0 is also interpreted as +broadcast by some hosts. The two latter forms are routed by gateways. In the +following examples we only use broadcast address 192.168.10.255. +

+ +

Example 1: Multicast client and servers

+ +

This example builds something like a "supervisor" or "client" that +communicates with a set of "servers". The supervisor may send packets to the +multicast address, and the servers may send response packets. Note that the +servers would also respond to other clients' requests.

+ +

Multicast server:

+ + +socat UDP4-RECVFROM:6666,ip-add-membership=224.1.0.1:192.168.10.2,fork EXEC:hostname + +

+This command receives multicast packets addressed to 224.1.0.1 and forks a +child process for each. The child processes may each send one or more reply +packets back to the particular sender. 192.168.10.2 means the address of the +interface where multicasts should be received. +Run this command on a number of hosts, and they will all respond in +parallel.

+ +

Multicast client:

+ + +socat STDIO UDP4-DATAGRAM:224.1.0.1:6666,range=192.168.10.0/24 + +

+This process transfers data from stdin to the multicast address, and transfers +packets received from the local network to stdout. It does not matter in which +direction the first data is passed. +A packet from the network is accepted by the IP stack for our socket if: +

    +
  • it is an incoming UDP/IPv4 packet
  • +
  • its target port matches the local port assigned to the socket (6666)
  • +
  • its target address matches one of the hosts local addresses or the any-host +multicast address
  • +
+Of these packets, socat handles only those matching the following criteria: +
    +
  • the source address is within the given range
  • +
  • the source port is 6666
  • +
+

+ + +

Example 2: Broadcast client and servers

+ +

Broadcast server:

+ + +socat UDP4-RECVFROM:6666,broadcast,fork EXEC:hostname + +

+This command receives packets addressed to a local broadcast address and forks +a child process for each. The child processes may each send one or more reply +packets back to the particular sender. +Run this command on a number of hosts, and they will all respond in +parallel.

+ +

Broadcast client:

+ + +socat STDIO UDP4-DATAGRAM:192.168.10.255:6666,broadcast,range=192.168.10.0/24 + +

+This process transfers data from stdin to the broadcast address, and transfers +packets received from the local network to stdout. It does not matter in which +direction the first data is passed. +A packet from the network is accepted by the IP stack for our socket if: +

    +
  • it is an incoming UDP/IPv4 packet
  • +
  • its target port matches the local port assigned to the socket (6666)
  • +
  • its target address matches one of the hosts local addresses or the any-host +multicast address, or a local broadcast address
  • +
+Of these packets, socat handles only those matching the following criteria: +
    +
  • the source address is within the given range
  • +
  • the source port is 6666
  • +
+

+

The broadcast option is only required for sending or receiving +local broadcasts.

+ +

Example 3: Multicast peers

+ +

It is possible to combine multicast sender and receiver in one socat +address. This allows to start processes on different hosts on the local network +that will communicate symmetrically, so each process can send messages that are +received by all the other ones.

+ + +socat STDIO UDP4-DATAGRAM:224.1.0.1:6666,bind=:6666,range=192.168.10.0/24,ip-add-membership=224.1.0.1:192.168.10.2 + +

+This command is valid for host 192.168.10.2; adapt this address to the +particular interface addresses of the hosts. +

+

+Starting this process opens a socket on port 6666 that will receive packets +directed to multicast address 224.1.0.1. Only packets with matching source +address and source port 6666 will be handled though. When this process sends +data to the network the packets will be addressed to 224.1.0.1:6666 and have a +source address of 192.168.10.2:6666, matching the accept criteria of the peers +on the local network. +

+ +

Note: this command receives the packets it just has sent; add option +ip-multicast-loop=0 if this in undesired.

+ +

Example 4: Broadcast peers

+ +

Just as with multicast, it is possible to combine broadcast sender and +receiver in one socat address.

+ + +socat STDIO UDP4-DATAGRAM:255.255.255.255:6666,bind=:6666,range=192.168.10.0/24,broadcast + +

+Starting this process opens a socket on port 6666 that will receive packets +directed to a local broadcast addresses. Only packets with matching source +address and source port 6666 will be handled though. When this process sends +data to the network the packets will be addressed to 255.255.255.255:6666 and +have a source address of 192.168.10.2:6666, matching the accept criteria of +the peers on the local network. +

+ +

Note: this command receives the packets it just has sent; there does not +seem to exist a simple way to prevent this.

+ + +

Troubleshooting

+ +

+If you do not get an error message during operation, but the packets do not +reach the target processes, use tcpdump to see if the packets have the +correct source and destination addresses and ports, and if they leave and enter +the hosts as expected. +

+

+The following subsections discuss some typical sources of trouble. +

+ +

IP filters

+

+If you do not succeed in receiving multicast or broadcast packets, check if +iptables are activated on the receiving or sending host. They might be +configured to disallow this traffic. +

+ +

Do not bind()

+

+When using multicast communications, you should not bind the sockets to a +specific IP address. It seems that the (Linux) IP stack compares the +destination address with the bind address, not taking care of the multicast +property of the incoming packet. +

+ +

Routing

+

+When you receive an error like:

+
... E sendto(3, 0x80c2e44, 4, +0, AF=2 224.1.0.1:6666, 16): Network is unreachable
+

you have a routing problem. The (Linux) IP stack seems to handle multicast +addresses just like unicast addresses when determining their route (interface and gateway).

+

+For the same reason, multicast packets will probably leave your host on the +interface with the default route.

+

+Set a multicast/broadcast route with the following command:

+ +route add -net 224.0.0.0/3 gw 192.168.10.2 + + +

ALL-SYSTEMS multicast address

+

+224.0.0.1 is the all-systems multicast address: all +datagram sockets appear to be automatically member of this group on all +interfaces. This membership cannot be dropped on Linux. +

+ + +

(In)Security

+ +

When you use the above examples you should understand that all datagram +sockets without exception accept packets that are directly addressed to them; +the multi- and broadcast receiving features are just extensions to the normal +functionality. socat has no way to find out if an incoming packet is addressed +to a unicast, multicast or broadcast address. Please contact the author if you +know how the target address can be determined.

+ +

Authentication or encryption are not available.

+ +

It is very easy to fake the source address of UDP (or raw IP) packets. You +should understand whether your network is protected from address spoofing +attacks.

+ +

Broadcast and multicast traffic can trivially be received by any +host on the local network.

+ + +

History

+ +Starting with version 1.5.0, socat provides a set of address types that +allow various operations on datagram oriented sockets: +
+
SENDTO
send packets to a remote socket and receive packet from this +remote socket only
+
RECV
receive all packets that arrive on the local socket, but do +not reply
+
RECVFROM
receive all packets that arrive on the local socket, and +reply using child processes
+
+ +

+These modes already enable several different client/server oriented operations. +Moreover, the SENDTO addresses can send to multicast and broadcast addresses +(the latter requires the broadcast option though). RECV and RECVFROM +also would accept packets addressed to a local broadcast address (with option +broadcast) or the all-systems multicast address. +

+ +

+These address types had, however, two major caveats: +

    +
  • Missing control of multicast group membership in the RECV and RECVFROM +addresses
  • +
  • The SENDTO address would never accept a reply to a broadcast or multicast +addressed packet because the source address of incoming replies would not match +the target address of the sent packet. +
+

+ +

New Features in socat 1.6.0

+ +

+socat version 1.6.0 addresses these problems and provides a new more generic +datagram address type (*-DATAGRAM) and the new address option IP-ADD-MEMBERSHIP. +

+ +

+Please note that the new features could not be successfully tested on IPv6; +these sections thus apply to IPv4 only. +

+ +

This document was last modified in March 2007.

+ +

More info about socat datagrams

+ +

Links regarding this tutorial

+address udp4-datagram
+address udp4-recvfrom
+option range
+option broadcast
+option ip-add-membership
+option fork
+option bind
+ +

Other datagram addresses

+address udp4-recv: pure datagram receiver
+address udp4-sendto: communicate +with one peer address
+address udp4-listen: pseudo stream server
+address udp4-connect: pseudo stream client
+ +

Related socat option groups

+IP options
+socket options
+file descriptor options
+range options
+child process options
+ + +

References

+socat home page
+socat man page
+multicasting on Wikipedia
+broadcasting on Wikipedia
+ +

+Copyright: Gerhard Rieger 2007
+License: GNU Free Documentation License (FDL) +

+ + + diff --git a/doc/socat-openssltunnel.html b/doc/socat-openssltunnel.html new file mode 100644 index 0000000..e2ce0fc --- /dev/null +++ b/doc/socat-openssltunnel.html @@ -0,0 +1,192 @@ + + +Securing Traffic Between two Socat Instances Using SSL + + + + + +

Securing Traffic Between two Socat Instances Using SSL

+ +

Introduction

+

+When you want to connect two socat processes running on different machines and +feel that you need to protect the connection against unauthorized access, +sniffing, data manipulation etc., you might want to encrypt the communications. +

+

+For this purpose socat integrates the OpenSSL library and provides SSL client +and server features. +

+

+SSL is a complex protocol that provides much more features than required for +protecting a single connection; in this document we present only a simple +scenario that provides just the basic security requirements. +

+ + +

Configuring OpenSSL in socat

+

+This section shows how the SSL addresses can be configured in socat. +In this docu we only use self signed certificates for the sake of simplicity. +

+

We assume that the server host is called server.domain.org and the +server process uses port 4433. To keep it simple, we use a very simple server +funtionality that just echos data (echo), and stdio on the +client.

+

Generate a server certificate

+ +

Perform the following steps on a trusted host where OpenSSL is +installed. It might as well be the client or server host themselves.

+

Prepare a basename for the files related to the server certificate:

+FILENAME=server + +

Generate a public/private key pair:

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

Generate a self signed certificate:

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

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

+

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

+cat $FILENAME.key $FILENAME.crt >$FILENAME.pem + +

The files that contain the private key should be kept secret, thus adapt +their permissions:

+chmod 600 $FILENAME.key $FILENAME.pem + +

Now bring the file server.pem to the SSL server, e.g. to directory +$HOME/etc/, using a secure channel like USB memory stick or SSH. Keep +tight permissions on the file even on the target host, and remove all other +instances of server.key and server.pem. +

+

Copy the trust certificate server.crt to the SSL client host, e.g. to directory +$HOME/etc/; a secure channel is not required here, and the permissions +are not critical. +

+ +

Generate a client certificate

+

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

+FILENAME=client + +

Repeat the procedure for certificate generation described above. +Copy client.pem to the SSL client, and client.crt to the +server.

+ +

OpenSSL Server

+ +

Instead of using a tcp-listen (tcp-l) address, we use openssl-listen (ssl-l) +for the server, cert=... tells the program to the file containing its +ceritificate and private key, and cafile=... points to the file +containing the certificate of the peer; we trust clients only if they can proof +that they have the related private key (OpenSSL handles this for us):

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

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

+ +

OpenSSL Client

+

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

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

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

+ +

TCP/IP version 6

+ +

If the communication is to go over IPv6, the above described commands have +to be adapted; ip6name.domain.org is assumed to resolve to the IPv6 +address of the server:

+

Server:

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

Client:

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

Troubleshooting

+ +

Test OpenSSL Integration

+

+If you get error messages like this:

+
... E unknown device/address "openssl-listen"
+

your socat executable probably does not have the OpenSSL library linked in. +Check socat's compile time configuration with the following command:

+socat -V |grep SSL +

Positive output: +#define WITH_OPENSSL 1
+Negative output: +#undef WITH_OPENSSL
+

+

+In the latter case, make sure you have OpenSSL and its development package +(include files) installed, and check the run of the configure script. +

+ + +

History

+

+A first OpenSSL client was implemented in socat 1.2.0; it did not support +client certificates and could not verify server certificates. It was rather +considered as a tool for probing typical SSL secured Internet services. +

+

+From version 1.4.0 on, socat provided experimental support for SSL client and +SSL server, implemented using the OpenSSL libraries. Only TCP/IPv4 transport +was supported. With both SSL client and server, trust certificates for checking +the peers authentication, and certificates for authentication could be +specified. This allowed for non interactive secure connection establishing. +The features were considered experimental; like most Internet sites, socat +server did not require the client to present a certificate per default, but the +client required a server certificate. + +

+

+DSA certificate support is implemented since version 1.4.2. +

+

+Socat version 1.5.0 extended SSL to TCP/IPv6 transports. +

+

+With socat version 1.6.0, the SSL server per default requires the client to +present a trusted certificate. socat's OpenSSL implementation still does not +check the contents of a certificate like host name or host address. +

+ +

This document was last modified in March 2007.

+ +

More info about socat OpenSSL

+ +

Links regarding this tutorial

+address openssl-connect
+address openssl-listen
+option cert
+option cafile
+ +

More socat options for OpenSSL addresses

+OpenSSL options
+TCP options
+IP options
+socket options
+file descriptor options
+retry options
+

For openssl-listen only:

+listen options
+child options
+range options
+ +

References

+socat home page
+socat man page
+OpenSSL home page
+stunnel home page
+secure sockets layer on Wikipedia
+ +

+Copyright: Gerhard Rieger 2007
+License: GNU Free Documentation License (FDL) +

+ + + diff --git a/doc/socat-tun.html b/doc/socat-tun.html new file mode 100644 index 0000000..0df6bca --- /dev/null +++ b/doc/socat-tun.html @@ -0,0 +1,165 @@ + + +Building TUN based virtual networks with socat + + + + + +

Building TUN based virtual networks with socat

+ +

Introduction

+

+Some operating systems allow the generation of virtual network interfaces that +do not connect to a wire but to a process that simulates the network. Often +these devices are called TUN or TAP. +

+

+socat provides an address type that creates a TUN device on Linux; the other +socat address can be any type; it transfer the "wire" data as desired. +

+

+This document shows how a simple virtual network can be created between +two hosts that may be far (many network hops) apart. On both hosts a socat +instance is started that connects to the other host using TCP and creates a TUN +device. See socat-openssltunnel.html for +a guide on securing the connection using SSL. +

+

+The following IP addresses are used in the example; replace them in the +following commands with the requirements of your situation:

+ + + + + + +
hostaddressmask
physical "server" address1.2.3.4n/a
physical "client" address223.2.3.4n/a
TUN on "server"192.168.255.1255.255.255.0
TUN on "client"192.168.255.2255.255.255.0
+

The TCP connection uses port 11443.

+ +

On "default" Linux installations, creating TUN/TAP devices might require +root privilege.

+ + +

Generate TUN devices with socat

+

In this section two instances of socat are used to generate TUN devices on +different hosts and connect the "wire" sides, providing a simple virtual +network. +

+

+We distinguish server and client only with respect to the connection between +the two socat instances; the TUN interfaces both have the same quality. +

+ +

TUN Server

+ +socat -d -d TCP-LISTEN:11443,reuseaddr TUN:192.168.255.1/24,up +

After starting this command, socat will wait for a connection and then +create a TUN pseudo network device with address 192.168.255.1; the bit number +specifies the mask of the network that is pretended to be connected on this +interface.

+ +

TUN Client

+socat TCP:1.2.3.4:11443 TUN:192.168.255.2/24,up +

This command should establish a connection to the server and create the TUN +device on the client.

+ +

Seeing it work

+ +

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

+ +

TCP/IP version 6

+ +

IPv6 as transport should work just like any TCP/IPv6 connection.

+ +

Creation of an IPv6 virtual interface is not directly possible, but you can +generate an IPv4 interface as described above, and add IPv6 addresses using +the ifconfig command. + +

Troubleshooting

+ +

Test TUN integration

+

+If you get error messages like this:

+
... E unknown device/address "tun"
+

your socat executable probably does not provide TUN/TAP support. Potential +reasons: you are not on Linux or are using an older version of socat. +

+ +

Missing kernel support

+

An error message like:

+
... E open("/dev/net/tun", 02, 0666): No such file or directory
+

indicates that your kernel does not have TUN/TAP support compiled +in. Rebuild your kernel with the appropriate configuration (probably under +Device driver / Network device support / Network device / Universal TUN/TAP). +

+ +

TUN cloning device permissions

+

An error message like:

+
... E open("/dev/net/tun", 02, 0666): Permission denied
+

indicates that you do not have permission to read or write the TUN cloning +device. Check its permission and ownership.

+ +

Interface down

+

If no error occurs but the pings do not work check if the network devices +have been created:

+ifconfig tun0 +

The output should look like:

+
+tun0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
+          inet addr:192.168.255.1  P-t-P:192.168.255.1  Mask:255.255.255.0
+          UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  Metric:1
+          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
+          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
+          collisions:0 txqueuelen:500 
+          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)
+
+

Check the "UP" keyword; you forget the "up" option in the socat command if + it is missing.

+

Check if the correct IP address and network mask are displayed.

+ +

Routing

+

+netstat -an |fgrep 192.168.255 +

The output should look like:

+
+192.168.255.0   0.0.0.0         255.255.255.0   U         0 0          0 tun0
+
+ +

Other problems

+

Another reason for failure might be iptables.

+

Run socat with options -d -d -d, this will show every data transfer +between the two processes. Each ping probe should cause a forth and a back +transfer.

+ +

History

+

+Linux TUN/TAP support was added to socat in version 1.6.0.

+ +

This document was last modified in March 2007.

+ +

More info about socat TUN/TAP support

+ +

Links regarding this tutorial

+socat address tun
+ +

socat options for TUN/TAP addresses

+TUN/TAP options
+ +

References

+socat home page
+socat man page
+OpenVPN home page
+TUN/TAP on Wikipedia
+ +

+Copyright: Gerhard Rieger 2007
+License: GNU Free Documentation License (FDL) +

+ + + diff --git a/doc/socat.1 b/doc/socat.1 new file mode 100644 index 0000000..3be5004 --- /dev/null +++ b/doc/socat.1 @@ -0,0 +1,2877 @@ +.TH "socat" "1" "March 2007" "socat" "" +.PP +.PP +.SH "NAME" +socat \- Multipurpose relay (SOcket CAT) +.PP +.SH "SYNOPSIS" +\f(CWsocat [options]
\fP +.br +\f(CWsocat -V\fP +.br +\f(CWsocat -h[h[h]] | -?[?[?]]\fP +.br +\f(CWfilan\fP +.br +\f(CWprocan\fP +.PP +.SH "DESCRIPTION" +.PP +\fBSocat\fP is a command line based utility that establishes two bidirectional byte +streams and transfers data between them\&. Because the streams can be constructed +from a large set of different types of data sinks and sources +(see address types), and because lots of +address options may be applied to the streams, socat can +be used for many different purposes\&. +It might be one of the tools that one `has already needed\'\&. +.PP +\fBFilan\fP is a utility that prints information about its active file +descriptors to stdout\&. It has been written for debugging \fBsocat\fP, but might be +useful for other purposes too\&. Use the -h option to find more infos\&. +.PP +\fBProcan\fP is a utility that prints information about process parameters to +stdout\&. It has been written to better understand +some UNIX process properties and for debugging \fBsocat\fP, but might be +useful for other purposes too\&. +.PP +The life cycle of a \fBsocat\fP instance typically consists of four phases\&. +.PP +In the \fIinit\fP phase, the command line options are parsed and logging is +initialized\&. +.PP +During the \fIopen\fP phase, \fBsocat\fP opens the first address and afterwards the +second address\&. These steps are usually blocking; thus, especially for complex address types like socks, +connection requests or authentication dialogs must be completed before the next +step is started\&. +.PP +In the \fItransfer\fP phase, \fBsocat\fP watches both streams\' read and write file +descriptors via \f(CWselect()\fP, and, when data is available on one side \fIand\fP +can be written to the other side, socat reads it, performs newline +character conversions if required, and writes the data to the write file +descriptor of the other stream, then continues waiting for more data in both +directions\&. +.PP +When one of the streams effectively reaches EOF, the \fIclosing\fP phase +begins\&. \fBSocat\fP transfers the EOF condition to the other stream, +i\&.e\&. tries to shutdown only its write stream, giving it a chance to +terminate gracefully\&. For a defined time \fBsocat\fP continues to transfer data in +the other direction, but then closes all remaining channels and terminates\&. +.PP +.SH "OPTIONS" +.PP +\fBSocat\fP provides some command line options that modify the behaviour of the +program\&. They have nothing to do with so called +address options that are used as parts of address specifications\&. +.PP +.IP "\fB\f(CW-V\fP\fP" +Print version and available feature information to stdout, and exit\&. +.IP "\fB\f(CW-h | -?\fP\fP" +Print a help text to stdout describing command line options and available address +types, and exit\&. +.IP "\fB\f(CW-hh | -??\fP\fP" +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 +implementation\&. +.IP "\fB\f(CW-hhh | -???\fP\fP" +Like -hh, plus a list of all available address option names\&. +.IP "\fB\f(CW-d\fP\fP" +Without this option, only fatal and error messages are generated; applying +this option also prints warning messages\&. See DIAGNOSTICS +for more information\&. +.IP "\fB\f(CW-d -d\fP\fP" +Prints fatal, error, warning, and notice messages\&. +.IP "\fB\f(CW-d -d -d\fP\fP" +Prints fatal, error, warning, notice, and info messages\&. +.IP "\fB\f(CW-d -d -d -d\fP\fP" +Prints fatal, error, warning, notice, info, and debug +messages\&. +.IP "\fB\f(CW-D\fP\fP" +Logs information about file descriptors before starting the transfer phase\&. +.IP "\fB\f(CW-ly[]\fP\fP" +Writes messages to syslog instead of stderr; severity as defined with -d +option\&. With optional , the syslog type can +be selected, default is "daemon"\&. +.IP "\fB\f(CW-lf\fP\fP\f(CW \fP" +Writes messages to [filename] instead of +stderr\&. +.IP "\fB\f(CW-ls\fP\fP" +Writes messages to stderr (this is the default)\&. +.IP "\fB\f(CW-lp\fP\fP\f(CW\fP" +Overrides the program name printed in error messages\&. +.IP "\fB\f(CW-lu\fP\fP" +Extends the timestamp of error messages to microsecond resolution\&. Does not +work when logging to syslog\&. +.IP "\fB\f(CW-lm[]\fP\fP" +Mixed log mode\&. During startup messages are printed to stderr; when \fBsocat\fP +starts the transfer phase loop or daemon mode (i\&.e\&. after opening all +streams and before starting data transfer, or, with listening sockets with +fork option, before the first accept call), it switches logging to syslog\&. +With optional , the syslog type can be +selected, default is "daemon"\&. +.IP "\fB\f(CW-lh\fP\fP" +Adds hostname to log messages\&. Uses the value from environment variable +HOSTNAME or the value retrieved with \f(CWuname()\fP if HOSTNAME is not set\&. +.IP "\fB\f(CW-v\fP\fP" +Writes the transferred data not only to their target streams, but also to +stderr\&. The output format is text with some conversions for readability, and +prefixed with "> " or "< " indicating flow directions\&. +.IP "\fB\f(CW-x\fP\fP" +Writes the transferred data not only to their target streams, but also to +stderr\&. The output format is hexadecimal, prefixed with "> " or "< " +indicating flow directions\&. Can be combined with \f(CW-v\fP\&. +.IP "\fB\f(CW-b\fP\fP\f(CW\fP" +Sets the data transfer block [size_t]\&. +At most bytes are transferred per step\&. Default is 8192 bytes\&. +.IP "\fB\f(CW-s\fP\fP" +By default, \fBsocat\fP terminates when an error occurred to prevent the process +from running when some option could not be applied\&. With this +option, \fBsocat\fP is sloppy with errors and tries to continue\&. Even with this +option, socat will exit on fatals, and will abort connection attempts when +security checks failed\&. +.IP "\fB\f(CW-t\fP\fP\f(CW\fP" +When one channel has reached EOF, the write part of the other channel is shut +down\&. Then, \fBsocat\fP waits [timeval] seconds +before terminating\&. Default is 0\&.5 seconds\&. This timeout only applies to +addresses where write and read part can be closed independently\&. When during +the timeout intervall the read part gives EOF, socat terminates without +awaiting the timeout\&. +.IP "\fB\f(CW-T\fP\fP\f(CW\fP" +Total inactivity timeout: when socat is already in the transfer loop and +nothing has happened for [timeval] seconds +(no data arrived, no interrupt occurred\&.\&.\&.) then it terminates\&. +Useful with protocols like UDP that cannot transfer EOF\&. +.IP "\fB\f(CW-u\fP\fP" +Uses unidirectional mode\&. The first address is only used for reading, and the +second address is only used for writing (example)\&. +.IP "\fB\f(CW-U\fP\fP" +Uses unidirectional mode in reverse direction\&. The first address is only +used for writing, and the second address is only used for reading\&. +.IP "\fB\f(CW-g\fP\fP" +During address option parsing, don\'t check if the option is considered +useful in the given address environment\&. Use it if you want to force, e\&.g\&., +appliance of a socket option to a serial device\&. +.IP "\fB\f(CW-L\fP\fP\f(CW\fP" +If lockfile exists, exits with error\&. If lockfile does not exist, creates it +and continues, unlinks lockfile on exit\&. +.IP "\fB\f(CW-W\fP\fP\f(CW\fP" +If lockfile exists, waits until it disappears\&. When lockfile does not exist, +creates it and continues, unlinks lockfile on exit\&. +.IP "\fB\f(CW-4\fP\fP" +Use IP version 4 in case that the addresses do not implicitly or explicitly +specify a version; this is the default\&. +.IP "\fB\f(CW-6\fP\fP" +Use IP version 6 in case that the addresses do not implicitly or explicitly +specify a version\&. +.PP +.SH "ADDRESS SPECIFICATIONS" +.PP +With the address command line arguments, the user gives \fBsocat\fP instructions and +the necessary information for establishing the byte streams\&. +.PP +An address specification usually consists of an address type +keyword, zero or more required address parameters separated by \':\' from the keyword and +from each +other, and zero or more address options separated by \',\'\&. +.PP +The keyword specifies the address type (e\&.g\&., TCP4, OPEN, EXEC)\&. For some +keywords there exist synonyms (\'-\' for STDIO, TCP for TCP4)\&. Keywords are case +insensitive\&. +For a few special address types, the keyword may be omitted: +Address specifications starting with a number are assumed to be FD (raw file +descriptor) addresses; +if a \'/\' is found before the first \':\' or \',\', GOPEN (generic file open) is +assumed\&. +.PP +The required number and type of address parameters depend on the address +type\&. E\&.g\&., TCP4 requires a server specification (name or address), and a port +specification (number or service name)\&. +.PP +Zero or more address options may be given with each address\&. They influence the +address in some ways\&. +Options consist of an option keyword or an option keyword and a value, +separated by \'=\'\&. Option keywords are case insensitive\&. +For filtering the options that are useful with an address +type, each option is member of one option group\&. For +each address type there is a set of option groups allowed\&. Only options +belonging to one of these address groups may be used (except with option -g)\&. +.PP +Address specifications following the above schema are also called \fIsingle\fP +address specifications\&. +Two single addresses can be combined with "!!" to form a \fIdual\fP type +address for one channel\&. Here, the first address is used by \fBsocat\fP for reading +data, and the +second address for writing data\&. There is no way to specify an option only once +for being applied to both single addresses\&. +.PP +Usually, addresses are opened in read/write +mode\&. When an address is part of a dual address specification, or when +option -u or -U is used, an address might be +used only for reading or for writing\&. Considering this is important with some +address types\&. +.PP +With socat version 1\&.5\&.0 and higher, the lexical analysis tries to handle +quotes and parenthesis meaningfully and allows escaping of special characters\&. +If one of the characters ( { [ \' is found, the corresponding closing +character - ) } ] \' - is looked for; they may also be nested\&. Within these +constructs, socats special characters and strings : , !! are not handled +specially\&. All those characters and strings can be escaped with \e or within "" +.PP +.SH "ADDRESS TYPES" +.PP +This section describes the available address types with their keywords, +parameters, and semantics\&. +.PP +.IP "\fB\f(CWCREATE:\fP\fP" +Opens with \f(CWcreat()\fP and uses the file +descriptor for writing\&. +This address type requires write-only context, because a file opened with +\f(CWcreat\fP cannot be read from\&. + must be a valid existing or not existing path\&. +If is a named pipe, \f(CWcreat()\fP might block; +if refers to a socket, this is an error\&. +.br +Option groups: FD,REG,NAMED +.br +Useful options: +mode, +user, +group, +unlink-early, +unlink-late, +append +.br +See also: OPEN, GOPEN +.IP "\fB\f(CWEXEC:\fP\fP" +Forks a sub process that establishes communication with its parent process +and invokes the specified program with \f(CWexecvp()\fP\&. + is a simple command +with arguments separated by single spaces\&. If the program name +contains a \'/\', the part after the last \'/\' is taken as ARGV[0]\&. If the +program name is a relative +path, the \f(CWexecvp()\fP semantics for finding the program via +\f(CW$PATH\fP +apply\&. After successful program start, \fBsocat\fP writes data to stdin of the +process and reads from its stdout using a UNIX domain socket generated by +\f(CWsocketpair()\fP per default\&. (example) +.br +Option groups: FD,SOCKET,EXEC,FORK,TERMIOS +.br +Useful options: +path, +fdin, +fdout, +chroot, +su, +su-d, +nofork, +pty, +stderr, +ctty, +setsid, +pipes, +login, +sigint, +sigquit +.br +See also: SYSTEM +.IP "\fB\f(CWFD:\fP\fP" +Uses the file descriptor \&. It must already exist as +valid UN*X file descriptor\&. +.br +Option groups: FD (TERMIOS,REG,SOCKET) +.br +See also: +STDIO, +STDIN, +STDOUT, +STDERR +.IP "\fB\f(CWGOPEN:\fP\fP" +(Generic open) This address type tries to handle any file system entry +except directories usefully\&. may be a +relative or absolute path\&. If it already exists, its type is checked\&. +In case of a UNIX domain socket, \fBsocat\fP connects; if connecting fails, +\fBsocat\fP assumes a datagram socket and uses \f(CWsendto()\fP calls\&. +If the entry is not a socket, \fBsocat\fP opens it applying the \f(CWO_APPEND\fP +flag\&. +If it does not exist, it is opened with flag +\f(CWO_CREAT\fP as a regular file (example)\&. +.br +Option groups: FD,REG,SOCKET,NAMED,OPEN +.br +See also: +OPEN, +CREATE, +UNIX-CONNECT +.IP +.IP "\fB\f(CWIP-SENDTO::\fP\fP" +Opens a raw IP socket\&. Depending on host specification or option pf, IP procotol version +4 or 6 is used\&. It uses to send packets +to [IP address] and receives packets from +host, ignores packets from other hosts\&. +Protocol 255 uses the raw socket with the IP header being part of the +data\&. +.br +Option groups: FD,SOCKET,IP4,IP6 +.br +Useful options: +pf, +ttl +See also: +IP4-SENDTO, +IP6-SENDTO, +IP-RECVFROM, +IP-RECV, +UDP-SENDTO +UNIX-SENDTO +.IP "\fB\f(CWIP4-SENDTO::\fP\fP" +Like IP-SENDTO, but always uses IPv4\&. +.br +Option groups: FD,SOCKET,IP4 +.br +.IP "\fB\f(CWIP6-SENDTO::\fP\fP" +Like IP-SENDTO, but always uses IPv6\&. +.br +Option groups: FD,SOCKET,IP6 +.br +.IP +.IP "\fB\f(CWIP-DATAGRAM:
:\fP\fP" +Sends outgoing data to the specified address which may in particular be a +broadcast or multicast address\&. Packets arriving on the local socket are +checked if their source addresses match +eventual RANGE or TCPWRAP +options\&. This address type can for example be used for implementing +symmetric or asymmetric broadcast or multicast communications\&. +.br +Option groups: FD, SOCKET, +IP4, IP6, RANGE +.br +Useful options: +range, +tcpwrap, +broadcast, +ip-multicast-loop, +ip-multicast-ttl, +ip-multicast-if, +ip-add-membership, +ttl, +tos, +bind, +pf +.br +See also: +IP4-DATAGRAM, +IP6-DATAGRAM, +IP-SENDTO, +IP-RECVFROM, +IP-RECV, +UDP-DATAGRAM +.IP "\fB\f(CWIP4-DATAGRAM::\fP\fP" +Like IP-DATAGRAM, but always uses IPv4\&. +(example) +.br +Option groups: FD, SOCKET, +IP4, RANGE +.br +.IP "\fB\f(CWIP6-DATAGRAM::\fP\fP" +Like IP-DATAGRAM, but always uses IPv6\&. Please +note that IPv6 does not know broadcasts\&. +.br +Option groups: FD, SOCKET, +IP6, RANGE +.br +.IP +.IP "\fB\f(CWIP-RECVFROM:\fP\fP" +Opens a raw IP socket of \&. Depending on option pf, IP procotol version +4 or 6 is used\&. It receives one packet from an unspecified peer and may send one or more answer packets to that peer\&. +This mode is particularly useful with fork option where each arriving packet - from arbitrary peers - is handled by its own sub process\&. +This allows a behaviour similar to typical UDP based servers like ntpd or named\&. +This address works well with IP-SENDTO address peers (see above)\&. +Protocol 255 uses the raw socket with the IP header being part of the +data\&. +.br +Option groups: FD,SOCKET,IP4,IP6,CHILD,RANGE +.br +Useful options: +pf, +fork, +range, +ttl, +broadcast +.br +See also: +IP4-RECVFROM, +IP6-RECVFROM, +IP-SENDTO, +IP-RECV, +UDP-RECVFROM, +UNIX-RECVFROM +.IP "\fB\f(CWIP4-RECVFROM:\fP\fP" +Like IP-RECVFROM, but always uses IPv4\&. +.br +Option groups: FD,SOCKET,IP4,CHILD,RANGE +.br +.IP "\fB\f(CWIP6-RECVFROM:\fP\fP" +Like IP-RECVFROM, but always uses IPv6\&. +.br +Option groups: FD,SOCKET,IP6,CHILD,RANGE +.br +.IP +.IP "\fB\f(CWIP-RECV:\fP\fP" +Opens a raw IP socket of \&. Depending on option pf, IP procotol version +4 or 6 is used\&. It receives packets from multiple unspecified peers and merges the data\&. +No replies are possible\&. +It can be, e\&.g\&., addressed by socat IP-SENDTO address peers\&. +Protocol 255 uses the raw socket with the IP header being part of the +data\&. +.br +Option groups: FD,SOCKET,IP4,IP6,RANGE +.br +Useful options: +pf, +range +.br +See also: +IP4-RECV, +IP6-RECV, +IP-SENDTO, +IP-RECVFROM, +UDP-RECV, +UNIX-RECV +.IP "\fB\f(CWIP4-RECV:\fP\fP" +Like IP-RECV, but always uses IPv4\&. +.br +Option groups: FD,SOCKET,IP4,RANGE +.br +.IP "\fB\f(CWIP6-RECV:\fP\fP" +Like IP-RECV, but always uses IPv6\&. +.br +Option groups: FD,SOCKET,IP6,RANGE +.br +.IP +.IP "\fB\f(CWOPEN:\fP\fP" +Opens using the \f(CWopen()\fP system call +(example)\&. +This operation fails on UNIX domain sockets\&. +.br +Note: This address type is rarly useful in bidirectional mode\&. +.br +Option groups: FD,REG,NAMED,OPEN +.br +Useful options: +creat, +excl, +noatime, +nofollow, +append, +rdonly, +wronly, +lock, +readbytes, +ignoreeof +.br +See also: +CREATE, +GOPEN, +UNIX-CONNECT +.IP "\fB\f(CWOPENSSL::\fP\fP" +Tries to establish a SSL connection to [TCP +service] on + [IP address] using TCP/IP version 4 or 6 +depending on address specification, name resolution, or option +pf\&. +.br +NOTE: The server certificate is only checked for validity against +cafile or capath, +but not for match with the server\'s name or its IP address! +.br +Option groups: FD,SOCKET,IP4,IP6,TCP,OPENSSL,RETRY +.br +Useful options: +cipher, +method, +verify, +cafile, +capath, +certificate, +bind, +pf, +connect-timeout, +sourceport, +retry +.br +See also: +OPENSSL-LISTEN, +TCP +.IP "\fB\f(CWOPENSSL-LISTEN:\fP\fP" +Listens on tcp [TCP service]\&. +The IP version is 4 or the one specified with +pf\&. When a +connection is accepted, this address behaves as SSL server\&. +.br +Note: You probably want to use the certificate option with this address\&. +.br +NOTE: The client certificate is only checked for validity against +cafile or capath, +but not for match with the client\'s name or its IP address! +.br +Option groups: FD,SOCKET,IP4,IP6,TCP,LISTEN,OPENSSL,CHILD,RANGE,RETRY +.br +Useful options: +pf, +cipher, +method, +verify, +cafile, +capath, +certificate, +fork, +bind, +range, +tcpwrap, +su, +reuseaddr, +retry +.br +See also: +OPENSSL, +TCP +.IP "\fB\f(CWPIPE:\fP\fP" +If already exists, it is opened\&. +If is does not exist, a named pipe is created and opened\&. Beginning with +socat version 1\&.4\&.3, the named pipe is removed when the address is closed +(but see option unlink-close +.br +Note: When a pipe is used for both reading and writing, it works +as echo service\&. +.br +Note: When a pipe is used for both reading and writing, and socat tries +to write more bytes than the pipe can buffer (Linux 2\&.4: 2048 bytes), socat +might block\&. Consider using socat option, e\&.g\&., \f(CW-b 2048\fP +.br +Option groups: FD,NAMED,OPEN +.br +Useful options: +rdonly, +nonblock, +group, +user, +mode, +unlink-early +.br +See also: unnamed pipe +.IP "\fB\f(CWPIPE\fP\fP" +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 data\&. +.br +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 +option \f(CW-b 2048\fP +.br +Option groups: FD +.br +See also: named pipe +.IP "\fB\f(CWPROXY:::\fP\fP" +Connects to an HTTP proxy server on port 8080 using TCP/IP version 4 or 6 +depending on address specification, name resolution, or option +pf, and sends a CONNECT +request for hostname:port\&. If the proxy grants access and succeeds to +connect to the target, data transfer between socat and the target can +start\&. Note that the traffic need not be HTTP but can be an arbitrary +protocol\&. +.br +Option groups: FD,SOCKET,IP4,IP6,TCP,HTTP,RETRY +.br +Useful options: +proxyport, +ignorecr, +proxyauth, +resolve, +crnl, +bind, +connect-timeout, +mss, +sourceport, +retry +.br +See also: SOCKS, TCP +.IP "\fB\f(CWPTY\fP\fP" +Generates a pseudo terminal (pty) and uses its master side\&. Another process +may open the pty\'s slave side using it like a serial line or terminal\&. +(example)\&. If +both the ptmx and the openpty mechanisms are available, ptmx is used +(POSIX)\&. +.br +Option groups: FD,NAMED,PTY,TERMIOS +.br +Useful options: +link, +openpty, +wait-slave, +mode, +user, +group +.br +See also: +UNIX-LISTEN, +PIPE, +EXEC, SYSTEM +.IP "\fB\f(CWREADLINE\fP\fP" +Uses GNU readline and history on stdio to allow editing and reusing input +lines (example)\&. This requires the GNU readline and +history libraries\&. Note that stdio should be a (pseudo) terminal device, +otherwise readline does not seem to work\&. +.br +Option groups: FD,READLINE,TERMIOS +.br +Useful options: +history, +noecho +.br +See also: +STDIO +.IP "\fB\f(CWSOCKS4:::\fP\fP" +Connects via [IP address] +to [IPv4 address] +on [TCP service], +using socks version 4 protocol over IP version 4 or 6 depending on address specification, name resolution, or option +pf (example)\&. +.br +Option groups: FD,SOCKET,IP4,IP6,TCP,SOCKS4,RETRY +.br +Useful options: +socksuser, +socksport, +sourceport, +pf, +retry +.br +See also: +SOCKS4A, +PROXY, +TCP +.IP "\fB\f(CWSOCKS4A:::\fP\fP" +like SOCKS4, but uses socks protocol version 4a, thus +leaving host name resolution to the socks server\&. +.br +Option groups: FD,SOCKET,IP4,IP6,TCP,SOCKS4,RETRY +.br +.IP "\fB\f(CWSTDERR\fP\fP" +Uses file descriptor 2\&. +.br +Option groups: FD (TERMIOS,REG,SOCKET) +.br +See also: FD +.IP "\fB\f(CWSTDIN\fP\fP" +Uses file descriptor 0\&. +.br +Option groups: FD (TERMIOS,REG,SOCKET) +.br +Useful options: +readbytes +.br +See also: FD +.IP "\fB\f(CWSTDIO\fP\fP" +Uses file descriptor 0 for reading, and 1 for writing\&. +.br +Option groups: FD (TERMIOS,REG,SOCKET) +.br +Useful options: +readbytes +.br +See also: FD +.IP "\fB\f(CWSTDOUT\fP\fP" +Uses file descriptor 1\&. +.br +Option groups: FD (TERMIOS,REG,SOCKET) +.br +See also: FD +.IP "\fB\f(CWSYSTEM:\fP\fP" +Forks a sub process that establishes communication with its parent process +and invokes the specified program with \f(CWsystem()\fP\&. Please note that + [string] must +not contain \',\' or "!!", and that shell meta characters may have to be +protected\&. +After successful program start, \fBsocat\fP writes data to stdin of the +process and reads from its stdout\&. +.br +Option groups: FD,SOCKET,EXEC,FORK,TERMIOS +.br +Useful options: +path, +fdin, +fdout, +chroot, +su, +su-d, +nofork, +pty, +stderr, +ctty, +setsid, +pipes, +sigint, +sigquit +.br +See also: EXEC +.IP "\fB\f(CWTCP::\fP\fP" +Connects to [TCP service] on + [IP address] using TCP/IP version 4 or 6 +depending on address specification, name resolution, or option +pf\&. +.br +Option groups: FD,SOCKET,IP4,IP6,TCP,RETRY +.br +Useful options: +crnl, +bind, +pf, +connect-timeout, +tos, +mtudiscover, +mss, +nodelay, +nonblock, +sourceport, +retry, +readbytes +.br +See also: +TCP4, +TCP6, +TCP-LISTEN, +UDP, +UNIX-CONNECT +.IP "\fB\f(CWTCP4::\fP\fP" +Like TCP, but only supports IPv4 protocol (example)\&. +.br +Option groups: FD,SOCKET,IP4,TCP,RETRY +.br +.IP "\fB\f(CWTCP6::\fP\fP" +Like TCP, but only supports IPv6 protocol\&. +.br +Option groups: FD,SOCKET,IP6,TCP,RETRY +.br +.IP "\fB\f(CWTCP-LISTEN:\fP\fP" +Listens on [TCP service] and accepts a +TCP/IP connection\&. The IP version is 4 or the one specified with +pf\&. +Note that opening +this address usually blocks until a client connects\&. +.br +Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP4,IP6,TCP,RETRY +.br +Useful options: +crnl, +fork, +bind, +range, +tcpwrap, +pf, +backlog, +mss, +su, +reuseaddr, +retry, +retry +.br +See also: +TCP4-LISTEN, +TCP6-LISTEN, +UDP-LISTEN, +UNIX-LISTEN, +OPENSSL-LISTEN +.IP "\fB\f(CWTCP4-LISTEN:\fP\fP" +Like TCP-LISTEN, but only supports IPv4 +protocol (example)\&. +.br +Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP4,TCP,RETRY +.br +.IP "\fB\f(CWTCP6-LISTEN:\fP\fP" +Like TCP-LISTEN, but only supports IPv6 +protocol\&. +.br +Additional useful option: +ipv6only +.br +Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP6,TCP,RETRY +.br +.IP "\fB\f(CWTUN:/\fP\fP" +Creates a Linux TUN/TAP device and assignes to it the address and netmask +defined by the parameters\&. The resulting network interface is ready for use +by other processes; socat serves its "wire side"\&. This address requires read +and write access to the tunnel cloning device, usually \f(CW/dev/net/tun\fP\&. +.br +Option groups: FD,NAMED,OPEN,TUN +.br +Useful options: +iff-up, +tun-device, +tun-name, +tun-type, +iff-no-pi +.br +See also: +ip-recv +.IP "\fB\f(CWUDP::\fP\fP" +Connects to [UDP service] on + [IP address] using UDP/IP version 4 or 6 +depending on address specification, name resolution, or option +pf\&. +.br +Please note that, +due to UDP protocol properties, no real connection is established; data has +to be sent for `connecting\' to the server, and no end-of-file condition can +be transported\&. +.br +Option groups: FD,SOCKET,IP4,IP6 +.br +Useful options: +ttl, +tos, +bind, +sourceport, +pf +.br +See also: +UDP4, +UDP6, +UDP-LISTEN, +TCP, +IP +.IP "\fB\f(CWUDP4::\fP\fP" +Like UDP, but only supports IPv4 protocol\&. +.br +Option groups: FD,SOCKET,IP4 +.br +.IP "\fB\f(CWUDP6::\fP\fP" +Like UDP, but only supports IPv6 protocol\&. +.br +Option groups: FD,SOCKET,IP6 +.br +.IP "\fB\f(CWUDP-DATAGRAM:
:\fP\fP" +Sends outgoing data to the specified address which may in particular be a +broadcast or multicast address\&. Packets arriving on the local socket are +checked for the correct remote port and if their source addresses match +eventual RANGE or TCPWRAP +options\&. This address type can for example be used for implementing +symmetric or asymmetric broadcast or multicast communications\&. +.br +Option groups: FD,SOCKET,IP4,IP6,RANGE +.br +Useful options: +range, +tcpwrap, +broadcast, +ip-multicast-loop, +ip-multicast-ttl, +ip-multicast-if, +ip-add-membership, +ttl, +tos, +bind, +sourceport, +pf +.br +See also: +UDP4-DATAGRAM, +UDP6-DATAGRAM, +UDP-SENDTO, +UDP-RECVFROM, +UDP-RECV, +UDP-CONNECT, +UDP-LISTEN, +IP-DATAGRAM +.IP "\fB\f(CWUDP4-DATAGRAM:
:\fP\fP" +Like UDP-DATAGRAM, but only supports IPv4 +protocol (example1, +example2)\&. +.br +Option groups: FD, SOCKET, +IP4, RANGE +.IP "\fB\f(CWUDP6-DATAGRAM:
:\fP\fP" +Like UDP-DATAGRAM, but only supports IPv6 +protocol\&. +.br +Option groups: FD,SOCKET, +IP6,RANGE +.IP "\fB\f(CWUDP-LISTEN:\fP\fP" +Waits for a UDP/IP packet arriving on +[UDP service] and `connects\' back to sender\&. +The accepted IP version is 4 or the one specified with option +pf\&. +Please note that, +due to UDP protocol properties, no real connection is established; data has +to arrive from the peer first, and no end-of-file condition can be +transported\&. Note that opening +this address usually blocks until a client connects\&. +.br +Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP4,IP6 +.br +Useful options: +fork, +bind, +range, +pf +.br +See also: +UDP, +UDP4-LISTEN, +UDP6-LISTEN, +TCP-LISTEN +.IP "\fB\f(CWUDP4-LISTEN:\fP\fP" +Like UDP-LISTEN, but only support IPv4 +protocol\&. +.br +Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP4 +.br +.IP "\fB\f(CWUDP6-LISTEN:\fP\fP" +Like UDP-LISTEN, but only support IPv6 +protocol\&. +.br +Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP6 +.br +.IP "\fB\f(CWUDP-SENDTO::\fP\fP" +Communicates with the specified peer socket, defined by [UDP +service] on + [IP address], using UDP/IP version 4 or 6 +depending on address specification, name resolution, or option +pf\&. 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\&. +.br +Option groups: FD,SOCKET,IP4,IP6 +.br +Useful options: +ttl, +tos, +bind, +sourceport, +pf +.br +See also: +UDP4-SENDTO, +UDP6-SENDTO, +UDP-RECVFROM, +UDP-RECV, +UDP-CONNECT, +UDP-LISTEN, +IP-SENDTO +.IP "\fB\f(CWUDP4-SENDTO::\fP\fP" +Like UDP-SENDTO, but only supports IPv4 +protocol\&. +.br +Option groups: FD,SOCKET,IP4 +.IP "\fB\f(CWUDP6-SENDTO::\fP\fP" +Like UDP-SENDTO, but only supports IPv6 +protocol\&. +.br +Option groups: FD,SOCKET,IP6 +.IP +.IP "\fB\f(CWUDP-RECVFROM:\fP\fP" +Creates a UDP socket on [UDP service] using +UDP/IP version 4 or 6 +depending on option pf\&. +It receives one packet from an unspecified peer and may send one or more +answer packets to that peer\&. This mode is particularly useful with fork +option +where each arriving packet - from arbitrary peers - is handled by its own sub +process\&. This allows a behaviour similar to typical UDP based servers like ntpd +or named\&. This address works well with socat SENDTO address peers\&. +.br +Option groups: FD,SOCKET,IP4,IP6,CHILD,RANGE +.br +Useful options: +fork, +ttl, +tos, +bind, +sourceport, +pf +.br +See also: +UDP4-RECVFROM, +UDP6-RECVFROM, +UDP-SENDTO, +UDP-RECV, +UDP-CONNECT, +UDP-LISTEN, +IP-RECVFROM, +UNIX-RECVFROM +.IP "\fB\f(CWUDP4-RECVFROM:\fP\fP" +Like UDP-RECVFROM, but only supports IPv4 protocol\&. +.br +Option groups: FD,SOCKET,IP4,CHILD,RANGE +.IP "\fB\f(CWUDP6-RECVFROM:\fP\fP" +Like UDP-RECVFROM, but only supports IPv6 protocol\&. +.br +Option groups: FD,SOCKET,IP6,CHILD,RANGE +.IP +.IP "\fB\f(CWUDP-RECV:\fP\fP" +Creates a UDP socket on [UDP service] using UDP/IP version 4 or 6 +depending on option pf\&. +It receives packets from multiple unspecified peers and merges the data\&. +No replies are possible\&. It works well with, e\&.g\&., socat UDP-SENDTO address peers; it behaves similar to a syslog server\&. +.br +Option groups: FD,SOCKET,IP4,IP6,RANGE +.br +Useful options: +fork, +pf, +bind, +sourceport, +ttl, +tos +.br +See also: +UDP4-RECV, +UDP6-RECV, +UDP-SENDTO, +UDP-RECVFROM, +UDP-CONNECT, +UDP-LISTEN, +IP-RECV, +UNIX-RECV +.IP "\fB\f(CWUDP4-RECV:\fP\fP" +Like UDP-RECV, but only supports IPv4 protocol\&. +.br +Option groups: FD,SOCKET,IP4,RANGE +.IP "\fB\f(CWUDP6-RECV:\fP\fP" +Like UDP-RECV, but only supports IPv6 protocol\&. +.br +Option groups: FD,SOCKET,IP6,RANGE +.IP +.IP "\fB\f(CWUNIX-CONNECT:\fP\fP" +Connects to assuming it is a UNIX domain +socket\&. +If does not exist, this is an error; +if is not a UNIX domain socket, this is an error; +if is a UNIX domain socket, but no process is listening, this is +an error\&. +.br +Option groups: FD,SOCKET, +NAMED,RETRY, +UNIX +.br +) +Useful options: +bind +.br +See also: +UNIX-LISTEN, +UNIX-SENDTO, +TCP +.IP +.IP "\fB\f(CWUNIX-LISTEN:\fP\fP" +Listens on using a UNIX domain stream +socket and accepts a connection\&. +If exists and is not a socket, this is an error\&. +If exists and is a UNIX domain socket, binding to the address +fails (use option unlink-early!)\&. +Note that opening this address usually blocks until a client connects\&. +Beginning with socat version 1\&.4\&.3, the file system entry is removed when +this address is closed (but see option unlink-close) (example)\&. +.br +Option groups: FD,SOCKET, +NAMED,LISTEN, +CHILD,RETRY, +UNIX +.br +Useful options: +fork, +umask, +mode, +user, +group, +unlink-early +.br +See also: +UNIX-CONNECT, +UNIX-RECVFROM, +UNIX-RECV, +TCP-LISTEN +.IP +.IP "\fB\f(CWUNIX-SENDTO:\fP\fP" +Communicates with the specified peer socket, defined by [] assuming it is a UNIX domain datagram socket\&. +It sends packets to and receives packets from that peer socket only\&. +It works well with socat UNIX-RECVFROM and UNIX-RECV address peers\&. +.br +Option groups: FD,SOCKET, +NAMED,UNIX +.br +Useful options: +bind +.br +See also: +UNIX-RECVFROM, +UNIX-RECV, +UNIX-CONNECT, +UDP-SENDTO, +IP-SENDTO +.IP +.IP "\fB\f(CWUNIX-RECVFROM:\fP\fP" +Creates a UNIX domain datagram socket []\&. +Receives one packet and may send one or more answer packets to that peer\&. +This mode is particularly useful with fork option where each arriving packet - from arbitrary peers - is handled by its own sub process\&. +This address works well with socat UNIX-SENDTO address peers\&. +.br +Option groups: FD,SOCKET, +NAMED,CHILD, +UNIX +.br +Useful options: +fork +.br +See also: +UNIX-SENDTO, +UNIX-RECV, +UNIX-LISTEN, +UDP-RECVFROM, +IP-RECVFROM +.IP +.IP "\fB\f(CWUNIX-RECV:\fP\fP" +Creates a UNIX domain datagram socket []\&. +Receives packets from multiple unspecified peers and merges the data\&. +No replies are possible\&. It can be, e\&.g\&., addressed by socat UNIX-SENDTO address peers\&. +It behaves similar to a syslog server\&. +Option groups: FD,SOCKET, +NAMED,UNIX +.br +See also: +UNIX-SENDTO, +UNIX-RECVFROM, +UNIX-LISTEN, +UDP-RECV, +IP-RECV +.IP +.IP "\fB\f(CWUNIX-CLIENT:\fP\fP" +Communicates with the specified peer socket, defined by +[] assuming it is a UNIX domain socket\&. +It first tries to connect and, if that fails, assumes it is a datagram +socket, thus supporting both types\&. +.br +Option groups: FD,SOCKET, +NAMED,UNIX +.br +Useful options: +bind +.br +See also: +UNIX-CONNECT, +UNIX-SENDTO, +GOPEN +.IP +.IP "\fB\f(CWABSTRACT-CONNECT:\fP\fP" +.IP "\fB\f(CWABSTRACT-LISTEN:\fP\fP" +.IP "\fB\f(CWABSTRACT-SENDTO:\fP\fP" +.IP "\fB\f(CWABSTRACT-RECVFROM:\fP\fP" +.IP "\fB\f(CWABSTRACT-RECV:\fP\fP" +.IP "\fB\f(CWABSTRACT-CLIENT:\fP\fP" +The ABSTRACT addresses are almost identical to the related UNIX addresses +except that they do not address file system based sockets but an alternate +UNIX domain address space\&. To archieve this the socket address strings are +prefixed with "\e0" internally\&. This feature is available (only?) on Linux\&. +Option groups are the same as with the related UNIX addresses, except that +the ABSTRACT addresses are not member of the NAMED group\&. +.PP +.SH "ADDRESS OPTIONS" +.PP +Address options can be applied to address specifications to influence the +process of opening the addresses and the +properties of the resulting data channels\&. +.PP +For technical reasons not every option can be +applied to every address type; e\&.g\&., applying a socket option to a regular file +will fail\&. To catch most useless combinations as early as in the open phase, +the concept of \fIoption groups\fP was introduced\&. Each option belongs to one +or more option groups\&. Options can be used only with address types that support +at least one of their option groups (but see option -g)\&. +.PP +Address options have data types that their values must conform to\&. +Every address option consists of just a keyword or a keyword followed by +"=value", where value must conform to the options type\&. +Some address options manipulate parameters of system calls; +e\&.g\&., option sync sets the \f(CWO_SYNC\fP flag with the \f(CWopen()\fP call\&. +Other options cause a system or library call; e\&.g\&., with option `ttl=value\' +the \f(CWsetsockopt(fd, SOL_IP, IP_TTL, value, sizeof(int))\fP call is applied\&. +Other +options set internal \fBsocat\fP variables that are used during data transfer; +e\&.g\&., `crnl\' causes explicit character conversions\&. +A few options have more complex implementations; e\&.g\&., su-d +(substuser-delayed) inquires some user and group infos, stores them, and +applies them later after a possible \f(CWchroot()\fP call\&. +.PP +If multiple options are given to an address, their sequence in the address specification has (almost) no +effect on the sequence of their execution/application\&. Instead, \fBsocat\fP has +built in an \fIoption phase\fP model that tries to bring the options in a useful +order\&. Some options exist in different forms (e\&.g\&., +unlink, unlink-early, unlink-late) to control the time of their execution\&. +.PP +If the same option is specified more than once within one address +specification, with equal or different values, the effect depends on the kind of option\&. Options +resulting in function calls like \f(CWsetsockopt()\fP cause multiple +invocations\&. With options that set parameters for a required call like +\f(CWopen()\fP +or set internal flags, the value of the last option occurrence is effective\&. +.PP +The existence or semantics of many options are system dependent\&. \fBSocat\fP +usually does NOT try to emulate missing libc or kernel features, it just +provides an +interface to the underlying system\&. So, if an operating system lacks a feature, +the related option is simply not available on this platform\&. +.PP +The following paragraphs introduce just the more common address options\&. For +a more comprehensive reference and to find information about canonical option +names, alias names, option phases, and platforms see file \fBxio\&.help\fP\&. +.br +.br +.PP +.br +.PP +\fI\fBFD option group\fP\fP +.PP +This option group contains options that are applied to a UN*X +style file descriptor, no matter how it was generated\&. +Because all current \fBsocat\fP address types are file descriptor based, these +options may be applied to any address\&. +.br +Note: Some of these options are also member of another option group, that +provides an other, non-fd based mechanism\&. +For these options, it depends on the actual address type and its option groups +which mechanism is used\&. The second, non-fd based mechanism is prioritized\&. +.IP "\fB\f(CWcloexec=\fP\fP" +Sets the \f(CWFD_CLOEXEC\fP flag with the \f(CWfcntl()\fP system call to value +\&. If set, +the file descriptor is closed on \f(CWexec()\fP family function calls\&. \fBSocat\fP +internally handles +this flag for the fds it controls, so in most cases there will be no need to +apply this option\&. +.IP "\fB\f(CWsetlk\fP\fP" +Tries to set a discretionary write lock to the whole file using the \f(CWfcntl(fd, +F_SETLK, \&.\&.\&.)\fP system call\&. If the file is already locked, this call results +in an error\&. +On Linux, when the file permissions for group are "S" (g-x,g+s), and the +file system is locally mounted with the "mand" option, the lock is +mandatory, i\&.e\&. prevents other processes from opening the file\&. +.IP "\fB\f(CWsetlkw\fP\fP" +Tries to set a discretionary waiting write lock to the whole file using the +\f(CWfcntl(fd, F_SETLKW, \&.\&.\&.)\fP system call\&. If the file is already locked, +this call blocks\&. +See option setlk for information about making this +lock mandatory\&. +.IP "\fB\f(CWsetlk-rd\fP\fP" +Tries to set a discretionary read lock to the whole file using the \f(CWfcntl(fd, +F_SETLK, \&.\&.\&.)\fP system call\&. If the file is already write locked, this call +results in an error\&. +See option setlk for information about making this +lock mandatory\&. +.IP "\fB\f(CWsetlkw-rd\fP\fP" +Tries to set a discretionary waiting read lock to the whole file using the +\f(CWfcntl(fd, F_SETLKW, \&.\&.\&.)\fP system call\&. If the file is already write +locked, this call blocks\&. +See option setlk for information about making this +lock mandatory\&. +.IP "\fB\f(CWflock-ex\fP\fP" +Tries to set a blocking exclusive advisory lock to the file using the +\f(CWflock(fd, LOCK_EX)\fP system call\&. \fBSocat\fP hangs in this call if the file +is locked by another process\&. +.IP "\fB\f(CWflock-ex-nb\fP\fP" +Tries to set a nonblocking exclusive advisory lock to the file using the +\f(CWflock(fd, LOCK_EX|LOCK_NB)\fP system call\&. If the file is already locked, +this option results in an error\&. +.IP "\fB\f(CWflock-sh\fP\fP" +Tries to set a blocking shared advisory lock to the file using the +\f(CWflock(fd, LOCK_SH)\fP system call\&. \fBSocat\fP hangs in this call if the file +is locked by another process\&. +.IP "\fB\f(CWflock-sh-nb\fP\fP" +Tries to set a nonblocking shared advisory lock to the file using the +\f(CWflock(fd, LOCK_SH|LOCK_NB)\fP system call\&. If the file is already locked, +this option results in an error\&. +.IP "\fB\f(CWlock\fP\fP" +Sets a blocking lock on the file\&. Uses the setlk or flock mechanism +depending on availability on the particular platform\&. If both are available, +the POSIX variant (setlkw) is used\&. +.IP "\fB\f(CWuser=\fP\fP" +Sets the (owner) of the stream\&. +If the address is member of the NAMED option group, +\fBsocat\fP uses the \f(CWchown()\fP system call after opening the +file or binding to the UNIX domain socket (race condition!)\&. +Without filesystem entry, \fBsocat\fP sets the user of the stream +using the \f(CWfchown()\fP system call\&. +These calls might require root privilege\&. +.IP "\fB\f(CWuser-late=\fP\fP" +Sets the owner of the fd to with the \f(CWfchown()\fP +system call after opening +or connecting the channel\&. +This is useful only on file system entries\&. +.IP "\fB\f(CWgroup=\fP\fP" +Sets the of the stream\&. +If the address is member of the NAMED option group, +\fBsocat\fP uses the \f(CWchown()\fP system call after opening the +file or binding to the UNIX domain socket (race condition!)\&. +Without filesystem entry, \fBsocat\fP sets the group of the stream +with the \f(CWfchown()\fP system call\&. +These calls might require group membership or root privilege\&. +.IP "\fB\f(CWgroup-late=\fP\fP" +Sets the group of the fd to with the +\f(CWfchown()\fP system call after opening +or connecting the channel\&. +This is useful only on file system entries\&. +.IP "\fB\f(CWmode=\fP\fP" +Sets the [mode_t] (permissions) of the stream\&. +If the address is member of the NAMED option group and +uses the \f(CWopen()\fP or \f(CWcreat()\fP call, the mode is applied with these\&. +If the address is member of the NAMED option group without using these +system calls, \fBsocat\fP uses the \f(CWchmod()\fP system call after opening the +filesystem entry or binding to the UNIX domain socket (race condition!)\&. +Otherwise, \fBsocat\fP sets the mode of the stream +using \f(CWfchmod()\fP\&. +These calls might require ownership or root privilege\&. +.IP "\fB\f(CWperm-late=\fP\fP" +Sets the permissions of the fd to value +[mode_t] using the \f(CWfchmod()\fP system call after +opening or connecting the channel\&. +This is useful only on file system entries\&. +.IP "\fB\f(CWappend=\fP\fP" +Always writes data to the actual end of file\&. +If the address is member of the OPEN option group, +\fBsocat\fP uses the \f(CWO_APPEND\fP flag with the \f(CWopen()\fP system call +(example)\&. +Otherwise, \fBsocat\fP applies the \f(CWfcntl(fd, F_SETFL, O_APPEND)\fP call\&. +.IP "\fB\f(CWnonblock=\fP\fP" +Tries to open or use file in nonblocking mode\&. Its only effects are that the +\f(CWconnect()\fP call of TCP addresses does not block, and that opening a +named pipe for reading does not block\&. +If the address is member of the OPEN option group, +\fBsocat\fP uses the \f(CWO_NONBLOCK\fP flag with the \f(CWopen()\fP system call\&. +Otherwise, \fBsocat\fP applies the \f(CWfcntl(fd, F_SETFL, O_NONBLOCK)\fP call\&. +.IP "\fB\f(CWbinary\fP\fP" +Opens the file in binary mode to avoid implicit line terminator +conversions (Cygwin)\&. +.IP "\fB\f(CWtext\fP\fP" +Opens the file in text mode to force implicit line terminator conversions +(Cygwin)\&. +.IP "\fB\f(CWnoinherit\fP\fP" +Does not keep this file open in a spawned process (Cygwin)\&. +.IP "\fB\f(CWcool-write\fP\fP" +Takes it easy when write fails with EPIPE or ECONNRESET and logs the message +with \fInotice\fP level instead of \fIerror\fP\&. +This prevents the log file from being filled with useless error messages +when socat is used as a high volume server or proxy where clients often +abort the connection\&. +.br +This option is experimental\&. +.IP "\fB\f(CWend-close\fP\fP" +Changes the (address dependent) method of ending a connection to just close +the file descriptors\&. This is useful when the connection is to be reused by +or shared with other processes (example)\&. +.br +Normally, socket connections will be ended with \f(CWshutdown(2)\fP which +terminates the socket even if it is shared by multiple processes\&. +\f(CWclose(2)\fP "unlinks" the socket from the process but keeps it active as +long as there are still links from other processes\&. +.br +Similarly, when an address of type EXEC or SYSTEM is ended, socat usually +will explicitely kill the sub process\&. With this option, it will just close +the file descriptors\&. +.PP +.br +.PP +\fI\fBNAMED option group\fP\fP +.PP +These options work on file system entries\&. +.br +See also options user, group, and +mode\&. +.PP +.IP "\fB\f(CWuser-early=\fP\fP" +Changes the (owner) of the file system entry before +accessing it, using the +\f(CWchown()\fP system call\&. This call might require root privilege\&. +.IP "\fB\f(CWgroup-early=\fP\fP" +Changes the of the file system entry before +accessing it, using the +\f(CWchown()\fP system call\&. This call might require group membership or root +privilege\&. +.IP "\fB\f(CWperm-early=\fP\fP" +Changes the [mode_t] of the file system entry +before accessing it, using the +\f(CWchmod()\fP system call\&. This call might require ownership or root +privilege\&. +.IP "\fB\f(CWumask=\fP\fP" +Sets the umask of the process to [mode_t] before +accessing the file system entry (useful +with UNIX domain sockets!)\&. This call might affect all further operations +of the \fBsocat\fP process! +.IP "\fB\f(CWunlink-early\fP\fP" +Unlinks (removes) the file before opening it and even before applying +user-early etc\&. +.IP "\fB\f(CWunlink\fP\fP" +Unlinks (removes) the file before accessing it, but after user-early etc\&. +.IP "\fB\f(CWunlink-late\fP\fP" +Unlinks (removes) the file after opening it to make it inaccessible for +other processes after a short race condition\&. +.IP "\fB\f(CWunlink-close\fP\fP" +Removes the addresses file system entry when closing the address\&. +For named pipes, +listening unix domain sockets, +and the symbolic links of pty addresses, +the default is 1; for created files, +opened files, +generic opened files, and +client unix domain sockets the default is 0\&. +.PP +.br +.PP +\fI\fBOPEN option group\fP\fP +.PP +The OPEN group options allow to set flags with the \f(CWopen()\fP system call\&. +E\&.g\&., option `creat\' sets the \f(CWO_CREAT\fP flag\&. +.br +See also options append and +nonblock\&. +.IP "\fB\f(CWcreat=\fP\fP" +Creates the file if it does not exist (example)\&. +.IP "\fB\f(CWdsync=\fP\fP" +Blocks \f(CWwrite()\fP calls until metainfo is physically written to media\&. +.IP "\fB\f(CWexcl=\fP\fP" +With option creat, if file exists this is an error\&. +.IP "\fB\f(CWlargefile=\fP\fP" +On 32 bit systems, allows a file larger than 2^31 bytes\&. +.IP "\fB\f(CWnoatime\fP\fP" +Sets the O_NOATIME options, so reads do not change the access timestamp\&. +.IP "\fB\f(CWnoctty=\fP\fP" +Does not make this file the controlling terminal\&. +.IP "\fB\f(CWnofollow=\fP\fP" +Does not follow symbolic links\&. +.IP "\fB\f(CWnshare=\fP\fP" +Does not allow to share this file with other processes\&. +.IP "\fB\f(CWrshare=\fP\fP" +Does not allow other processes to open this file for writing\&. +.IP "\fB\f(CWrsync=\fP\fP" +Blocks \f(CWwrite()\fP until metainfo is physically written to media\&. +.IP "\fB\f(CWsync=\fP\fP" +Blocks \f(CWwrite()\fP until data is physically written to media\&. +.IP "\fB\f(CWrdonly=\fP\fP" +Opens the file for reading only\&. +.IP "\fB\f(CWwronly=\fP\fP" +Opens the file for writing only\&. +.IP "\fB\f(CWtrunc\fP\fP" +Truncates the file to size 0 during opening it\&. +.PP +.br +.PP +\fI\fBREG and BLK option group\fP\fP +.PP +These options are usually applied to a UN*X file descriptor, but their +semantics make sense only on a file supporting random access\&. +.IP "\fB\f(CWseek=\fP\fP" +Applies the \f(CWlseek(fd, , SEEK_SET)\fP (or \f(CWlseek64\fP) system +call, thus positioning the file pointer absolutely to +[off_t or off64_t]\&. +.IP "\fB\f(CWseek-cur=\fP\fP" +Applies the \f(CWlseek(fd, , SEEK_CUR)\fP (or \f(CWlseek64\fP) system +call, thus positioning the file pointer [off_t or +off64_t] bytes relatively to its current position (which +is usually 0)\&. +.IP "\fB\f(CWseek-end=\fP\fP" +Applies the \f(CWlseek(fd, , SEEK_END)\fP (or \f(CWlseek64\fP) system +call, thus positioning the file pointer [off_t or +off64_t] bytes relatively to the files current end\&. +.IP "\fB\f(CWftruncate=\fP\fP" +Applies the \f(CWftruncate(fd, )\fP +(or \f(CWftruncate64\fP if available) system call, thus +truncating the file at the position [off_t or +off64_t]\&. +.IP +.IP "\fB\f(CWsecrm=\fP\fP" +.IP "\fB\f(CWunrm=\fP\fP" +.IP "\fB\f(CWcompr=\fP\fP" +.IP "\fB\f(CWext2-sync=\fP\fP" +.IP "\fB\f(CWimmutable=\fP\fP" +.IP "\fB\f(CWext2-append=\fP\fP" +.IP "\fB\f(CWnodump=\fP\fP" +.IP "\fB\f(CWext2-noatime=\fP\fP" +.IP "\fB\f(CWjournal-data=\fP\fP" +.IP "\fB\f(CWnotail=\fP\fP" +.IP "\fB\f(CWdirsync=\fP\fP" +These options change non standard file attributes on operating systems and +file systems that support these features, like Linux with ext2fs, +ext3fs, or reiserfs\&. See man 1 chattr for information on these options\&. +Please note that there might be a race condition between creating the file +and applying these options\&. +.PP +.br +.PP +\fI\fBPROCESS option group\fP\fP +.PP +Options of this group change the process properties instead of just affecting +one data channel\&. +For EXEC and SYSTEM addresses and for LISTEN and CONNECT type addresses with +option FORK, +these options apply to the child processes instead of the main socat process\&. +.IP "\fB\f(CWchroot=\fP\fP" +Performs a \f(CWchroot()\fP operation to +after processing the address (example)\&. This call might require root privilege\&. +.IP "\fB\f(CWchroot-early=\fP\fP" +Performs a \f(CWchroot()\fP operation to +before opening the address\&. This call might require root privilege\&. +.IP "\fB\f(CWsetgid=\fP\fP" +Changes the primary of the process after +processing the address\&. This call might require root privilege\&. +.IP "\fB\f(CWsetgid-early=\fP\fP" +Changes the primary of the process before opening +the address\&. This call might require root privilege\&. +.IP "\fB\f(CWsetuid=\fP\fP" +Changes the (owner) of the process after processing +the address\&. This call might require root privilege\&. +.IP "\fB\f(CWsetuid-early=\fP\fP" +Changes the (owner) of the process before opening +the address\&. This call might require root privilege\&. +.IP "\fB\f(CWsu=\fP\fP" +Changes the (owner) and groups of the process after +processing the address (example)\&. This call might require root privilege\&. +.IP "\fB\f(CWsu-d=\fP\fP" +Short name for \fB\f(CWsubstuser-delayed\fP\fP\&. +Changes the +(owner) and groups of the process after processing the address (example)\&. +The user and his groups are retrieved \fIbefore\fP a possible +\f(CWchroot()\fP\&. This call might require root privilege\&. +.IP "\fB\f(CWsetpgid=\fP\fP" +Makes the process a member of the specified process group +\&. If no value +is given, or if the value is 0 or 1, the process becomes leader of a new +process group\&. +.IP "\fB\f(CWsetsid\fP\fP" +Makes the process the leader of a new session (example)\&. +.PP +.br +.PP +\fI\fBREADLINE option group\fP\fP +.PP +These options apply to the readline address type\&. +.IP "\fB\f(CWhistory=\fP\fP" +Reads and writes history from/to (example)\&. +.IP "\fB\f(CWnoprompt\fP\fP" +Since version 1\&.4\&.0, socat per default tries to determine a prompt - +that is then passed to the readline call - by remembering the last +incomplete line of the output\&. With this option, socat does not pass a +prompt to readline, so it begins line editing in the first column +of the terminal\&. +.IP "\fB\f(CWnoecho=\fP\fP" +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 +typed\&. The pattern is a regular expression, e\&.g\&. +"^[Pp]assword:\&.*$" or "([Uu]ser:|[Pp]assword:)"\&. See regex(7) for details\&. +(example) +.IP "\fB\f(CWprompt=\fP\fP" +Passes the string as prompt to the readline function\&. readline prints this +prompt when stepping through the history\&. If this string matches a constant +prompt issued by an interactive program on the other socat address, +consistent look and feel can be archieved\&. +.PP +.br +.PP +\fI\fBAPPLICATION option group\fP\fP +.PP +This group contains options that work at data level\&. +Note that these options only apply to the "raw" data transferred by socat, +but not to protocol data used by addresses like +PROXY\&. +.IP "\fB\f(CWcr\fP\fP" +Converts the default line termination character NL (\'\en\', 0x0a) to/from CR +(\'\er\', 0x0d) when writing/reading on this channel\&. +.IP "\fB\f(CWcrnl\fP\fP" +Converts the default line termination character NL (\'\en\', 0x0a) to/from CRNL +("\er\en", 0x0d0a) when writing/reading on this channel (example)\&. +Note: socat simply strips all CR characters\&. +.IP "\fB\f(CWignoreeof\fP\fP" +When EOF occurs on this channel, \fBsocat\fP ignores it and tries to read more +data (like "tail -f") (example)\&. +.IP "\fB\f(CWreadbytes=\fP\fP" +\fBsocat\fP reads only so many bytes from this address (the address provides +only so many bytes for transfer and pretends to be at EOF afterwards)\&. +Must be greater than 0\&. +.IP "\fB\f(CWlockfile=\fP\fP" +If lockfile exists, exits with error\&. If lockfile does not exist, creates it +and continues, unlinks lockfile on exit\&. +.IP "\fB\f(CWwaitlock=\fP\fP" +If lockfile exists, waits until it disappears\&. When lockfile does not exist, +creates it and continues, unlinks lockfile on exit\&. +.PP +.br +.PP +\fI\fBSOCKET option group\fP\fP +.PP +These options are intended for all kinds of sockets, e\&.g\&. IP or UNIX domain\&. Most are applied with a \f(CWsetsockopt()\fP call\&. +.IP "\fB\f(CWbind=\fP\fP" +Binds the socket to the given socket address using the \f(CWbind()\fP system +call\&. The form of is socket domain dependent: +IP4 and IP6 allow the form [hostname|hostaddress][:(service|port)] (example), +UNIX domain sockets require \&. +.IP "\fB\f(CWconnect-timeout=\fP\fP" +Abort the connection attempt after [timeval] +with error status\&. +.IP "\fB\f(CWinterface=\fP\fP" +Binds the socket to the given \&. +This option might require root privilege\&. +.IP "\fB\f(CWbroadcast\fP\fP" +For datagram sockets, allows sending to broadcast addresses and receiving +packets addressed to broadcast addresses\&. +.IP "\fB\f(CWbsdcompat\fP\fP" +Emulates some (old?) bugs of the BSD socket implementation\&. +.IP "\fB\f(CWdebug\fP\fP" +Enables socket debugging\&. +.IP "\fB\f(CWdontroute\fP\fP" +Only communicates with directly connected peers, does not use routers\&. +.IP "\fB\f(CWkeepalive\fP\fP" +Enables sending keepalives on the socket\&. +.IP "\fB\f(CWlinger=\fP\fP" +Blocks \f(CWshutdown()\fP or \f(CWclose()\fP until data transfers have finished +or the given timeout [int] expired\&. +.IP "\fB\f(CWoobinline\fP\fP" +Places out-of-band data in the input data stream\&. +.IP "\fB\f(CWpriority=\fP\fP" +Sets the protocol defined [] for outgoing +packets\&. +.IP "\fB\f(CWrcvbuf=\fP\fP" +Sets the size of the receive buffer after the \f(CWsocket()\fP call to + [int]\&. With TCP +sockets, this value corresponds to the socket\'s maximal window size\&. +.IP "\fB\f(CWrcvbuf-late=\fP\fP" +Sets the size of the receive buffer when the socket is already +connected to [int]\&. +With TCP sockets, this value corresponds to the socket\'s +maximal window size\&. +.IP "\fB\f(CWrcvlowat=\fP\fP" +Specifies the minimum number of received bytes [int] until +the socket layer will pass the buffered data to \fBsocat\fP\&. +.IP "\fB\f(CWrcvtimeo=\fP\fP" +Sets the receive timeout [timeval]\&. +.IP "\fB\f(CWreuseaddr\fP\fP" +Allows other sockets to bind to an address even if parts of it (e\&.g\&. the +local port) are already in use by \fBsocat\fP (example)\&. +.IP "\fB\f(CWsndbuf=\fP\fP" +Sets the size of the send buffer after the \f(CWsocket()\fP call to + [int]\&. +.IP "\fB\f(CWsndbuf-late=\fP\fP" +Sets the size of the send buffer when the socket is connected to + [int]\&. +.IP "\fB\f(CWsndlowat=\fP\fP" +Specifies the minimum number of bytes in the send buffer until the socket +layer will send the data to [int]\&. +.IP "\fB\f(CWsndtimeo=\fP\fP" +Sets the send timeout to seconds [timeval]\&. +.IP "\fB\f(CWtype=\fP\fP" +Sets the type of the socket, usually as argument to the \f(CWsocket()\fP or +\f(CWsocketpair()\fP call, to [int]\&. +Under Linux, 1 means stream oriented socket, 2 means datagram socket, and 3 +means raw socket\&. +.IP "\fB\f(CWpf=\fP\fP" +Forces the use of the specified IP version\&. can be +something like "ip4" or "ip6"\&. +.PP +.br +.PP +\fI\fBUNIX option group\fP\fP +.PP +These options apply to UNIX domain based addresses\&. +.IP "\fB\f(CWunix-tightsocklen=[0|1]\fP\fP" +On socket operations, pass a socket address length that does not include the +whole \f(CWstruct sockaddr_un\fP record but (besides other components) only +the relevant part of the filename or abstract string\&. Default is 1\&. +.PP +\fI\fBIP4 and IP6 option groups\fP\fP +.PP +These options can be used with IPv4 and IPv6 based sockets\&. +.IP "\fB\f(CWtos=\fP\fP" +Sets the TOS (type of service) field of outgoing packets to +[byte] (see RFC 791)\&. +.IP "\fB\f(CWttl=\fP\fP" +Sets the TTL (time to live) field of outgoing packets to +[byte]\&. +.IP "\fB\f(CWipoptions=\fP\fP" +Sets IP options like source routing\&. Must be given in binary form, +recommended format is a leading "x" followed by an even number of hex +digits\&. This option may be used multiple times, data are appended\&. +E\&.g\&., to connect to host 10\&.0\&.0\&.1 via some gateway using a loose source +route, use the gateway as address parameter and set a loose source route +using the option \f(CWipoptions=x8307040a000001\fP\&. +.br +IP options are defined in RFC 791\&. +.br +.IP "\fB\f(CWmtudiscover=<0|1|2>\fP\fP" +Takes 0, 1, 2 to never, want, or always use path MTU discover on this +socket\&. +.IP "\fB\f(CWip-add-membership=\fP\fP" +.IP "\fB\f(CWip-add-membership=\fP\fP" +.IP "\fB\f(CWip-add-membership=\fP\fP" +.IP "\fB\f(CWip-add-membership=\fP\fP" +.IP "\fB\f(CWip-add-membership=\fP\fP" +Makes the socket member of the specified multicast group\&. This is currently +only implemented for IPv4\&. The option takes the IP address of the multicast +group and info about the desired network interface\&. The most common syntax +is the first one, while the others are only available on systems that +provide \f(CWstruct mreqn\fP (Linux)\&. +.br +The indices of active network interfaces can be shown using the utility +\fBprocan\fP\&. +dif(\fB\f(CWip-multicast-if=\fP\fP) +Specifies hostname or address of the network interface to be used for +multicast traffic\&. +dif(\fB\f(CWip-multicast-loop=\fP\fP) +Specifies if outgoing multicast traffic should loop back to the interface\&. +dif(\fB\f(CWip-multicast-ttl=\fP\fP) +Sets the TTL used for outgoing multicast traffic\&. Default is 1\&. +.IP "\fB\f(CWres-debug\fP\fP" +.IP "\fB\f(CWres-aaonly\fP\fP" +.IP "\fB\f(CWres-usevc\fP\fP" +.IP "\fB\f(CWres-primary\fP\fP" +.IP "\fB\f(CWres-igntc\fP\fP" +.IP "\fB\f(CWres-recurse\fP\fP" +.IP "\fB\f(CWres-defnames\fP\fP" +.IP "\fB\f(CWres-stayopen\fP\fP" +.IP "\fB\f(CWres-dnsrch\fP\fP" +These options set the corresponding resolver (name resolution) option flags\&. +Append "=0" to clear a default option\&. See man resolver(5) for more +information on these options\&. Note: these options are valid only for the +address they are applied to\&. +.IP +.PP +.br +.PP +\fI\fBIP6 option group\fP\fP +.PP +These options can only be used on IPv6 based sockets\&. See IP +options for options that can be applied to both IPv4 and IPv6 +sockets\&. +.IP "\fB\f(CWipv6only=\fP\fP" +Sets the IPV6_V6ONLY socket option\&. If 0, the TCP stack will also accept +connections using IPv4 protocol on the same port\&. The default is system +dependent\&. +.PP +.br +.PP +\fI\fBTCP option group\fP\fP +.PP +These options may be applied to TCP sockets\&. They work by invoking \f(CWsetsockopt()\fP with the appropriate parameters\&. +.IP "\fB\f(CWcork\fP\fP" +Doesn\'t send packets smaller than MSS (maximal segment size)\&. +.IP "\fB\f(CWdefer-accept\fP\fP" +While listening, accepts connections only when data from the peer arrived\&. +.IP "\fB\f(CWkeepcnt=\fP\fP" +Sets the number of keepalives before shutting down the socket to + [int]\&. +.IP "\fB\f(CWkeepidle=\fP\fP" +Sets the idle time before sending the first keepalive to +[int]\&. +.IP "\fB\f(CWkeepintvl=\fP\fP" +Sets the intervall between two keepalives to +[int]\&. +.IP "\fB\f(CWlinger2=\fP\fP" +Sets the time to keep the socket in FIN-WAIT-2 state to +[int]\&. +.IP "\fB\f(CWmss=\fP\fP" +Sets the MSS (maximum segment size) after the \f(CWsocket()\fP call to +[int]\&. This +value is then proposed to the peer with the SYN or SYN/ACK packet +(example)\&. +.IP "\fB\f(CWmss-late=\fP\fP" +Sets the MSS of the socket after connection has been established to +[int]\&. +.IP "\fB\f(CWnodelay\fP\fP" +Turns off the Nagle algorithm for measuring the RTT (round trip time)\&. +.IP "\fB\f(CWrfc1323\fP\fP" +Enables RFC1323 TCP options: TCP window scale, round-trip time measurement +(RTTM), and protect against wrapped sequence numbers (PAWS) (AIX)\&. +.IP "\fB\f(CWstdurg\fP\fP" +Enables RFC1122 compliant urgent pointer handling (AIX)\&. +.IP "\fB\f(CWsyncnt=\fP\fP" +Sets the maximal number of SYN retransmits during connect to +[int]\&. +.IP "\fB\f(CWmd5sig\fP\fP" +Enables generation of MD5 digests on the packets (FreeBSD)\&. +.IP "\fB\f(CWnoopt\fP\fP" +Disables use of TCP options (FreeBSD, MacOSX)\&. +.IP "\fB\f(CWnopush\fP\fP" +sets the TCP_NOPUSH socket option (FreeBSD, MacOSX)\&. +.IP "\fB\f(CWsack-disable\fP\fP" +Disables use the selective acknowledge feature (OpenBSD)\&. +.IP "\fB\f(CWsignature-enable\fP\fP" +Enables generation of MD5 digests on the packets (OpenBSD)\&. +.IP "\fB\f(CWabort-threshold=\fP\fP" +Sets the time to wait for an answer of the peer on an established connection +(HP-UX)\&. +.IP "\fB\f(CWconn-abort-threshold=\fP\fP" +Sets the time to wait for an answer of the server during the initial connect +(HP-UX)\&. +.IP "\fB\f(CWkeepinit\fP\fP" +Sets the time to wait for an answer of the server during connect() before +giving up\&. Value in half seconds, default is 150 (75s) (Tru64)\&. +.IP "\fB\f(CWpaws\fP\fP" +Enables the "protect against wrapped sequence numbers" feature (Tru64)\&. +.IP "\fB\f(CWsackena\fP\fP" +Enables selective acknowledge (Tru64)\&. +.IP "\fB\f(CWtsoptena\fP\fP" +Enables the time stamp option that allows RTT recalculation on existing +connections (Tru64)\&. +.PP +.br +.PP +\fI\fBUDP and TCP option groups\fP\fP +.PP +Here we find options that are related to the network port mechanism and that +thus can be used with UDP and TCP, client and server addresses\&. +.IP "\fB\f(CWsourceport=\fP\fP" +For outgoing (client) TCP and UDP connections, it sets the source + using an extra \f(CWbind()\fP call\&. +With TCP or UDP listen addresses, socat immediately shuts down the +connection if the client does not use this sourceport (example)\&. +.IP "\fB\f(CWlowport\fP\fP" +Outgoing (client) TCP and UDP connections with this option use +an unused random source port between 640 and 1023 incl\&. On UNIX class operating +systems, this requires root privilege, and thus indicates that the +client process is authorized by local root\&. +TCP and UDP listen addresses with this option immediately shut down the +connection if the client does not use a sourceport <= 1023\&. +This mechanism can provide limited authorization under some circumstances\&. +.PP +.br +.PP +\fI\fBSOCKS option group\fP\fP +.PP +When using SOCKS type addresses, some socks specific options can be set\&. +.IP "\fB\f(CWsocksport=\fP\fP" +Overrides the default "socks" service or port 1080 for the socks server +port with \&. +.IP "\fB\f(CWsocksuser=\fP\fP" +Sends the [string] in the username field to the +socks server\&. Default is the actual user name ($LOGNAME or $USER) (example)\&. +.PP +.br +.PP +\fI\fBHTTP option group\fP\fP +.PP +Options that can be provided with HTTP type addresses\&. The only HTTP address +currently implemented is proxy-connect\&. +.PP +.IP "\fB\f(CWproxyport=\fP\fP" +Overrides the default HTTP proxy port 8080 with +\&. +.IP "\fB\f(CWignorecr\fP\fP" +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 +to ignore CR in the answer\&. Nevertheless, socat sends CR+NL to the proxy\&. +.IP "\fB\f(CWproxyauth=:\fP\fP" +Provide "basic" authentication to the proxy server\&. The argument to the +option is used with a "Proxy-Authorization: Base" header in base64 encoded +form\&. +.br +Note: username and password are visible for every user on the local machine +in the process list; username and password are transferred to the proxy +server unencrypted (base64 encoded) and might be sniffed\&. +.IP "\fB\f(CWresolve\fP\fP" +Per default, socat sends to the proxy a CONNECT request containing the +target hostname\&. With this option, socat resolves the hostname locally and +sends the IP address\&. Please note that, according to RFC 2396, only name +resolution to IPv4 addresses is implemented\&. +.PP +.br +.PP +\fI\fBRANGE option group\fP\fP +.PP +These options check if a connecting client should be granted access\&. They can +be applied to listening and receiving network sockets\&. tcp-wrappers options +fall into this group\&. +.IP "\fB\f(CWrange=\fP\fP" +After accepting a connection, tests if the peer is within \fIrange\fP\&. For +IPv4 addresses, address-range takes the form address/bits, e\&.g\&. +10\&.0\&.0\&.0/8, or address:mask, e\&.g\&. 10\&.0\&.0\&.0:255\&.0\&.0\&.0 (example); for IPv6, it is [ip6-address/bits], e\&.g\&. [::1/128]\&. +If the client address does not match, \fBsocat\fP issues a warning and keeps +listening/receiving\&. +.IP "\fB\f(CWtcpwrap[=]\fP\fP" +Uses Wietse Venema\'s libwrap (tcpd) library to determine +if the client is allowed to connect\&. The configuration files are +/etc/hosts\&.allow and /etc/hosts\&.deny per default, see "man 5 hosts_access" +for more information\&. The optional (type string) +is passed to the wrapper functions as daemon process name (example)\&. +If omitted, the basename of socats invocation (argv[0]) is passed\&. +If both tcpwrap and range options are applied to an address, both +conditions must be fulfilled to allow the connection\&. +.IP "\fB\f(CWallow-table=\fP\fP" +Takes the specified file instead of /etc/hosts\&.allow\&. +.IP "\fB\f(CWdeny-table=\fP\fP" +Takes the specified file instead of /etc/hosts\&.deny\&. +.IP "\fB\f(CWtcpwrap-etc=\fP\fP" +Looks for hosts\&.allow and hosts\&.deny in the specified directory\&. Is +overridden by options hosts-allow +and hosts-deny\&. +.PP +.br +.PP +\fI\fBLISTEN option group\fP\fP +.PP +Options specific to listening sockets\&. +.IP "\fB\f(CWbacklog=\fP\fP" +Sets the backlog value passed with the \f(CWlisten()\fP system call to +[int]\&. Default is 5\&. +.br +.PP +\fI\fBCHILD option group\fP\fP +.PP +Options for addresses with multiple connections via child processes\&. +.IP "\fB\f(CWfork\fP\fP" +After establishing a connection, handles its channel in a child process and +keeps the parent process attempting to produce more connections, either by +listening or by connecting in a loop (example)\&. +.br +SSL-CONNECT and SSL-LISTEN differ in when they actually fork off the child: +SSL-LISTEN forks \fIbefore\fP the SSL handshake, while SSL-CONNECT forks +\fIafterwards\fP\&. +RETRY and FOREVER options are not inherited by the child process\&. +.br +.PP +.br +.PP +\fI\fBEXEC option group\fP\fP +.PP +Options for addresses that invoke a program\&. +.IP "\fB\f(CWpath=\fP\fP" +Overrides the PATH environment variable for searching the program with +\&. This +\f(CW$PATH\fP value is effective in the child process too\&. +.IP "\fB\f(CWlogin\fP\fP" +Prefixes \f(CWargv[0]\fP for the \f(CWexecvp()\fP call with \'-\', thus making a +shell behave as login shell\&. +.PP +.br +.PP +\fI\fBFORK option group\fP\fP +.PP +EXEC or SYSTEM addresses invoke a program using a child process and transfer data between \fBsocat\fP and the program\&. The interprocess communication mechanism can be influenced with the following options\&. Per +default, a \f(CWsocketpair()\fP is created and assigned to stdin and stdout of +the child process, while stderr is inherited from the \fBsocat\fP process, and the +child process uses file descriptors 0 and 1 for communicating with the main +socat process\&. +.IP "\fB\f(CWnofork\fP\fP" +Does not fork a subprocess for executing the program, instead calls execvp() +or system() directly from the actual socat instance\&. This avoids the +overhead of another process between the program and its peer, +but introduces a lot of restrictions: +.IP o +this option can only be applied to the second \fBsocat\fP address\&. +.IP o +it cannot be applied to a part of a dual address\&. +.IP o +the first socat address cannot be OPENSSL or READLINE +.IP o +socat options -b, -t, -D, -l, -v, -x become useless +.IP o +for both addresses, options ignoreeof, cr, and crnl become useless +.IP o +for the second address (the one with option nofork), options +append, cloexec, flock, user, group, mode, nonblock, +perm-late, setlk, and setpgid cannot be applied\&. Some of these could be +used on the first address though\&. +.IP "\fB\f(CWpipes\fP\fP" +Creates a pair of unnamed pipes for interprocess communication instead of a +socket pair\&. +.IP "\fB\f(CWopenpty\fP\fP" +Establishes communication with the sub process using a pseudo terminal +created with \f(CWopenpty()\fP instead of the default (socketpair or ptmx)\&. +.IP "\fB\f(CWptmx\fP\fP" +Establishes communication with the sub process using a pseudo terminal +created by opening \fB/dev/ptmx\fP or \fB/dev/ptc\fP instead of the default +(socketpair)\&. +.IP "\fB\f(CWpty\fP\fP" +Establishes communication with the sub process using a pseudo terminal +instead of a socket pair\&. Creates the pty with an available mechanism\&. If +openpty and ptmx are both available, it uses ptmx because this is POSIX +compliant (example)\&. +.IP "\fB\f(CWctty\fP\fP" +Makes the pty the controlling tty of the sub process (example)\&. +.IP "\fB\f(CWstderr\fP\fP" +Directs stderr of the sub process to its output channel by making stderr a +\f(CWdup()\fP of stdout (example)\&. +.IP "\fB\f(CWfdin=\fP\fP" +Assigns the sub processes input channel to its file descriptor + +instead of stdin (0)\&. The program started from the subprocess has to use +this fd for reading data from \fBsocat\fP (example)\&. +.IP "\fB\f(CWfdout=\fP\fP" +Assigns the sub processes output channel to its file descriptor + +instead of stdout (1)\&. The program started from the subprocess has to use +this fd for writing data to \fBsocat\fP (example)\&. +.IP "\fB\f(CWsighup\fP\fP, \fB\f(CWsigint\fP\fP, \fB\f(CWsigquit\fP\fP" +Has \fBsocat\fP pass an eventual signal of this type to the sub process\&. +If no address has this option, socat terminates on these signals\&. +.PP +.br +.PP +\fI\fBTERMIOS option group\fP\fP +.PP +For addresses that work on a tty (e\&.g\&., stdio, file:/dev/tty, exec:\&.\&.\&.,pty), the terminal parameters defined in the UN*X termios mechanism are made available as address option parameters\&. +Please note that changes of the parameters of your interactive terminal +remain effective after \fBsocat\fP\'s termination, so you might have to enter "reset" +or "stty sane" in your shell afterwards\&. +For EXEC and SYSTEM addresses with option PTY, +these options apply to the pty by the child processes\&. +.PP +.IP "\fB\f(CWb0\fP\fP" +Disconnects the terminal\&. +.IP "\fB\f(CWb19200\fP\fP" +Sets the serial line speed to 19200 baud\&. Some other rates are possible; use +something like \f(CWsocat -hh |grep \' b[1-9]\'\fP to find all speeds supported by +your implementation\&. +.br +Note: On some operating systems, these options may not be +available\&. Use ispeed or ospeed +instead\&. +.IP "\fB\f(CWecho=\fP\fP" +Enables or disables local echo (example)\&. +.IP "\fB\f(CWicanon=\fP\fP" +Sets or clears canonical mode, enabling line buffering and some special +characters\&. +.IP "\fB\f(CWraw\fP\fP" +Sets raw mode, thus passing input and output almost unprocessed (example)\&. +.IP "\fB\f(CWignbrk=\fP\fP" +Ignores or interpretes the BREAK character (e\&.g\&., ^C) +.IP "\fB\f(CWbrkint=\fP\fP" +.IP "\fB\f(CWbs0\fP\fP" +.IP "\fB\f(CWbs1\fP\fP" +.IP "\fB\f(CWbsdly=<0|1>\fP\fP" +.IP "\fB\f(CWclocal=\fP\fP" +.IP +\.LP +\.nf +\fBcr0 +cr1 +cr2 +cr3\fP +\.fi +\.IP +Sets the carriage return delay to 0, 1, 2, or 3, respectively\&. +0 means no delay, the other values are terminal dependent\&. +.IP +.IP "\fB\f(CWcrdly=<0|1|2|3>\fP\fP" +.IP "\fB\f(CWcread=\fP\fP" +.IP "\fB\f(CWcrtscts=\fP\fP" +.IP +\.LP +\.nf +\fBcs5 +cs6 +cs7 +cs8\fP +\.fi +\.IP +Sets the character size to 5, 6, 7, or 8 bits, respectively\&. +.IP +.IP "\fB\f(CWcsize=<0|1|2|3>\fP\fP" +.IP "\fB\f(CWcstopb=\fP\fP" +Sets two stop bits, rather than one\&. +.IP "\fB\f(CWdsusp=\fP\fP" +Sets the value for the VDSUSP character that suspends the current foreground +process and reactivates the shell (all except Linux)\&. +.IP "\fB\f(CWechoctl=\fP\fP" +Echos control characters in hat notation (e\&.g\&. ^A) +.IP "\fB\f(CWechoe=\fP\fP" +.IP "\fB\f(CWechok=\fP\fP" +.IP "\fB\f(CWechoke=\fP\fP" +.IP "\fB\f(CWechonl=\fP\fP" +.IP "\fB\f(CWechoprt=\fP\fP" +.IP "\fB\f(CWeof=\fP\fP" +.IP "\fB\f(CWeol=\fP\fP" +.IP "\fB\f(CWeol2=\fP\fP" +.IP "\fB\f(CWerase=\fP\fP" +.IP "\fB\f(CWdiscard=\fP\fP" +.IP "\fB\f(CWff0\fP\fP" +.IP "\fB\f(CWff1\fP\fP" +.IP "\fB\f(CWffdly=\fP\fP" +.IP "\fB\f(CWflusho=\fP\fP" +.IP "\fB\f(CWhupcl=\fP\fP" +.IP "\fB\f(CWicrnl=\fP\fP" +.IP "\fB\f(CWiexten=\fP\fP" +.IP "\fB\f(CWigncr=\fP\fP" +.IP "\fB\f(CWignpar=\fP\fP" +.IP "\fB\f(CWimaxbel=\fP\fP" +.IP "\fB\f(CWinlcr=\fP\fP" +.IP "\fB\f(CWinpck=\fP\fP" +.IP "\fB\f(CWintr=\fP\fP" +.IP "\fB\f(CWisig=\fP\fP" +.IP "\fB\f(CWispeed=\fP\fP" +Set the baud rate for incoming data on this line\&. +.br +See also: ospeed, b19200 +dif(\fB\f(CWistrip=\fP\fP) +.IP "\fB\f(CWiuclc=\fP\fP" +.IP "\fB\f(CWixany=\fP\fP" +.IP "\fB\f(CWixoff=\fP\fP" +.IP "\fB\f(CWixon=\fP\fP" +.IP "\fB\f(CWkill=\fP\fP" +.IP "\fB\f(CWlnext=\fP\fP" +.IP "\fB\f(CWmin=\fP\fP" +.IP "\fB\f(CWnl0\fP\fP" +Sets the newline delay to 0\&. +.IP "\fB\f(CWnl1\fP\fP" +.IP "\fB\f(CWnldly=\fP\fP" +.IP "\fB\f(CWnoflsh=\fP\fP" +.IP "\fB\f(CWocrnl=\fP\fP" +.IP "\fB\f(CWofdel=\fP\fP" +.IP "\fB\f(CWofill=\fP\fP" +.IP "\fB\f(CWolcuc=\fP\fP" +.IP "\fB\f(CWonlcr=\fP\fP" +.IP "\fB\f(CWonlret=\fP\fP" +.IP "\fB\f(CWonocr=\fP\fP" +.IP "\fB\f(CWopost=\fP\fP" +Enables or disables output processing; e\&.g\&., converts NL to CR-NL\&. +.IP "\fB\f(CWospeed=\fP\fP" +Set the baud rate for outgoing data on this line\&. +.br +See also: ispeed, b19200 +.IP "\fB\f(CWparenb=\fP\fP" +Enable parity generation on output and parity checking for input\&. +.IP "\fB\f(CWparmrk=\fP\fP" +.IP "\fB\f(CWparodd=\fP\fP" +.IP "\fB\f(CWpendin=\fP\fP" +.IP "\fB\f(CWquit=\fP\fP" +.IP "\fB\f(CWreprint=\fP\fP" +.IP "\fB\f(CWsane\fP\fP" +Brings the terminal to something like a useful default state\&. +.IP "\fB\f(CWstart=\fP\fP" +.IP "\fB\f(CWstop=\fP\fP" +.IP "\fB\f(CWsusp=\fP\fP" +.IP "\fB\f(CWswtc=\fP\fP" +.IP "\fB\f(CWtab0\fP\fP" +.IP "\fB\f(CWtab1\fP\fP" +.IP "\fB\f(CWtab2\fP\fP" +.IP "\fB\f(CWtab3\fP\fP" +.IP "\fB\f(CWtabdly=\fP\fP" +.IP "\fB\f(CWtime=\fP\fP" +.IP "\fB\f(CWtostop=\fP\fP" +.IP "\fB\f(CWvt0\fP\fP" +.IP "\fB\f(CWvt1\fP\fP" +.IP "\fB\f(CWvtdly=\fP\fP" +.IP "\fB\f(CWwerase=\fP\fP" +.IP "\fB\f(CWxcase=\fP\fP" +.IP "\fB\f(CWxtabs\fP\fP" +.PP +.br +.PP +\fI\fBPTY option group\fP\fP +.PP +These options are intended for use with the pty address +type\&. +.PP +.IP "\fB\f(CWlink=\fP\fP" +Generates a symbolic link that points to the actual pseudo terminal +(pty)\&. This might help +to solve the problem that ptys are generated with more or less +unpredictable names, making it difficult to directly access the socat +generated pty automatically\&. With this option, the user can specify a "fix" +point in the file hierarchy that helps him to access the actual pty +(example)\&. +Beginning with \fBsocat\fP version 1\&.4\&.3, the symbolic link is removed when +the address is closed (but see option unlink-close)\&. +.IP "\fB\f(CWwait-slave\fP\fP" +Blocks the open phase until a process opens the slave side of the pty\&. +Usually, socat continues after generating the pty with opening the next +address or with entering the transfer loop\&. With the wait-slave option, +socat waits until some process opens the slave side of the pty before +continuing\&. +This option only works if the operating system provides the \f(CWpoll()\fP +system call\&. And it depends on an undocumented behaviour of pty\'s, so it +does not work on all operating systems\&. It has successfully been tested on +Linux, FreeBSD, NetBSD, and on Tru64 with openpty\&. +.IP "\fB\f(CWpty-intervall=\fP\fP" +When the wait-slave option is set, socat +periodically checks the HUP condition using \f(CWpoll()\fP to find if the pty\'s +slave side has been opened\&. The default polling intervall is 1s\&. Use the +pty-intervall option [timeval] to change this value\&. +.PP +.br +.PP +\fI\fBOPENSSL option group\fP\fP +.PP +These options apply to the openssl and +openssl-listen address types\&. +.PP +.IP "\fB\f(CWcipher=\fP\fP" +Selects the list of ciphers that may be used for the connection\&. +See the man page of \f(CWciphers\fP, section \fBCIPHER LIST FORMAT\fP, for +detailed information about syntax, values, and default of \&. +.br +Several cipher strings may be given, separated by \':\'\&. +Some simple cipher strings: +.IP "3DES" +Uses a cipher suite with triple DES\&. +.IP "MD5" +Uses a cipher suite with MD5\&. +.IP "aNULL" +Uses a cipher suite without authentication\&. +.IP "NULL" +Does not use encryption\&. +.IP "HIGH" +Uses a cipher suite with "high" encryption\&. +Note that the peer must support the selected property, or the negotiation +will fail\&. +.IP "\fB\f(CWmethod=\fP\fP" +Sets the protocol version to be used\&. Valid strings (not case sensitive) +are: +.IP "\f(CWSSLv2\fP" +Select SSL protocol version 2\&. +.IP "\f(CWSSLv3\fP" +Select SSL protocol version 3\&. +.IP "\f(CWSSLv23\fP" +Select SSL protocol version 2 or 3\&. This is the default when +this option is not provided\&. +.IP "\f(CWTLSv1\fP" +Select TLS protocol version 1\&. +.IP "\fB\f(CWverify=\fP\fP" +Controls check of the peer\'s certificate\&. Default is 1 (true)\&. Disabling +verify might open your socket for everyone, making the encryption useless! +.IP "\fB\f(CWcert=\fP\fP" +Specifies the file with the certificate and private key for authentication\&. +The certificate must be in OpenSSL format (*\&.pem)\&. +With openssl-listen, use of this option is strongly +recommended\&. Except with cipher aNULL, "no shared ciphers" error will +occur when no certificate is given\&. +.IP "\fB\f(CWkey=\fP\fP" +Specifies the file with the private key\&. The private key may be in this +file or in the file given with the cert option\&. The party that has +to proof that it is the owner of a certificate needs the private key\&. +.IP "\fB\f(CWdhparams=\fP\fP" +Specifies the file with the Diffie Hellman parameters\&. These parameters may +also be in the file given with the cert +option in which case the dhparams option is not needed\&. +.IP "\fB\f(CWcafile=\fP\fP" +Specifies the file with the trusted (root) authority certificates\&. The file +must be in PEM format and should contain one or more certificates\&. The party +that checks the authentication of its peer trusts only certificates that are +in this file\&. +.IP "\fB\f(CWcapath=\fP\fP" +Specifies the directory with the trusted (root) certificates\&. The directory +must contain certificates in PEM format and their hashes (see OpenSSL +documentation) +.IP "\fB\f(CWegd=\fP\fP" +On some systems, openssl requires an explicit source of random data\&. Specify +the socket name where an entropy gathering daemon like egd provides random +data, e\&.g\&. /dev/egd-pool\&. +.IP "\fB\f(CWpseudo\fP\fP" +On systems where openssl cannot find an entropy source and where no entropy +gathering daemon can be utilized, this option activates a mechanism for +providing pseudo entropy\&. This is archieved 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 random() calls\&. +.br +NOTE:This mechanism is not sufficient for generation of secure keys! +.IP "\fB\f(CWfips\fP\fP" +Enables FIPS mode if compiled in\&. For info about the FIPS encryption +implementation standard see http://oss-institute\&.org/fips-faq\&.html\&. +This mode might require that the involved certificates are generated with a +FIPS enabled version of openssl\&. Setting or clearing this option on one +socat address affects all OpenSSL addresses of this process\&. +.PP +.br +.PP +\fI\fBRETRY option group\fP\fP +.PP +Options that control retry of some system calls, especially connection +attempts\&. +.PP +.IP "\fB\f(CWretry=\fP\fP" +Number of retries before the connection or listen attempt is aborted\&. +Default is 0, which means just one attempt\&. +.IP "\fB\f(CWintervall=\fP\fP" +Time between consecutive attempts (seconds, +[timespec])\&. Default is 1 second\&. +.IP "\fB\f(CWforever\fP\fP" +Performs an unlimited number of retry attempts\&. +.PP +.br +.PP +\fI\fBTUN option group\fP\fP +.PP +Options that control Linux TUN/TAP interface device addresses\&. +.PP +.IP "\fB\f(CWtun-device=\fP\fP" +Instructs socat to take another path for the TUN clone device\&. Default is +\f(CW/dev/net/tun\fP\&. +.IP "\fB\f(CWtun-name=\fP\fP" +Gives the resulting network interface a specific name instead of the system +generated (tun0, tun1, etc\&.) +.IP "\fB\f(CWtun-type=[tun|tap]\fP\fP" +Sets the type of the TUN device; use this option to generate a TAP +device\&. See the Linux docu for the difference between these types\&. +When you try to establish a tunnel between two TUN devices, their types +should be the same\&. +.IP "\fB\f(CWiff-no-pi\fP\fP" +Sets the IFF_NO_PI flag which controls if the device includes additional +packet information in the tunnel\&. +When you try to establish a tunnel between two TUN devices, these flags +should have the same values\&. +.IP "\fB\f(CWiff-up\fP\fP" +Sets the TUN network interface status UP\&. Strongly recommended\&. +.IP "\fB\f(CWiff-broadcast\fP\fP" +Sets the BROADCAST flag of the TUN network interface\&. +.IP "\fB\f(CWiff-debug\fP\fP" +Sets the DEBUG flag of the TUN network interface\&. +.IP "\fB\f(CWiff-loopback\fP\fP" +Sets the LOOPBACK flag of the TUN network interface\&. +.IP "\fB\f(CWiff-pointopoint\fP\fP" +Sets the POINTOPOINT flag of the TUN device\&. +.IP "\fB\f(CWiff-notrailers\fP\fP" +Sets the NOTRAILERS flag of the TUN device\&. +.IP "\fB\f(CWiff-running\fP\fP" +Sets the RUNNING flag of the TUN device\&. +.IP "\fB\f(CWiff-noarp\fP\fP" +Sets the NOARP flag of the TUN device\&. +.IP "\fB\f(CWiff-promisc\fP\fP" +Sets the PROMISC flag of the TUN device\&. +.IP "\fB\f(CWiff-allmulti\fP\fP" +Sets the ALLMULTI flag of the TUN device\&. +.IP "\fB\f(CWiff-master\fP\fP" +Sets the MASTER flag of the TUN device\&. +.IP "\fB\f(CWiff-slave\fP\fP" +Sets the SLAVE flag of the TUN device\&. +.IP "\fB\f(CWiff-multicast\fP\fP" +Sets the MULTICAST flag of the TUN device\&. +.IP "\fB\f(CWiff-portsel\fP\fP" +Sets the PORTSEL flag of the TUN device\&. +.IP "\fB\f(CWiff-automedia\fP\fP" +Sets the AUTOMEDIA flag of the TUN device\&. +.IP "\fB\f(CWiff-dynamic\fP\fP" +Sets the DYNAMIC flag of the TUN device\&. +.PP +.br +.PP +.SH "DATA VALUES" +.PP +This section explains the different data types that address parameters and +address options can take\&. +.PP +.IP "address-range" +Is currently only implemented for IPv4 and IPv6\&. See address-option +`range\' +.IP "bool" +"0" or "1"; if value is omitted, "1" is taken\&. +.IP "byte" +An unsigned int number, read with \f(CWstrtoul()\fP, lower or equal to +\f(CWUCHAR_MAX\fP\&. +.IP "command-line" +A string specifying a program name and its arguments, separated by single +spaces\&. +.IP "data" +A raw data specification following \fIdalan\fP syntax\&. The only documented +form is a string starting with \'x\' followed by an even number of hex digits\&. +.IP "directory" +A string with usual UN*X directory name semantics\&. +.IP "facility" +The name of a syslog facility in lower case characters\&. +.IP "fdnum" +An unsigned int type, read with \f(CWstrtoul()\fP, specifying a UN*X file +descriptor\&. +.IP "filename" +A string with usual UN*X filename semantics\&. +.IP "group" +If the first character is a decimal digit, the value is read with +\f(CWstrtoul()\fP as unsigned integer specifying a group id\&. Otherwise, it +must be an existing group name\&. +.IP "int" +A number following the rules of the \f(CWstrtol()\fP function with base +"0", i\&.e\&. decimal number, octal number with leading "0", or hexadecimal +number with leading "0x"\&. The value must fit into a C int\&. +.IP "interface" +A string specifying the device name of a network interface, e\&.g\&. "eth0"\&. +.IP "IP address" +An IPv4 address in numbers-and-dots notation, an IPv6 address in hex +notation enclosed in brackets, or a hostname that resolves to an IPv4 or an +IPv6 address\&. +.br +Examples: 127\&.0\&.0\&.1, [::1], www\&.dest-unreach\&.org, dns1 +.IP "IPv4 address" +An IPv4 address in numbers-and-dots notation or a hostname that resolves to +an IPv4 address\&. +.br +Examples: 127\&.0\&.0\&.1, www\&.dest-unreach\&.org, dns2 +.IP "IPv6 address" +An iPv6 address in hexnumbers-and-colons notation enclosed in brackets, or a +hostname that resolves to an IPv6 address\&. +.br +Examples: [::1], [1234:5678:9abc:def0:1234:5678:9abc:def0], +ip6name\&.domain\&.org +.IP "long" +A number read with \f(CWstrtol()\fP\&. The value must fit into a C long\&. +.IP "long long" +A number read with \f(CWstrtoll()\fP\&. The value must fit into a C long long\&. +.IP "off_t" +An implementation dependend signed number, usually 32 bits, read with strtol +or strtoll\&. +.IP "off64_t" +An implementation dependend signed number, usually 64 bits, read with strtol +or strtoll\&. +.IP "mode_t" +An unsigned integer, read with \f(CWstrtoul()\fP, specifying mode (permission) +bits\&. +.IP "pid_t" +A number, read with \f(CWstrtol()\fP, specifying a process id\&. +.IP "port" +A uint16_t (16 bit unsigned number) specifying a TCP or UDP port, read +with \f(CWstrtoul()\fP\&. +.IP "protocol" +An unsigned 8 bit number, read with \f(CWstrtoul()\fP\&. +.IP "size_t" +An unsigned number with size_t limitations, read with \f(CWstrtoul\fP\&. +.IP "sockname" +A socket address\&. See address-option `bind\' +.IP "string" +A sequence of characters, not containing \'\e0\' and, depending on +the position within the command line, \':\', \',\', or "!!"\&. Note +that you might have to escape shell meta characters in the command line\&. +.IP "TCP service" +A service name, not starting with a digit, that is resolved by +\f(CWgetservbyname()\fP, or an unsigned int 16 bit number read with +\f(CWstrtoul()\fP\&. +.IP "timeval" +A double float specifying seconds; the number is mapped into a +struct timeval, consisting of seconds and microseconds\&. +.IP "timespec" +A double float specifying seconds; the number is mapped into a +struct timespec, consisting of seconds and nanoseconds\&. +.IP "UDP service" +A service name, not starting with a digit, that is resolved by +\f(CWgetservbyname()\fP, or an unsigned int 16 bit number read with +\f(CWstrtoul()\fP\&. +.IP "unsigned int" +A number read with \f(CWstrtoul()\fP\&. The value must fit into a C unsigned +int\&. +.IP "user" +If the first character is a decimal digit, the value is read with +\f(CWstrtoul()\fP as unsigned integer specifying a user id\&. Otherwise, it must +be an existing user name\&. +.PP +.SH "EXAMPLES" +.PP +.IP +.IP "\fB\f(CWsocat - TCP4:www\&.domain\&.org:80\fP\fP" +.IP +Transfers data between STDIO (-) and a +TCP4 connection to port 80 of host +www\&.domain\&.org\&. This example results in an interactive connection similar to +telnet or netcat\&. The stdin terminal parameters are not changed, so you may +close the relay with ^D or abort it with ^C\&. +.IP +\.LP +\.nf +\fBsocat -d -d READLINE,history=$HOME/.http_history \\ +TCP4:www.domain.org:www,crnl\fP +\.fi +.IP +.IP +This is similar to the previous example, but you can edit the current line in a +bash like manner (READLINE) and use the +history file \&.http_history; \fBsocat\fP +prints messages about progress (-d -d)\&. The port is specified by service name +(www), and correct network line termination characters (crnl) instead of NL +are used\&. +.IP +.IP "\fB\f(CWsocat TCP4-LISTEN:www TCP4:www\&.domain\&.org:www\fP\fP" +.IP +Installs a simple TCP port forwarder\&. With +TCP4-LISTEN it listens on local port "www" until a +connection comes in, accepts it, then connects to the remote host +(TCP4) and starts data transfer\&. It will not accept a +second connection\&. +.IP +\.LP +\.nf +\fBsocat -d -d -lmlocal2 \\ +TCP4-LISTEN:80,bind=myaddr1,reuseaddr,fork,su=nobody,range=10.0.0.0/8 \\ +TCP4:www.domain.org:80,bind=myaddr2\fP +\.fi +.IP +.IP +TCP port forwarder, each side bound to another local IP address +(bind)\&. This example handles an almost +arbitrary number of parallel or consecutive connections by +fork\'ing a new +process after each \f(CWaccept()\fP\&. It provides a little security by +su\'ing to user +nobody after forking; it only permits connections from the private 10 network (range); +due to reuseaddr, it allows immediate restart after master process\'s +termination, even if some child sockets are not completely shut down\&. +With -lmlocal2, socat logs to stderr until successfully +reaching the accept loop\&. Further logging is directed to syslog with facility +local2\&. +.IP +\.LP +\.nf +\fBsocat TCP4-LISTEN:5555,fork,tcpwrap=script \\ +EXEC:/bin/myscript,chroot=/home/sandbox,su-d=sandbox,pty,stderr\fP +\.fi +.IP +.IP +A simple server that accepts connections +(TCP4-LISTEN) and fork\'s a new +child process for each connection; every child acts as single relay\&. +The client must match the rules for daemon process name "script" in +/etc/hosts\&.allow and /etc/hosts\&.deny, otherwise it is refused access (see "man +5 hosts_access")\&. +For EXEC\'uting the program, the child process +chroot\'s +to \fB/home/sandbox\fP, su\'s to user sandbox, and then starts +the program \fB/home/sandbox/bin/myscript\fP\&. \fBSocat\fP and +myscript communicate via a pseudo tty (pty); myscript\'s +stderr is redirected to stdout, +so its error messages are transferred via \fBsocat\fP to the connected client\&. +.IP +\.LP +\.nf +\fBsocat EXEC:"mail.sh target@domain.com",fdin=3,fdout=4 \\ +TCP4:mail.relay.org:25,crnl,bind=alias1.server.org,mss=512\fP +\.fi +.IP +.IP +\fBmail\&.sh\fP is a shell script, distributed with \fBsocat\fP, that implements a +simple +SMTP client\&. It is programmed to "speak" SMTP on its FDs 3 (in) and 4 (out)\&. +The fdin and fdout options tell \fBsocat\fP +to use these FDs for communication with +the program\&. Because mail\&.sh inherits stdin and stdout while \fBsocat\fP does not +use them, the script can read a +mail body from stdin\&. \fBSocat\fP makes alias1 your local source address +(bind), cares for correct network line termination +(crnl) and sends +at most 512 data bytes per packet (mss)\&. +.IP +.IP "\fB\f(CWsocat - /dev/ttyS0,raw,echo=0,crnl\fP\fP" +.IP +Opens an interactive connection via the serial line, e\&.g\&. for talking with a +modem\&. raw and echo set ttyS0\'s terminal +parameters to practicable values, crnl +converts to correct newline characters\&. Consider using +READLINE instead of `-\'\&. +.IP +\.LP +\.nf +\fBsocat UNIX-LISTEN:/tmp/.X11-unix/X1,fork \\ +SOCKS4:host.victim.org:127.0.0.1:6000,socksuser=nobody,sourceport=20\fP +\.fi +.IP +.IP +With UNIX-LISTEN, \fBsocat\fP opens a listening +UNIX domain socket \fB/tmp/\&.X11-unix/X1\fP\&. This path corresponds +to local XWindow display :1 on your machine, so XWindow client connections to +DISPLAY=:1 are accepted\&. \fBSocat\fP then speaks with +the SOCKS4 server host\&.victim\&.org that might permit +sourceport 20 based connections due to an FTP related +weakness in its static IP filters\&. \fBSocat\fP +pretends to be invoked by socksuser nobody, and +requests to be connected to +loopback port 6000 (only weak sockd configurations will allow this)\&. So we get +a connection to the victims XWindow server and, if it does not require MIT +cookies or Kerberos authentication, we can start work\&. Please note that there +can only be one connection at a time, because TCP can establish only one +session with a given set of addresses and ports\&. +.IP +.IP "\fB\f(CWsocat -u /tmp/readdata,seek-end=0,ignoreeof -\fP\fP" +.IP +This is an example for unidirectional data transfer +(-u)\&. \fBSocat\fP transfers data +from file /tmp/readdata (implicit address GOPEN), starting +at its current end (seek-end=0 lets \fBsocat\fP start +reading at current end of file; use seek=0 or no +seek option to first read the existing data) in a "tail -f" like mode +(ignoreeof)\&. The "file" +might also be a listening UNIX domain socket (do not use a seek option then)\&. +.IP +\.LP +\.nf +\fB(sleep 5; echo PASSWORD; sleep 5; echo ls; sleep 1) | +socat - EXEC:'ssh -l user server',pty,setsid,ctty\fP +\.fi +.IP +.IP +EXEC\'utes an ssh session to server\&. Uses a pty for communication between \fBsocat\fP and +ssh, makes it ssh\'s controlling tty (ctty), +and makes this pty the owner of +a new process group (setsid), so ssh accepts the password from \fBsocat\fP\&. +.IP +\.LP +\.nf +\fBsocat -u TCP4-LISTEN:3334,reuseaddr,fork \\ +OPEN:/tmp/in.log,creat,append\fP +\.fi +.IP +.IP +Implements a simple network based message collector\&. +For each client connecting to port 3334, a new child process is generated (option fork)\&. +All data sent by the clients are append\'ed to the file /tmp/in\&.log\&. +If the file does not exist, socat creat\'s it\&. +Option reuseaddr allows immediate restart of the server +process\&. +.IP +.IP +.IP "\fB\f(CWsocat READLINE,noecho=\'[Pp]assword:\' EXEC:\'ftp ftp\&.server\&.com\',pty,setsid,ctty\fP\fP" +.IP +Wraps a command line history (READLINE) around the EXEC\'uted ftp client utility\&. +This allows editing and reuse of FTP commands for relatively comfortable +browsing through the ftp directory hierarchy\&. The password is echoed! +pty is required to have ftp issue a prompt\&. +Nevertheless, there may occur some confusion with the password and FTP +prompts\&. +.IP +(\fB\f(CWsocat PTY,link=$HOME/dev/vmodem0,raw,echo=0,waitslave EXEC:\'"ssh modemserver\&.us\&.org socat - /dev/ttyS0,nonblock,raw,echo=0"\'\fP\fP) +.IP +Generates a pseudo terminal +device (PTY) on the client that can be reached under the +symbolic link \fB$HOME/dev/vmodem0\fP\&. +An application that expects a serial line or modem +can be configured to use \fB$HOME/dev/vmodem0\fP; its traffic will be directed +to a modemserver via ssh where another socat instance links it with +\fB/dev/ttyS0\fP\&. +.IP +\.LP +\.nf +\fBsocat TCP4-LISTEN:2022,reuseaddr,fork \\ +PROXY:proxy:www.domain.org:22,proxyport=3128,proxyauth=user:pass\fP +\.fi +.IP +.IP +starts a forwarder that accepts connections on port 2022, and directs them +through the proxy daemon listening on port 3128 +(proxyport) on host proxy, using the +CONNECT method, where they are authenticated as "user" with "pass" (proxyauth)\&. The proxy +should establish connections to host www\&.domain\&.org on port 22 then\&. +.IP +.IP "\fB\f(CWsocat - SSL:server:4443,cafile=server\&.crt,cert=client\&.pem\fP\fP" +.IP +is an OpenSSL client that tries to establish a secure connection to an SSL +server\&. Option cafile specifies a file that +contains trust certificates: we trust the server only when it presents one of +these certificates and proofs that it owns the related private key\&. +Otherwise the connection is terminated\&. +With cert a file containing the client certificate +and the associated private key is specified\&. This is required in case the +server wishes a client authentication; many Internet servers do not\&. +.br +The first address (\'-\') can be replaced by almost any other socat address\&. +.IP +.IP "\fB\f(CWsocat SSL-LISTEN:4443,reuseaddr,pf=ip4,fork,cert=server\&.pem,cafile=client\&.crt PIPE\fP\fP" +.IP +is an OpenSSL server that accepts TCP connections, presents the certificate +from the file server\&.pem and forces the client to present a certificate that is +verified against cafile\&.crt\&. +.br +The second address (\'PIPE\') can be replaced by almost any other socat +address\&. +.br +For instructions on generating and distributing OpenSSL keys and certificates +see the additional socat docu \f(CWsocat-openssl\&.txt\fP\&. +.IP +.IP "\fB\f(CWecho |socat -u - file:/tmp/bigfile,create,largefile,seek=100000000000\fP\fP" +.IP +creates a 100GB sparse file; this requires a file system type that +supports this (ext2, ext3, reiserfs, jfs; not minix, vfat)\&. The operation of +writing 1 byte might take long (reiserfs: some minutes; ext2: "no" time), and +the resulting file can consume some disk space with just its inodes (reiserfs: +2MB; ext2: 16KB)\&. +.IP +.IP "\fB\f(CWsocat tcp-l:7777,reuseaddr,fork system:\'filan -i 0 -s >&2\',nofork\fP\fP" +.IP +listens for incoming TCP connections on port 7777\&. For each accepted +connection, invokes a shell\&. This shell has its stdin and stdout directly +connected to the TCP socket (nofork)\&. The shell starts filan and lets it print the socket addresses to +stderr (your terminal window)\&. +.IP +.IP "\fB\f(CWecho -e "\e0\e14\e0\e0\ec" |socat -u - file:/usr/bin/squid\&.exe,seek=0x00074420\fP\fP" +.IP +functions as primitive binary editor: it writes the 4 bytes 000 014 000 000 to +the executable /usr/bin/squid at offset 0x00074420 (this is a real world patch +to make the squid executable from Cygwin run under Windows, actual per May 2004)\&. +.IP +.IP "\fB\f(CWsocat - tcp:www\&.blackhat\&.org:31337,readbytes=1000\fP\fP" +.IP +connects to an unknown service and prevents being flooded\&. +.IP +.IP "\fB\f(CWsocat -U TCP:target:9999,end-close TCP-L:8888,reuseaddr,fork\fP\fP" +.IP +merges data arriving from different TCP streams on port 8888 to just one stream +to target:9999\&. The end-close option prevents the child +processes forked off by the second address from terminating the shared +connection to 9999 (close(2) just unlinks the inode which stays active as long +as the parent process lives; shutdown(2) would actively terminate the +connection)\&. +.IP +.IP "\fB\f(CWsocat - UDP4-DATAGRAM:192\&.168\&.1\&.0:123,sp=123,broadcast,range=192\&.168\&.1\&.0/24\fP\fP" +.IP +sends a broadcast to the network 192\&.168\&.1\&.0/24 and receives the replies of the +timeservers there\&. Ignores NTP packets from hosts outside this network\&. +.IP +.IP "\fB\f(CWsocat - IP4-DATAGRAM:255\&.255\&.255\&.255:44,broadcast,range=10\&.0\&.0\&.0/8\fP\fP" +.IP +sends a broadcast to the local network(s) using protocol 44\&. Accepts replies +from the private address range only\&. +.IP +.IP "\fB\f(CWsocat - UDP4-DATAGRAM:224\&.255\&.0\&.1:6666,bind=:6666,ip-add-membership=224\&.255\&.0\&.1:eth0\fP\fP" +.IP +transfers data from stdin to the specified multicast address using UDP\&. Both +local and remote ports are 6666\&. Tells the interface eth0 to also accept +multicast packets of the given group\&. Multiple hosts on the local network can +run this command, so all data sent by any of the hosts will be received +by all the other ones\&. Note that there are many possible reasons for failure, +including IP-filters, routing issues, wrong interface selection by the +operating system, bridges, or a badly configured switch\&. +.IP +.IP "\fB\f(CWsocat TCP:host2:4443 TUN:192\&.168\&.255\&.1/24,up\fP\fP" +.IP +establishes one side of a virtual (but not private!) network with host2 where a +similar process might run, with TCP-L and tun address 192\&.168\&.255\&.2\&. They +can reach each other using the addresses 192\&.168\&.255\&.1 and +192\&.168\&.255\&.2\&. Substitute the TCP link with an SSL connection protected by +client and server authentication (see OpenSSL +client and +server)\&. +.IP +.PP +.SH "DIAGNOSTICS" +.PP +\fBSocat\fP uses a logging mechanism that allows to filter messages by severity\&. The +severities provided are more or less compatible to the appropriate syslog +priority\&. With one or up to four occurrences of the -d command line option, the +lowest priority of messages that are issued can be selected\&. Each message +contains a single uppercase character specifying the messages severity (one of +F, E, W, N, I, or D) +.PP +.IP "FATAL:" +Conditions that require unconditional and immediate program termination\&. +.IP "ERROR:" +Conditions that prevent proper program processing\&. Usually the +program is terminated (see option -s)\&. +.IP "WARNING:" +Something did not function correctly or is in a state where +correct further processing cannot be guaranteed, but might be possible\&. +.IP "NOTICE:" +Interesting actions of the program, e\&.g\&. for supervising \fBsocat\fP in some kind of server mode\&. +.IP "INFO:" +Description of what the program does, and maybe why it +happens\&. Allows to monitor the lifecycles of file descriptors\&. +.IP "DEBUG:" +Description of how the program works, all system or library calls and their results\&. +.PP +Log messages can be written to stderr, to a file, or to syslog\&. +.PP +On exit, \fBsocat\fP gives status 0 if it terminated due to EOF or inactivity +timeout, with a positive value on error, and with a negative value on fatal +error\&. +.PP +.SH "FILES" +.PP +/usr/bin/socat +.br +/usr/bin/filan +.br +/usr/bin/procan +.PP +.SH "ENVIRONMENT VARIABLES" +.PP +.IP "\fBSOCAT_DEFAULT_LISTEN_IP\fP" +(Values 4 or 6) Sets the IP version to be used +for listen, recv, and recvfrom addresses if no pf +(protocol-family) option is given\&. Is overridden by socat options +-4 or -6\&. +.IP +.IP "\fBSOCAT_PREFERRED_RESOLVE_IP\fP" +(Values 0, 4, or 6) Sets the IP version to +be used when resolving target host names when version is not specified by +address type, option pf (protocol-family), or +address format\&. If name resolution does not return a matching entry, the first +result (with differing IP version) is taken\&. With value 0, socat always selects +the first record and its IP version\&. +.IP +.IP "\fBSOCAT_FORK_WAIT\fP" +Specifies the time (seconds) to sleep the parent and +child processes after successful fork()\&. Useful for debugging\&. +.IP +.IP "\fBHOSTNAME\fP" +Is used to determine the hostname for logging (see +-lh)\&. +.IP +.IP "\fBLOGNAME\fP" +Is used as name for the socks client user name if no +socksuser is given\&. +.br +With options su and +su-d, LOGNAME is set to the given user name\&. +.IP +.IP "\fBUSER\fP" +Is used as name for the socks client user name if no +socksuser is given and LOGNAME is empty\&. +.br +With options su and +su-d, USER is set to the given user name\&. +.IP +.IP "\fBSHELL\fP" +With options su and +su-d, SHELL is set to the login shell of the +given user\&. +.IP +.IP "\fBPATH\fP" +Can be set with option path for exec and +system addresses\&. +.IP +.IP "\fBHOME\fP" +With options su and +su-d, HOME is set to the home directory of the +given user\&. +.IP +.PP +.SH "CREDITS" +.PP +The work of the following groups and organizations was invaluable for this +project: +.PP +The \fIFSF\fP (GNU, http://www\&.fsf\&.org/ project +with their free and portable development software and +lots of other useful tools and libraries\&. +.PP +The \fILinux developers community\fP (http://www\&.linux\&.org/) for providing a free, open source operating +system\&. +.PP +The \fIOpen Group\fP (http://www\&.unix-systems\&.org/) for making their +standard specifications available on the Internet for free\&. +.PP +.SH "VERSION" +.PP +This man page describes version 1\&.6\&.0 of \fBsocat\fP\&. +.PP +.SH "BUGS" +.PP +Addresses cannot be nested, so a single socat process cannot, e\&.g\&., drive ssl +over socks\&. +.PP +Address option ftruncate without value uses default 1 instead of 0\&. +.PP +Verbose modes (-x and/or -v) display line termination characters inconsistently +when address options cr or crnl are used: They show the data \fIafter\fP +conversion in either direction\&. +.PP +The data transfer blocksize setting (-b) is ignored with address readline\&. +.PP +Send bug reports to +.PP +.SH "SEE ALSO" +.PP +nc(1), netcat6(1), sock(1), rinetd(8), cage(1), socks\&.conf(5), openssl(1), +stunnel(8), pty(1), rlwrap(1), setsid(1) +.PP +\fBSocat\fP home page http://www\&.dest-unreach\&.org/socat/ +.PP +.SH "AUTHOR" +.PP +Gerhard Rieger diff --git a/doc/socat.html b/doc/socat.html new file mode 100644 index 0000000..47e02fb --- /dev/null +++ b/doc/socat.html @@ -0,0 +1,2686 @@ + + + + + + + + + + + + + + + + +socat + + + + + +
+ +

socat

+

socat

+

March 2007

+ + + +

+ +

CONTENTS

+ +NAME
+SYNOPSIS
+DESCRIPTION
+OPTIONS
+ADDRESS SPECIFICATIONS
+ADDRESS TYPES
+ADDRESS OPTIONS
+DATA VALUES
+EXAMPLES
+DIAGNOSTICS
+FILES
+ENVIRONMENT VARIABLES
+CREDITS
+VERSION
+BUGS
+SEE ALSO
+

+

NAME

+ socat - Multipurpose relay (SOcket CAT) +

+

SYNOPSIS

+ +socat [options] <address> <address>
+socat -V
+socat -h[h[h]] | -?[?[?]]
+filan
+procan +

+

DESCRIPTION

+ +

Socat is a command line based utility that establishes two bidirectional byte +streams and transfers data between them. Because the streams can be constructed +from a large set of different types of data sinks and sources +(see address types), and because lots of +address options may be applied to the streams, socat can +be used for many different purposes. +It might be one of the tools that one `has already needed'. +

Filan is a utility that prints information about its active file +descriptors to stdout. It has been written for debugging socat, but might be +useful for other purposes too. Use the -h option to find more infos. +

Procan is a utility that prints information about process parameters to +stdout. It has been written to better understand +some UNIX process properties and for debugging socat, but might be +useful for other purposes too. +

The life cycle of a socat instance typically consists of four phases. +

In the init phase, the command line options are parsed and logging is +initialized. +

During the open phase, socat opens the first address and afterwards the +second address. These steps are usually blocking; thus, especially for complex address types like socks, +connection requests or authentication dialogs must be completed before the next +step is started. +

In the transfer phase, socat watches both streams' read and write file +descriptors via select(), and, when data is available on one side and +can be written to the other side, socat reads it, performs newline +character conversions if required, and writes the data to the write file +descriptor of the other stream, then continues waiting for more data in both +directions. +

When one of the streams effectively reaches EOF, the closing phase +begins. Socat transfers the EOF condition to the other stream, +i.e. tries to shutdown only its write stream, giving it a chance to +terminate gracefully. For a defined time socat continues to transfer data in +the other direction, but then closes all remaining channels and terminates. +

+

OPTIONS

+ +

Socat provides some command line options that modify the behaviour of the +program. They have nothing to do with so called +address options that are used as parts of address specifications. +

+

-V
+ Print version and available feature information to stdout, and exit. +

-h | -?
+ Print a help text to stdout describing command line options and available address + types, and exit. +

-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 + implementation. +

-hhh | -???
+ Like -hh, plus a list of all available address option names. +

-d
+ Without this option, only fatal and error messages are generated; applying + this option also prints warning messages. See DIAGNOSTICS + for more information. +

-d -d
Prints fatal, error, warning, and notice messages. +

-d -d -d
Prints fatal, error, warning, notice, and info messages. +

-d -d -d -d
Prints fatal, error, warning, notice, info, and debug + messages. +

-D
+ Logs information about file descriptors before starting the transfer phase. +

-ly[<facility>]
+ Writes messages to syslog instead of stderr; severity as defined with -d + option. With optional <facility>, the syslog type can + be selected, default is "daemon". +

-lf <logfile>
+ Writes messages to <logfile> [filename] instead of + stderr. +

-ls
+ Writes messages to stderr (this is the default). +

-lp<progname>
+ Overrides the program name printed in error messages. +

-lu
+ Extends the timestamp of error messages to microsecond resolution. Does not + work when logging to syslog. +

-lm[<facility>]
+ Mixed log mode. During startup messages are printed to stderr; when socat + starts the transfer phase loop or daemon mode (i.e. after opening all + streams and before starting data transfer, or, with listening sockets with + fork option, before the first accept call), it switches logging to syslog. + With optional <facility>, the syslog type can be + selected, default is "daemon". +

-lh
+ Adds hostname to log messages. Uses the value from environment variable + HOSTNAME or the value retrieved with uname() if HOSTNAME is not set. +

-v
+ Writes the transferred data not only to their target streams, but also to + stderr. The output format is text with some conversions for readability, and + prefixed with "> " or "< " indicating flow directions. +

-x
+ Writes the transferred data not only to their target streams, but also to + stderr. The output format is hexadecimal, prefixed with "> " or "< " + indicating flow directions. Can be combined with -v. +

-b<size>
+ Sets the data transfer block <size> [size_t]. + At most <size> bytes are transferred per step. Default is 8192 bytes. +

-s
+ By default, socat terminates when an error occurred to prevent the process + from running when some option could not be applied. With this + option, socat is sloppy with errors and tries to continue. Even with this + option, socat will exit on fatals, and will abort connection attempts when + security checks failed. +

-t<timeout>
+ When one channel has reached EOF, the write part of the other channel is shut + down. Then, socat waits <timeout> [timeval] seconds + before terminating. Default is 0.5 seconds. This timeout only applies to + addresses where write and read part can be closed independently. When during + the timeout intervall the read part gives EOF, socat terminates without + awaiting the timeout. +

-T<timeout>
+ Total inactivity timeout: when socat is already in the transfer loop and + nothing has happened for <timeout> [timeval] seconds + (no data arrived, no interrupt occurred...) then it terminates. + Useful with protocols like UDP that cannot transfer EOF. +

-u
+ Uses unidirectional mode. The first address is only used for reading, and the + second address is only used for writing (example). +

-U
+ Uses unidirectional mode in reverse direction. The first address is only + used for writing, and the second address is only used for reading. +

-g
+ During address option parsing, don't check if the option is considered + useful in the given address environment. Use it if you want to force, e.g., + appliance of a socket option to a serial device. +

-L<lockfile>
+ If lockfile exists, exits with error. If lockfile does not exist, creates it + and continues, unlinks lockfile on exit. +

-W<lockfile>
+ If lockfile exists, waits until it disappears. When lockfile does not exist, + creates it and continues, unlinks lockfile on exit. +

-4
+ Use IP version 4 in case that the addresses do not implicitly or explicitly + specify a version; this is the default. +

-6
+ Use IP version 6 in case that the addresses do not implicitly or explicitly + specify a version. +
+

+

ADDRESS SPECIFICATIONS

+ +

With the address command line arguments, the user gives socat instructions and +the necessary information for establishing the byte streams. +

An address specification usually consists of an address type +keyword, zero or more required address parameters separated by ':' from the keyword and +from each +other, and zero or more address options separated by ','. +

The keyword specifies the address type (e.g., TCP4, OPEN, EXEC). For some +keywords there exist synonyms ('-' for STDIO, TCP for TCP4). Keywords are case +insensitive. +For a few special address types, the keyword may be omitted: +Address specifications starting with a number are assumed to be FD (raw file +descriptor) addresses; +if a '/' is found before the first ':' or ',', GOPEN (generic file open) is +assumed. +

The required number and type of address parameters depend on the address +type. E.g., TCP4 requires a server specification (name or address), and a port +specification (number or service name). +

Zero or more address options may be given with each address. They influence the +address in some ways. +Options consist of an option keyword or an option keyword and a value, +separated by '='. Option keywords are case insensitive. +For filtering the options that are useful with an address +type, each option is member of one option group. For +each address type there is a set of option groups allowed. Only options +belonging to one of these address groups may be used (except with option -g). +

+Address specifications following the above schema are also called single +address specifications. +Two single addresses can be combined with "!!" to form a dual type +address for one channel. Here, the first address is used by socat for reading +data, and the +second address for writing data. There is no way to specify an option only once +for being applied to both single addresses. +

Usually, addresses are opened in read/write +mode. When an address is part of a dual address specification, or when +option -u or -U is used, an address might be +used only for reading or for writing. Considering this is important with some +address types. +

With socat version 1.5.0 and higher, the lexical analysis tries to handle +quotes and parenthesis meaningfully and allows escaping of special characters. +If one of the characters ( { [ ' is found, the corresponding closing +character - ) } ] ' - is looked for; they may also be nested. Within these +constructs, socats special characters and strings : , !! are not handled +specially. All those characters and strings can be escaped with \ or within "" +

+

ADDRESS TYPES

+ +

This section describes the available address types with their keywords, +parameters, and semantics. +

+

CREATE:<filename>
+ Opens <filename> with creat() and uses the file + descriptor for writing. + This address type requires write-only context, because a file opened with + creat cannot be read from. + <filename> must be a valid existing or not existing path. + If <filename> is a named pipe, creat() might block; + if <filename> refers to a socket, this is an error.
+ Option groups: FD,REG,NAMED
+ Useful options: + mode, + user, + group, + unlink-early, + unlink-late, + append
+ See also: OPEN, GOPEN +

EXEC:<command-line>
+ Forks a sub process that establishes communication with its parent process + and invokes the specified program with execvp(). + <command-line> is a simple command + with arguments separated by single spaces. If the program name + contains a '/', the part after the last '/' is taken as ARGV[0]. If the + program name is a relative + path, the execvp() semantics for finding the program via + $PATH + apply. After successful program start, socat writes data to stdin of the + process and reads from its stdout using a UNIX domain socket generated by + socketpair() per default. (example)
+ Option groups: FD,SOCKET,EXEC,FORK,TERMIOS
+ Useful options: + path, + fdin, + fdout, + chroot, + su, + su-d, + nofork, + pty, + stderr, + ctty, + setsid, + pipes, + login, + sigint, + sigquit
+ See also: SYSTEM +

FD:<fdnum>
+ Uses the file descriptor <fdnum>. It must already exist as + valid UN*X file descriptor.
+ Option groups: FD (TERMIOS,REG,SOCKET)
+ See also: + STDIO, + STDIN, + STDOUT, + STDERR +

GOPEN:<filename>
+ (Generic open) This address type tries to handle any file system entry + except directories usefully. <filename> may be a + relative or absolute path. If it already exists, its type is checked. + In case of a UNIX domain socket, socat connects; if connecting fails, + socat assumes a datagram socket and uses sendto() calls. + If the entry is not a socket, socat opens it applying the O_APPEND + flag. + If it does not exist, it is opened with flag + O_CREAT as a regular file (example).
+ Option groups: FD,REG,SOCKET,NAMED,OPEN
+ See also: + OPEN, + CREATE, + UNIX-CONNECT +

IP-SENDTO:<host>:<protocol>
+ Opens a raw IP socket. Depending on host specification or option pf, IP procotol version + 4 or 6 is used. It uses <protocol> to send packets + to <host> [IP address] and receives packets from + host, ignores packets from other hosts. + Protocol 255 uses the raw socket with the IP header being part of the + data.
+ Option groups: FD,SOCKET,IP4,IP6
+ Useful options: + pf, + ttl + See also: + IP4-SENDTO, + IP6-SENDTO, + IP-RECVFROM, + IP-RECV, + UDP-SENDTO + UNIX-SENDTO +

IP4-SENDTO:<host>:<protocol>
+ Like IP-SENDTO, but always uses IPv4.
+ Option groups: FD,SOCKET,IP4
+

IP6-SENDTO:<host>:<protocol>
+ Like IP-SENDTO, but always uses IPv6.
+ Option groups: FD,SOCKET,IP6
+

IP-DATAGRAM:<address>:<protocol>
+ Sends outgoing data to the specified address which may in particular be a + broadcast or multicast address. Packets arriving on the local socket are + checked if their source addresses match + eventual RANGE or TCPWRAP + options. This address type can for example be used for implementing + symmetric or asymmetric broadcast or multicast communications.
+ Option groups: FD, SOCKET, + IP4, IP6, RANGE
+ Useful options: + range, + tcpwrap, + broadcast, + ip-multicast-loop, + ip-multicast-ttl, + ip-multicast-if, + ip-add-membership, + ttl, + tos, + bind, + pf
+ See also: + IP4-DATAGRAM, + IP6-DATAGRAM, + IP-SENDTO, + IP-RECVFROM, + IP-RECV, + UDP-DATAGRAM +

IP4-DATAGRAM:<host>:<protocol>
+ Like IP-DATAGRAM, but always uses IPv4. + (example)
+ Option groups: FD, SOCKET, + IP4, RANGE
+

IP6-DATAGRAM:<host>:<protocol>
+ Like IP-DATAGRAM, but always uses IPv6. Please + note that IPv6 does not know broadcasts.
+ Option groups: FD, SOCKET, + IP6, RANGE
+

IP-RECVFROM:<protocol>
+ Opens a raw IP socket of <protocol>. Depending on option pf, IP procotol version + 4 or 6 is used. It receives one packet from an unspecified peer and may send one or more answer packets to that peer. + This mode is particularly useful with fork option where each arriving packet - from arbitrary peers - is handled by its own sub process. + This allows a behaviour similar to typical UDP based servers like ntpd or named. + This address works well with IP-SENDTO address peers (see above). + Protocol 255 uses the raw socket with the IP header being part of the + data.
+ Option groups: FD,SOCKET,IP4,IP6,CHILD,RANGE
+ Useful options: + pf, + fork, + range, + ttl, + broadcast
+ See also: + IP4-RECVFROM, + IP6-RECVFROM, + IP-SENDTO, + IP-RECV, + UDP-RECVFROM, + UNIX-RECVFROM +

IP4-RECVFROM:<protocol>
+ Like IP-RECVFROM, but always uses IPv4.
+ Option groups: FD,SOCKET,IP4,CHILD,RANGE
+

IP6-RECVFROM:<protocol>
+ Like IP-RECVFROM, but always uses IPv6.
+ Option groups: FD,SOCKET,IP6,CHILD,RANGE
+

IP-RECV:<protocol>
+ Opens a raw IP socket of <protocol>. Depending on option pf, IP procotol version + 4 or 6 is used. It receives packets from multiple unspecified peers and merges the data. + No replies are possible. + It can be, e.g., addressed by socat IP-SENDTO address peers. + Protocol 255 uses the raw socket with the IP header being part of the + data.
+ Option groups: FD,SOCKET,IP4,IP6,RANGE
+ Useful options: + pf, + range
+ See also: + IP4-RECV, + IP6-RECV, + IP-SENDTO, + IP-RECVFROM, + UDP-RECV, + UNIX-RECV +

IP4-RECV:<protocol>
+ Like IP-RECV, but always uses IPv4.
+ Option groups: FD,SOCKET,IP4,RANGE
+

IP6-RECV:<protocol>
+ Like IP-RECV, but always uses IPv6.
+ Option groups: FD,SOCKET,IP6,RANGE
+

OPEN:<filename>
+ Opens <filename> using the open() system call + (example). + This operation fails on UNIX domain sockets.
+ Note: This address type is rarly useful in bidirectional mode.
+ Option groups: FD,REG,NAMED,OPEN
+ Useful options: + creat, + excl, + noatime, + nofollow, + append, + rdonly, + wronly, + lock, + readbytes, + ignoreeof
+ See also: + CREATE, + GOPEN, + UNIX-CONNECT +

OPENSSL:<host>:<port>
+ Tries to establish a SSL connection to <port> [TCP + service] on + <host> [IP address] using TCP/IP version 4 or 6 + depending on address specification, name resolution, or option + pf.
+ NOTE: The server certificate is only checked for validity against + cafile or capath, + but not for match with the server's name or its IP address!
+ Option groups: FD,SOCKET,IP4,IP6,TCP,OPENSSL,RETRY
+ Useful options: + cipher, + method, + verify, + cafile, + capath, + certificate, + bind, + pf, + connect-timeout, + sourceport, + retry
+ See also: + OPENSSL-LISTEN, + TCP +

OPENSSL-LISTEN:<port>
+ Listens on tcp <port> [TCP service]. + The IP version is 4 or the one specified with + pf. When a + connection is accepted, this address behaves as SSL server.
+ Note: You probably want to use the certificate option with this address.
+ NOTE: The client certificate is only checked for validity against + cafile or capath, + but not for match with the client's name or its IP address!
+ Option groups: FD,SOCKET,IP4,IP6,TCP,LISTEN,OPENSSL,CHILD,RANGE,RETRY
+ Useful options: + pf, + cipher, + method, + verify, + cafile, + capath, + certificate, + fork, + bind, + range, + tcpwrap, + su, + reuseaddr, + retry
+ See also: + OPENSSL, + TCP +

PIPE:<filename>
+ If <filename> already exists, it is opened. + If is does not exist, a named pipe is created and opened. Beginning with + socat version 1.4.3, the named pipe is removed when the address is closed + (but see option unlink-close
+ Note: When a pipe is used for both reading and writing, it works + as echo service.
+ Note: When a pipe is used for both reading and writing, and socat tries + to write more bytes than the pipe can buffer (Linux 2.4: 2048 bytes), socat + might block. Consider using socat option, e.g., -b 2048
+ Option groups: FD,NAMED,OPEN
+ Useful options: + rdonly, + nonblock, + group, + user, + mode, + unlink-early
+ See also: unnamed pipe +

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 data.
+ 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 + option -b 2048
+ Option groups: FD
+ See also: named pipe +

PROXY:<proxy>:<hostname>:<port>
+ Connects to an HTTP proxy server on port 8080 using TCP/IP version 4 or 6 + depending on address specification, name resolution, or option + pf, and sends a CONNECT + request for hostname:port. If the proxy grants access and succeeds to + connect to the target, data transfer between socat and the target can + start. Note that the traffic need not be HTTP but can be an arbitrary + protocol.
+ Option groups: FD,SOCKET,IP4,IP6,TCP,HTTP,RETRY
+ Useful options: + proxyport, + ignorecr, + proxyauth, + resolve, + crnl, + bind, + connect-timeout, + mss, + sourceport, + retry
+ See also: SOCKS, TCP +

PTY
+ Generates a pseudo terminal (pty) and uses its master side. Another process + may open the pty's slave side using it like a serial line or terminal. + (example). If + both the ptmx and the openpty mechanisms are available, ptmx is used + (POSIX).
+ Option groups: FD,NAMED,PTY,TERMIOS
+ Useful options: + link, + openpty, + wait-slave, + mode, + user, + group
+ See also: + UNIX-LISTEN, + PIPE, + EXEC, SYSTEM +

READLINE
+ Uses GNU readline and history on stdio to allow editing and reusing input + lines (example). This requires the GNU readline and + history libraries. Note that stdio should be a (pseudo) terminal device, + otherwise readline does not seem to work.
+ Option groups: FD,READLINE,TERMIOS
+ Useful options: + history, + noecho
+ See also: + STDIO +

SOCKS4:<socks-server>:<host>:<port>
+ Connects via <socks-server> [IP address] + to <host> [IPv4 address] + on <port> [TCP service], + using socks version 4 protocol over IP version 4 or 6 depending on address specification, name resolution, or option + pf (example).
+ Option groups: FD,SOCKET,IP4,IP6,TCP,SOCKS4,RETRY
+ Useful options: + socksuser, + socksport, + sourceport, + pf, + retry
+ See also: + SOCKS4A, + PROXY, + TCP +

SOCKS4A:<socks-server>:<host>:<port>
+ like SOCKS4, but uses socks protocol version 4a, thus + leaving host name resolution to the socks server.
+ Option groups: FD,SOCKET,IP4,IP6,TCP,SOCKS4,RETRY
+

STDERR
+ Uses file descriptor 2.
+ Option groups: FD (TERMIOS,REG,SOCKET)
+ See also: FD +

STDIN
+ Uses file descriptor 0.
+ Option groups: FD (TERMIOS,REG,SOCKET)
+ Useful options: + readbytes
+ See also: FD +

STDIO
+ Uses file descriptor 0 for reading, and 1 for writing.
+ Option groups: FD (TERMIOS,REG,SOCKET)
+ Useful options: + readbytes
+ See also: FD +

STDOUT
+ Uses file descriptor 1.
+ Option groups: FD (TERMIOS,REG,SOCKET)
+ See also: FD +

SYSTEM:<shell-command>
+ Forks a sub process that establishes communication with its parent process + and invokes the specified program with system(). Please note that + <shell-command> [string] must + not contain ',' or "!!", and that shell meta characters may have to be + protected. + After successful program start, socat writes data to stdin of the + process and reads from its stdout.
+ Option groups: FD,SOCKET,EXEC,FORK,TERMIOS
+ Useful options: + path, + fdin, + fdout, + chroot, + su, + su-d, + nofork, + pty, + stderr, + ctty, + setsid, + pipes, + sigint, + sigquit
+ See also: EXEC +

TCP:<host>:<port>
+ Connects to <port> [TCP service] on + <host> [IP address] using TCP/IP version 4 or 6 + depending on address specification, name resolution, or option + pf.
+ Option groups: FD,SOCKET,IP4,IP6,TCP,RETRY
+ Useful options: + crnl, + bind, + pf, + connect-timeout, + tos, + mtudiscover, + mss, + nodelay, + nonblock, + sourceport, + retry, + readbytes
+ See also: + TCP4, + TCP6, + TCP-LISTEN, + UDP, + UNIX-CONNECT +

TCP4:<host>:<port>
+ Like TCP, but only supports IPv4 protocol (example).
+ Option groups: FD,SOCKET,IP4,TCP,RETRY
+

TCP6:<host>:<port>
+ Like TCP, but only supports IPv6 protocol.
+ Option groups: FD,SOCKET,IP6,TCP,RETRY
+

TCP-LISTEN:<port>
+ Listens on <port> [TCP service] and accepts a + TCP/IP connection. The IP version is 4 or the one specified with + pf. + Note that opening + this address usually blocks until a client connects.
+ Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP4,IP6,TCP,RETRY
+ Useful options: + crnl, + fork, + bind, + range, + tcpwrap, + pf, + backlog, + mss, + su, + reuseaddr, + retry, + retry
+ See also: + TCP4-LISTEN, + TCP6-LISTEN, + UDP-LISTEN, + UNIX-LISTEN, + OPENSSL-LISTEN +

TCP4-LISTEN:<port>
+ Like TCP-LISTEN, but only supports IPv4 + protocol (example).
+ Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP4,TCP,RETRY
+

TCP6-LISTEN:<port>
+ Like TCP-LISTEN, but only supports IPv6 + protocol.
+ Additional useful option: + ipv6only
+ Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP6,TCP,RETRY
+

TUN:<if-addr>/<bits>
+ Creates a Linux TUN/TAP device and assignes to it the address and netmask + defined by the parameters. The resulting network interface is ready for use + by other processes; socat serves its "wire side". This address requires read + and write access to the tunnel cloning device, usually /dev/net/tun. +
+ Option groups: FD,NAMED,OPEN,TUN
+ Useful options: + iff-up, + tun-device, + tun-name, + tun-type, + iff-no-pi
+ See also: + ip-recv +

UDP:<host>:<port>
+ Connects to <port> [UDP service] on + <host> [IP address] using UDP/IP version 4 or 6 + depending on address specification, name resolution, or option + pf.
+ Please note that, + due to UDP protocol properties, no real connection is established; data has + to be sent for `connecting' to the server, and no end-of-file condition can + be transported.
+ Option groups: FD,SOCKET,IP4,IP6
+ Useful options: + ttl, + tos, + bind, + sourceport, + pf
+ See also: + UDP4, + UDP6, + UDP-LISTEN, + TCP, + IP +

UDP4:<host>:<port>
+ Like UDP, but only supports IPv4 protocol.
+ Option groups: FD,SOCKET,IP4
+

UDP6:<host>:<port>
+ Like UDP, but only supports IPv6 protocol.
+ Option groups: FD,SOCKET,IP6
+

UDP-DATAGRAM:<address>:<port>
+ Sends outgoing data to the specified address which may in particular be a + broadcast or multicast address. Packets arriving on the local socket are + checked for the correct remote port and if their source addresses match + eventual RANGE or TCPWRAP + options. This address type can for example be used for implementing + symmetric or asymmetric broadcast or multicast communications.
+ Option groups: FD,SOCKET,IP4,IP6,RANGE
+ Useful options: + range, + tcpwrap, + broadcast, + ip-multicast-loop, + ip-multicast-ttl, + ip-multicast-if, + ip-add-membership, + ttl, + tos, + bind, + sourceport, + pf
+ See also: + UDP4-DATAGRAM, + UDP6-DATAGRAM, + UDP-SENDTO, + UDP-RECVFROM, + UDP-RECV, + UDP-CONNECT, + UDP-LISTEN, + IP-DATAGRAM +

UDP4-DATAGRAM:<address>:<port>
+ Like UDP-DATAGRAM, but only supports IPv4 + protocol (example1, + example2).
+ Option groups: FD, SOCKET, + IP4, RANGE +

UDP6-DATAGRAM:<address>:<port>
+ Like UDP-DATAGRAM, but only supports IPv6 + protocol.
+ Option groups: FD,SOCKET, + IP6,RANGE +

UDP-LISTEN:<port>
+ Waits for a UDP/IP packet arriving on <port> + [UDP service] and `connects' back to sender. + The accepted IP version is 4 or the one specified with option + pf. + Please note that, + due to UDP protocol properties, no real connection is established; data has + to arrive from the peer first, and no end-of-file condition can be + transported. Note that opening + this address usually blocks until a client connects.
+ Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP4,IP6
+ Useful options: + fork, + bind, + range, + pf
+ See also: + UDP, + UDP4-LISTEN, + UDP6-LISTEN, + TCP-LISTEN +

UDP4-LISTEN:<port>
+ Like UDP-LISTEN, but only support IPv4 + protocol.
+ Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP4
+

UDP6-LISTEN:<port>
+ Like UDP-LISTEN, but only support IPv6 + protocol.
+ Option groups: FD,SOCKET,LISTEN,CHILD,RANGE,IP6
+

UDP-SENDTO:<host>:<port>
+ Communicates with the specified peer socket, defined by <port> [UDP + service] on + <host> [IP address], using UDP/IP version 4 or 6 + depending on address specification, name resolution, or option + pf. 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.
+ Option groups: FD,SOCKET,IP4,IP6
+ Useful options: + ttl, + tos, + bind, + sourceport, + pf
+ See also: + UDP4-SENDTO, + UDP6-SENDTO, + UDP-RECVFROM, + UDP-RECV, + UDP-CONNECT, + UDP-LISTEN, + IP-SENDTO +

UDP4-SENDTO:<host>:<port>
+ Like UDP-SENDTO, but only supports IPv4 + protocol.
+ Option groups: FD,SOCKET,IP4 +

UDP6-SENDTO:<host>:<port>
+ Like UDP-SENDTO, but only supports IPv6 + protocol.
+ Option groups: FD,SOCKET,IP6 +

UDP-RECVFROM:<port>
+ Creates a UDP socket on <port> [UDP service] using + UDP/IP version 4 or 6 + depending on option pf. + It receives one packet from an unspecified peer and may send one or more + answer packets to that peer. This mode is particularly useful with fork + option + where each arriving packet - from arbitrary peers - is handled by its own sub + process. This allows a behaviour similar to typical UDP based servers like ntpd + or named. This address works well with socat SENDTO address peers.
+ Option groups: FD,SOCKET,IP4,IP6,CHILD,RANGE
+ Useful options: + fork, + ttl, + tos, + bind, + sourceport, + pf
+ See also: + UDP4-RECVFROM, + UDP6-RECVFROM, + UDP-SENDTO, + UDP-RECV, + UDP-CONNECT, + UDP-LISTEN, + IP-RECVFROM, + UNIX-RECVFROM +

UDP4-RECVFROM:<port>
+ Like UDP-RECVFROM, but only supports IPv4 protocol.
+ Option groups: FD,SOCKET,IP4,CHILD,RANGE +

UDP6-RECVFROM:<port>
+ Like UDP-RECVFROM, but only supports IPv6 protocol.
+ Option groups: FD,SOCKET,IP6,CHILD,RANGE +

UDP-RECV:<port>
+ Creates a UDP socket on <port> [UDP service] using UDP/IP version 4 or 6 + depending on option pf. + It receives packets from multiple unspecified peers and merges the data. + No replies are possible. It works well with, e.g., socat UDP-SENDTO address peers; it behaves similar to a syslog server.
+ Option groups: FD,SOCKET,IP4,IP6,RANGE
+ Useful options: + fork, + pf, + bind, + sourceport, + ttl, + tos
+ See also: + UDP4-RECV, + UDP6-RECV, + UDP-SENDTO, + UDP-RECVFROM, + UDP-CONNECT, + UDP-LISTEN, + IP-RECV, + UNIX-RECV +

UDP4-RECV:<port>
+ Like UDP-RECV, but only supports IPv4 protocol.
+ Option groups: FD,SOCKET,IP4,RANGE +

UDP6-RECV:<port>
+ Like UDP-RECV, but only supports IPv6 protocol.
+ Option groups: FD,SOCKET,IP6,RANGE +

UNIX-CONNECT:<filename>
+ Connects to <filename> assuming it is a UNIX domain + socket. + If <filename> does not exist, this is an error; + if <filename> is not a UNIX domain socket, this is an error; + if <filename> is a UNIX domain socket, but no process is listening, this is + an error.
+ Option groups: FD,SOCKET, + NAMED,RETRY, + UNIX
) + Useful options: + bind
+ See also: + UNIX-LISTEN, + UNIX-SENDTO, + TCP +

UNIX-LISTEN:<filename>
+ Listens on <filename> using a UNIX domain stream + socket and accepts a connection. + If <filename> exists and is not a socket, this is an error. + If <filename> exists and is a UNIX domain socket, binding to the address + fails (use option unlink-early!). + Note that opening this address usually blocks until a client connects. + Beginning with socat version 1.4.3, the file system entry is removed when + this address is closed (but see option unlink-close) (example).
+ Option groups: FD,SOCKET, + NAMED,LISTEN, + CHILD,RETRY, + UNIX
+ Useful options: + fork, + umask, + mode, + user, + group, + unlink-early
+ See also: + UNIX-CONNECT, + UNIX-RECVFROM, + UNIX-RECV, + TCP-LISTEN +

UNIX-SENDTO:<filename>
+ Communicates with the specified peer socket, defined by [<filename>] assuming it is a UNIX domain datagram socket. + It sends packets to and receives packets from that peer socket only. + It works well with socat UNIX-RECVFROM and UNIX-RECV address peers.
+ Option groups: FD,SOCKET, + NAMED,UNIX
+ Useful options: + bind
+ See also: + UNIX-RECVFROM, + UNIX-RECV, + UNIX-CONNECT, + UDP-SENDTO, + IP-SENDTO +

UNIX-RECVFROM:<filename>
+ Creates a UNIX domain datagram socket [<filename>]. + Receives one packet and may send one or more answer packets to that peer. + This mode is particularly useful with fork option where each arriving packet - from arbitrary peers - is handled by its own sub process. + This address works well with socat UNIX-SENDTO address peers.
+ Option groups: FD,SOCKET, + NAMED,CHILD, + UNIX
+ Useful options: + fork
+ See also: + UNIX-SENDTO, + UNIX-RECV, + UNIX-LISTEN, + UDP-RECVFROM, + IP-RECVFROM +

UNIX-RECV:<filename>
+ Creates a UNIX domain datagram socket [<filename>]. + Receives packets from multiple unspecified peers and merges the data. + No replies are possible. It can be, e.g., addressed by socat UNIX-SENDTO address peers. + It behaves similar to a syslog server. + Option groups: FD,SOCKET, + NAMED,UNIX
+ See also: + UNIX-SENDTO, + UNIX-RECVFROM, + UNIX-LISTEN, + UDP-RECV, + IP-RECV +

UNIX-CLIENT:<filename>
+ Communicates with the specified peer socket, defined by + [<filename>] assuming it is a UNIX domain socket. + It first tries to connect and, if that fails, assumes it is a datagram + socket, thus supporting both types.
+ Option groups: FD,SOCKET, + NAMED,UNIX
+ Useful options: + bind
+ See also: + UNIX-CONNECT, + UNIX-SENDTO, + GOPEN +

ABSTRACT-CONNECT:<string>
+

ABSTRACT-LISTEN:<string>
+

ABSTRACT-SENDTO:<string>
+

ABSTRACT-RECVFROM:<string>
+

ABSTRACT-RECV:<string>
+

ABSTRACT-CLIENT:<string>
+ The ABSTRACT addresses are almost identical to the related UNIX addresses + except that they do not address file system based sockets but an alternate + UNIX domain address space. To archieve this the socket address strings are + prefixed with "\0" internally. This feature is available (only?) on Linux. + Option groups are the same as with the related UNIX addresses, except that + the ABSTRACT addresses are not member of the NAMED group. +
+

+

ADDRESS OPTIONS

+ +

Address options can be applied to address specifications to influence the +process of opening the addresses and the +properties of the resulting data channels. +

For technical reasons not every option can be +applied to every address type; e.g., applying a socket option to a regular file +will fail. To catch most useless combinations as early as in the open phase, +the concept of option groups was introduced. Each option belongs to one +or more option groups. Options can be used only with address types that support +at least one of their option groups (but see option -g). +

Address options have data types that their values must conform to. +Every address option consists of just a keyword or a keyword followed by +"=value", where value must conform to the options type. + +Some address options manipulate parameters of system calls; +e.g., option sync sets the O_SYNC flag with the open() call. +Other options cause a system or library call; e.g., with option `ttl=value' +the setsockopt(fd, SOL_IP, IP_TTL, value, sizeof(int)) call is applied. +Other +options set internal socat variables that are used during data transfer; +e.g., `crnl' causes explicit character conversions. +A few options have more complex implementations; e.g., su-d +(substuser-delayed) inquires some user and group infos, stores them, and +applies them later after a possible chroot() call. +

If multiple options are given to an address, their sequence in the address specification has (almost) no +effect on the sequence of their execution/application. Instead, socat has +built in an option phase model that tries to bring the options in a useful +order. Some options exist in different forms (e.g., +unlink, unlink-early, unlink-late) to control the time of their execution. +

If the same option is specified more than once within one address +specification, with equal or different values, the effect depends on the kind of option. Options +resulting in function calls like setsockopt() cause multiple +invocations. With options that set parameters for a required call like +open() +or set internal flags, the value of the last option occurrence is effective. +

The existence or semantics of many options are system dependent. Socat +usually does NOT try to emulate missing libc or kernel features, it just +provides an +interface to the underlying system. So, if an operating system lacks a feature, +the related option is simply not available on this platform. +

The following paragraphs introduce just the more common address options. For +a more comprehensive reference and to find information about canonical option +names, alias names, option phases, and platforms see file xio.help. +

+


+

FD option group +

This option group contains options that are applied to a UN*X +style file descriptor, no matter how it was generated. +Because all current socat address types are file descriptor based, these +options may be applied to any address.
+Note: Some of these options are also member of another option group, that +provides an other, non-fd based mechanism. +For these options, it depends on the actual address type and its option groups +which mechanism is used. The second, non-fd based mechanism is prioritized. +

+

cloexec=<bool>
+ Sets the FD_CLOEXEC flag with the fcntl() system call to value + <bool>. If set, + the file descriptor is closed on exec() family function calls. Socat + internally handles + this flag for the fds it controls, so in most cases there will be no need to + apply this option. +

setlk
+ Tries to set a discretionary write lock to the whole file using the fcntl(fd, + F_SETLK, ...) system call. If the file is already locked, this call results + in an error. + On Linux, when the file permissions for group are "S" (g-x,g+s), and the + file system is locally mounted with the "mand" option, the lock is + mandatory, i.e. prevents other processes from opening the file. +

setlkw
+ Tries to set a discretionary waiting write lock to the whole file using the + fcntl(fd, F_SETLKW, ...) system call. If the file is already locked, + this call blocks. + See option setlk for information about making this + lock mandatory. +

setlk-rd
+ Tries to set a discretionary read lock to the whole file using the fcntl(fd, + F_SETLK, ...) system call. If the file is already write locked, this call + results in an error. + See option setlk for information about making this + lock mandatory. +

setlkw-rd
+ Tries to set a discretionary waiting read lock to the whole file using the + fcntl(fd, F_SETLKW, ...) system call. If the file is already write + locked, this call blocks. + See option setlk for information about making this + lock mandatory. +

flock-ex
+ Tries to set a blocking exclusive advisory lock to the file using the + flock(fd, LOCK_EX) system call. Socat hangs in this call if the file + is locked by another process. +

flock-ex-nb
+ Tries to set a nonblocking exclusive advisory lock to the file using the + flock(fd, LOCK_EX|LOCK_NB) system call. If the file is already locked, + this option results in an error. +

flock-sh
+ Tries to set a blocking shared advisory lock to the file using the + flock(fd, LOCK_SH) system call. Socat hangs in this call if the file + is locked by another process. +

flock-sh-nb
+ Tries to set a nonblocking shared advisory lock to the file using the + flock(fd, LOCK_SH|LOCK_NB) system call. If the file is already locked, + this option results in an error. +

lock
+ Sets a blocking lock on the file. Uses the setlk or flock mechanism + depending on availability on the particular platform. If both are available, + the POSIX variant (setlkw) is used. +

user=<user>
+ Sets the <user> (owner) of the stream. + If the address is member of the NAMED option group, + socat uses the chown() system call after opening the + file or binding to the UNIX domain socket (race condition!). + Without filesystem entry, socat sets the user of the stream + using the fchown() system call. + These calls might require root privilege. +

user-late=<user>
+ Sets the owner of the fd to <user> with the fchown() + system call after opening + or connecting the channel. + This is useful only on file system entries. +

group=<group>
+ Sets the <group> of the stream. + If the address is member of the NAMED option group, + socat uses the chown() system call after opening the + file or binding to the UNIX domain socket (race condition!). + Without filesystem entry, socat sets the group of the stream + with the fchown() system call. + These calls might require group membership or root privilege. +

group-late=<group>
+ Sets the group of the fd to <group> with the + fchown() system call after opening + or connecting the channel. + This is useful only on file system entries. +

mode=<mode>
+ Sets the <mode> [mode_t] (permissions) of the stream. + If the address is member of the NAMED option group and + uses the open() or creat() call, the mode is applied with these. + If the address is member of the NAMED option group without using these + system calls, socat uses the chmod() system call after opening the + filesystem entry or binding to the UNIX domain socket (race condition!). + Otherwise, socat sets the mode of the stream + using fchmod(). + These calls might require ownership or root privilege. +

perm-late=<mode>
+ Sets the permissions of the fd to value <mode> + [mode_t] using the fchmod() system call after + opening or connecting the channel. + This is useful only on file system entries. +

append=<bool>
+ Always writes data to the actual end of file. + If the address is member of the OPEN option group, + socat uses the O_APPEND flag with the open() system call + (example). + Otherwise, socat applies the fcntl(fd, F_SETFL, O_APPEND) call. +

nonblock=<bool>
+ Tries to open or use file in nonblocking mode. Its only effects are that the + connect() call of TCP addresses does not block, and that opening a + named pipe for reading does not block. + If the address is member of the OPEN option group, + socat uses the O_NONBLOCK flag with the open() system call. + Otherwise, socat applies the fcntl(fd, F_SETFL, O_NONBLOCK) call. + + +

binary
+ Opens the file in binary mode to avoid implicit line terminator + conversions (Cygwin). +

text
+ Opens the file in text mode to force implicit line terminator conversions + (Cygwin). +

noinherit
+ Does not keep this file open in a spawned process (Cygwin). +

cool-write
+ Takes it easy when write fails with EPIPE or ECONNRESET and logs the message + with notice level instead of error. + This prevents the log file from being filled with useless error messages + when socat is used as a high volume server or proxy where clients often + abort the connection.
+ This option is experimental. +

end-close
+ Changes the (address dependent) method of ending a connection to just close + the file descriptors. This is useful when the connection is to be reused by + or shared with other processes (example).
+ Normally, socket connections will be ended with shutdown(2) which + terminates the socket even if it is shared by multiple processes. + close(2) "unlinks" the socket from the process but keeps it active as + long as there are still links from other processes.
+ Similarly, when an address of type EXEC or SYSTEM is ended, socat usually + will explicitely kill the sub process. With this option, it will just close + the file descriptors. +
+


+

NAMED option group +

These options work on file system entries.
+See also options user, group, and +mode. +

+

user-early=<user>
+ Changes the <user> (owner) of the file system entry before + accessing it, using the + chown() system call. This call might require root privilege. +

group-early=<group>
+ Changes the <group> of the file system entry before + accessing it, using the + chown() system call. This call might require group membership or root + privilege. +

perm-early=<mode>
+ Changes the <mode> [mode_t] of the file system entry + before accessing it, using the + chmod() system call. This call might require ownership or root + privilege. +

umask=<mode>
+ Sets the umask of the process to <mode> [mode_t] before + accessing the file system entry (useful + with UNIX domain sockets!). This call might affect all further operations + of the socat process! +

unlink-early
+ Unlinks (removes) the file before opening it and even before applying + user-early etc. +

unlink
+ Unlinks (removes) the file before accessing it, but after user-early etc. +

unlink-late
+ Unlinks (removes) the file after opening it to make it inaccessible for + other processes after a short race condition. +

unlink-close
+ Removes the addresses file system entry when closing the address. + For named pipes, + listening unix domain sockets, + and the symbolic links of pty addresses, + the default is 1; for created files, + opened files, + generic opened files, and + client unix domain sockets the default is 0. +
+


+

OPEN option group +

The OPEN group options allow to set flags with the open() system call. +E.g., option `creat' sets the O_CREAT flag.
+See also options append and +nonblock. +

+

creat=<bool>
+ Creates the file if it does not exist (example). +

dsync=<bool>
+ Blocks write() calls until metainfo is physically written to media. +

excl=<bool>
+ With option creat, if file exists this is an error. +

largefile=<bool>
+ On 32 bit systems, allows a file larger than 2^31 bytes. +

noatime
+ Sets the O_NOATIME options, so reads do not change the access timestamp. +

noctty=<bool>
+ Does not make this file the controlling terminal. +

nofollow=<bool>
+ Does not follow symbolic links. +

nshare=<bool>
+ Does not allow to share this file with other processes. +

rshare=<bool>
+ Does not allow other processes to open this file for writing. +

rsync=<bool>
+ Blocks write() until metainfo is physically written to media. +

sync=<bool>
+ Blocks write() until data is physically written to media. + + + + +

rdonly=<bool>
+ Opens the file for reading only. + +

wronly=<bool>
+ Opens the file for writing only. +

trunc
+ Truncates the file to size 0 during opening it. +
+


+

REG and BLK option group +

These options are usually applied to a UN*X file descriptor, but their +semantics make sense only on a file supporting random access. +

+

seek=<offset>
+ Applies the lseek(fd, <offset>, SEEK_SET) (or lseek64) system + call, thus positioning the file pointer absolutely to <offset> + [off_t or off64_t]. +

seek-cur=<offset>
+ Applies the lseek(fd, <offset>, SEEK_CUR) (or lseek64) system + call, thus positioning the file pointer <offset> [off_t or + off64_t] bytes relatively to its current position (which + is usually 0). +

seek-end=<offset>
+ Applies the lseek(fd, <offset>, SEEK_END) (or lseek64) system + call, thus positioning the file pointer <offset> [off_t or + off64_t] bytes relatively to the files current end. +

ftruncate=<offset>
+ Applies the ftruncate(fd, <offset>) + (or ftruncate64 if available) system call, thus + truncating the file at the position <offset> [off_t or + off64_t]. +

secrm=<bool>
+

unrm=<bool>
+

compr=<bool>
+

ext2-sync=<bool>
+

immutable=<bool>
+

ext2-append=<bool>
+

nodump=<bool>
+

ext2-noatime=<bool>
+

journal-data=<bool>
+

notail=<bool>
+

dirsync=<bool>
+ These options change non standard file attributes on operating systems and + file systems that support these features, like Linux with ext2fs, + ext3fs, or reiserfs. See man 1 chattr for information on these options. + Please note that there might be a race condition between creating the file + and applying these options. +
+


+

PROCESS option group +

Options of this group change the process properties instead of just affecting +one data channel. +For EXEC and SYSTEM addresses and for LISTEN and CONNECT type addresses with +option FORK, +these options apply to the child processes instead of the main socat process. +

+

chroot=<directory>
+ Performs a chroot() operation to <directory> + after processing the address (example). This call might require root privilege. +

chroot-early=<directory>
+ Performs a chroot() operation to <directory> + before opening the address. This call might require root privilege. +

setgid=<group>
+ Changes the primary <group> of the process after + processing the address. This call might require root privilege. +

setgid-early=<group>
+ Changes the primary <group> of the process before opening + the address. This call might require root privilege. +

setuid=<user>
+ Changes the <user> (owner) of the process after processing + the address. This call might require root privilege. +

setuid-early=<user>
+ Changes the <user> (owner) of the process before opening + the address. This call might require root privilege. +

su=<user>
+ Changes the <user> (owner) and groups of the process after + processing the address (example). This call might require root privilege. +

su-d=<user>
+ Short name for substuser-delayed. + Changes the <user> + (owner) and groups of the process after processing the address (example). + The user and his groups are retrieved before a possible + chroot(). This call might require root privilege. +

setpgid=<pid_t>
+ Makes the process a member of the specified process group + <pid_t>. If no value + is given, or if the value is 0 or 1, the process becomes leader of a new + process group. +

setsid
+ Makes the process the leader of a new session (example). +
+


+

READLINE option group +

These options apply to the readline address type. +

+

history=<filename>
+ Reads and writes history from/to <filename> (example). +

noprompt
+ Since version 1.4.0, socat per default tries to determine a prompt - + that is then passed to the readline call - by remembering the last + incomplete line of the output. With this option, socat does not pass a + prompt to readline, so it begins line editing in the first column + of the terminal. +

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 + typed. The pattern is a regular expression, e.g. + "^[Pp]assword:.*$" or "([Uu]ser:|[Pp]assword:)". See regex(7) for details. + (example) +

prompt=<string>
+ Passes the string as prompt to the readline function. readline prints this + prompt when stepping through the history. If this string matches a constant + prompt issued by an interactive program on the other socat address, + consistent look and feel can be archieved. +
+


+

APPLICATION option group +

This group contains options that work at data level. +Note that these options only apply to the "raw" data transferred by socat, +but not to protocol data used by addresses like +PROXY. +

+

cr
+ Converts the default line termination character NL ('\n', 0x0a) to/from CR + ('\r', 0x0d) when writing/reading on this channel. +

crnl
+ Converts the default line termination character NL ('\n', 0x0a) to/from CRNL + ("\r\n", 0x0d0a) when writing/reading on this channel (example). + Note: socat simply strips all CR characters. +

ignoreeof
+ When EOF occurs on this channel, socat ignores it and tries to read more + data (like "tail -f") (example). +

readbytes=<bytes>
+ socat reads only so many bytes from this address (the address provides + only so many bytes for transfer and pretends to be at EOF afterwards). + Must be greater than 0. +

lockfile=<filename>
+ If lockfile exists, exits with error. If lockfile does not exist, creates it + and continues, unlinks lockfile on exit. +

waitlock=<filename>
+ If lockfile exists, waits until it disappears. When lockfile does not exist, + creates it and continues, unlinks lockfile on exit. +
+


+

SOCKET option group +

These options are intended for all kinds of sockets, e.g. IP or UNIX domain. Most are applied with a setsockopt() call. +

+

bind=<sockname>
+ Binds the socket to the given socket address using the bind() system + call. The form of <sockname> is socket domain dependent: + IP4 and IP6 allow the form [hostname|hostaddress][:(service|port)] (example), + UNIX domain sockets require <filename>. +

connect-timeout=<seconds>
+ Abort the connection attempt after <seconds> [timeval] + with error status. +

interface=<interface>
+ Binds the socket to the given <interface>. + This option might require root privilege. +

broadcast
+ For datagram sockets, allows sending to broadcast addresses and receiving + packets addressed to broadcast addresses. +

bsdcompat
+ Emulates some (old?) bugs of the BSD socket implementation. +

debug
+ Enables socket debugging. +

dontroute
+ Only communicates with directly connected peers, does not use routers. +

keepalive
+ Enables sending keepalives on the socket. +

linger=<seconds>
+ Blocks shutdown() or close() until data transfers have finished + or the given timeout [int] expired. + +

oobinline
+ Places out-of-band data in the input data stream. +

priority=<priority>
+ Sets the protocol defined <priority> [<int>] for outgoing + packets. +

rcvbuf=<bytes>
+ Sets the size of the receive buffer after the socket() call to + <bytes> [int]. With TCP + sockets, this value corresponds to the socket's maximal window size. +

rcvbuf-late=<bytes>
+ Sets the size of the receive buffer when the socket is already + connected to <bytes> [int]. + With TCP sockets, this value corresponds to the socket's + maximal window size. +

rcvlowat=<bytes>
+ Specifies the minimum number of received bytes [int] until + the socket layer will pass the buffered data to socat. +

rcvtimeo=<seconds>
+ Sets the receive timeout [timeval]. +

reuseaddr
+ Allows other sockets to bind to an address even if parts of it (e.g. the + local port) are already in use by socat (example). +

sndbuf=<bytes>
+ Sets the size of the send buffer after the socket() call to + <bytes> [int]. +

sndbuf-late=<bytes>
+ Sets the size of the send buffer when the socket is connected to + <bytes> [int]. +

sndlowat=<bytes>
+ Specifies the minimum number of bytes in the send buffer until the socket + layer will send the data to <bytes> [int]. +

sndtimeo=<seconds>
+ Sets the send timeout to seconds [timeval]. +

type=<type>
+ Sets the type of the socket, usually as argument to the socket() or + socketpair() call, to <type> [int]. + Under Linux, 1 means stream oriented socket, 2 means datagram socket, and 3 + means raw socket. + + + + + + + + + + + + + + + + + + + + + +

pf=<string>
+ Forces the use of the specified IP version. <string> can be + something like "ip4" or "ip6". +
+


+

UNIX option group +

These options apply to UNIX domain based addresses. +

+

unix-tightsocklen=[0|1]
+ On socket operations, pass a socket address length that does not include the + whole struct sockaddr_un record but (besides other components) only + the relevant part of the filename or abstract string. Default is 1. +
+

+IP4 and IP6 option groups +

These options can be used with IPv4 and IPv6 based sockets. +

+

tos=<tos>
+ Sets the TOS (type of service) field of outgoing packets to <tos> + [byte] (see RFC 791). +

ttl=<ttl>
+ Sets the TTL (time to live) field of outgoing packets to <ttl> + [byte]. +

ipoptions=<data>
+ Sets IP options like source routing. Must be given in binary form, + recommended format is a leading "x" followed by an even number of hex + digits. This option may be used multiple times, data are appended. + E.g., to connect to host 10.0.0.1 via some gateway using a loose source + route, use the gateway as address parameter and set a loose source route + using the option ipoptions=x8307040a000001.
+ IP options are defined in RFC 791.
+ +

mtudiscover=<0|1|2>
+ Takes 0, 1, 2 to never, want, or always use path MTU discover on this + socket. + + + + + + + + + + + + +

ip-add-membership=<multicast-address:interface-address>
+

ip-add-membership=<multicast-address:interface-name>
+

ip-add-membership=<multicast-address:interface-index>
+

ip-add-membership=<multicast-address:interface-address:interface-name>
+

ip-add-membership=<multicast-address:interface-address:interface-index>
+ Makes the socket member of the specified multicast group. This is currently + only implemented for IPv4. The option takes the IP address of the multicast + group and info about the desired network interface. The most common syntax + is the first one, while the others are only available on systems that + provide struct mreqn (Linux).
+ The indices of active network interfaces can be shown using the utility + procan. + +dif(ip-multicast-if=<hostname>) + Specifies hostname or address of the network interface to be used for + multicast traffic. + +dif(ip-multicast-loop=<bool>) + Specifies if outgoing multicast traffic should loop back to the interface. + +dif(ip-multicast-ttl=<byte>) + Sets the TTL used for outgoing multicast traffic. Default is 1. +

res-debug
+

res-aaonly
+

res-usevc
+

res-primary
+

res-igntc
+

res-recurse
+

res-defnames
+

res-stayopen
+

res-dnsrch
+ These options set the corresponding resolver (name resolution) option flags. + Append "=0" to clear a default option. See man resolver(5) for more + information on these options. Note: these options are valid only for the + address they are applied to. +

+


+

IP6 option group +

These options can only be used on IPv6 based sockets. See IP +options for options that can be applied to both IPv4 and IPv6 +sockets. +

+

ipv6only=<bool>
+ Sets the IPV6_V6ONLY socket option. If 0, the TCP stack will also accept + connections using IPv4 protocol on the same port. The default is system + dependent. +
+


+

TCP option group +

These options may be applied to TCP sockets. They work by invoking setsockopt() with the appropriate parameters. +

+

cork
+ Doesn't send packets smaller than MSS (maximal segment size). +

defer-accept
+ While listening, accepts connections only when data from the peer arrived. +

keepcnt=<count>
+ Sets the number of keepalives before shutting down the socket to + <count> [int]. +

keepidle=<seconds>
+ Sets the idle time before sending the first keepalive to <seconds> + [int]. +

keepintvl=<seconds>
+ Sets the intervall between two keepalives to <seconds> + [int]. +

linger2=<seconds>
+ Sets the time to keep the socket in FIN-WAIT-2 state to <seconds> + [int]. +

mss=<bytes>
+ Sets the MSS (maximum segment size) after the socket() call to <bytes> + [int]. This + value is then proposed to the peer with the SYN or SYN/ACK packet + (example). +

mss-late=<bytes>
+ Sets the MSS of the socket after connection has been established to <bytes> + [int]. +

nodelay
+ Turns off the Nagle algorithm for measuring the RTT (round trip time). +

rfc1323
+ Enables RFC1323 TCP options: TCP window scale, round-trip time measurement + (RTTM), and protect against wrapped sequence numbers (PAWS) (AIX). +

stdurg
+ Enables RFC1122 compliant urgent pointer handling (AIX). +

syncnt=<count>
+ Sets the maximal number of SYN retransmits during connect to <count> + [int]. + + +

md5sig
+ Enables generation of MD5 digests on the packets (FreeBSD). +

noopt
+ Disables use of TCP options (FreeBSD, MacOSX). +

nopush
+ sets the TCP_NOPUSH socket option (FreeBSD, MacOSX). +

sack-disable
+ Disables use the selective acknowledge feature (OpenBSD). +

signature-enable
+ Enables generation of MD5 digests on the packets (OpenBSD). +

abort-threshold=<milliseconds>
+ Sets the time to wait for an answer of the peer on an established connection + (HP-UX). +

conn-abort-threshold=<milliseconds>
+ Sets the time to wait for an answer of the server during the initial connect + (HP-UX). +

keepinit
+ Sets the time to wait for an answer of the server during connect() before + giving up. Value in half seconds, default is 150 (75s) (Tru64). +

paws
+ Enables the "protect against wrapped sequence numbers" feature (Tru64). +

sackena
+ Enables selective acknowledge (Tru64). +

tsoptena
+ Enables the time stamp option that allows RTT recalculation on existing + connections (Tru64). +
+


+

UDP and TCP option groups +

Here we find options that are related to the network port mechanism and that +thus can be used with UDP and TCP, client and server addresses. +

+

sourceport=<port>
+ For outgoing (client) TCP and UDP connections, it sets the source + <port> using an extra bind() call. + With TCP or UDP listen addresses, socat immediately shuts down the + connection if the client does not use this sourceport (example). +

lowport
+ Outgoing (client) TCP and UDP connections with this option use + an unused random source port between 640 and 1023 incl. On UNIX class operating + systems, this requires root privilege, and thus indicates that the + client process is authorized by local root. + TCP and UDP listen addresses with this option immediately shut down the + connection if the client does not use a sourceport <= 1023. + This mechanism can provide limited authorization under some circumstances. +
+


+

SOCKS option group +

When using SOCKS type addresses, some socks specific options can be set. +

+

socksport=<tcp service>
+ Overrides the default "socks" service or port 1080 for the socks server + port with <TCP service>. +

socksuser=<user>
+ Sends the <user> [string] in the username field to the + socks server. Default is the actual user name ($LOGNAME or $USER) (example). +
+


+

HTTP option group +

Options that can be provided with HTTP type addresses. The only HTTP address +currently implemented is proxy-connect. +

+

proxyport=<TCP service>
+ Overrides the default HTTP proxy port 8080 with + <TCP service>. +

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 + to ignore CR in the answer. Nevertheless, socat sends CR+NL to the proxy. +

proxyauth=<username>:<password>
+ Provide "basic" authentication to the proxy server. The argument to the + option is used with a "Proxy-Authorization: Base" header in base64 encoded + form.
+ Note: username and password are visible for every user on the local machine + in the process list; username and password are transferred to the proxy + server unencrypted (base64 encoded) and might be sniffed. +

resolve
+ Per default, socat sends to the proxy a CONNECT request containing the + target hostname. With this option, socat resolves the hostname locally and + sends the IP address. Please note that, according to RFC 2396, only name + resolution to IPv4 addresses is implemented. +
+


+

RANGE option group +

These options check if a connecting client should be granted access. They can +be applied to listening and receiving network sockets. tcp-wrappers options +fall into this group. +

+

range=<address-range>
+ After accepting a connection, tests if the peer is within range. For + IPv4 addresses, address-range takes the form address/bits, e.g. + 10.0.0.0/8, or address:mask, e.g. 10.0.0.0:255.0.0.0 (example); for IPv6, it is [ip6-address/bits], e.g. [::1/128]. + If the client address does not match, socat issues a warning and keeps + listening/receiving. +

tcpwrap[=<name>]
+ Uses Wietse Venema's libwrap (tcpd) library to determine + if the client is allowed to connect. The configuration files are + /etc/hosts.allow and /etc/hosts.deny per default, see "man 5 hosts_access" + for more information. The optional <name> (type string) + is passed to the wrapper functions as daemon process name (example). + If omitted, the basename of socats invocation (argv[0]) is passed. + If both tcpwrap and range options are applied to an address, both + conditions must be fulfilled to allow the connection. +

allow-table=<filename>
+ Takes the specified file instead of /etc/hosts.allow. +

deny-table=<filename>
+ Takes the specified file instead of /etc/hosts.deny. +

tcpwrap-etc=<directoryname>
+ Looks for hosts.allow and hosts.deny in the specified directory. Is + overridden by options hosts-allow + and hosts-deny. +
+


+

LISTEN option group +

Options specific to listening sockets. +

+

backlog=<count>
+ Sets the backlog value passed with the listen() system call to <count> + [int]. Default is 5. +
+

+

CHILD option group +

Options for addresses with multiple connections via child processes. +

+

fork
+ After establishing a connection, handles its channel in a child process and + keeps the parent process attempting to produce more connections, either by + listening or by connecting in a loop (example).
+ SSL-CONNECT and SSL-LISTEN differ in when they actually fork off the child: +SSL-LISTEN forks before the SSL handshake, while SSL-CONNECT forks +afterwards. + RETRY and FOREVER options are not inherited by the child process.
+
+


+

EXEC option group +

Options for addresses that invoke a program. +

+

path=<string>
+ Overrides the PATH environment variable for searching the program with + <string>. This + $PATH value is effective in the child process too. +

login
+ Prefixes argv[0] for the execvp() call with '-', thus making a + shell behave as login shell. +
+


+

FORK option group +

EXEC or SYSTEM addresses invoke a program using a child process and transfer data between socat and the program. The interprocess communication mechanism can be influenced with the following options. Per +default, a socketpair() is created and assigned to stdin and stdout of +the child process, while stderr is inherited from the socat process, and the +child process uses file descriptors 0 and 1 for communicating with the main +socat process. +

+

nofork
+ Does not fork a subprocess for executing the program, instead calls execvp() + or system() directly from the actual socat instance. This avoids the + overhead of another process between the program and its peer, + but introduces a lot of restrictions: +
+
  • this option can only be applied to the second socat address. +
  • it cannot be applied to a part of a dual address. +
  • the first socat address cannot be OPENSSL or READLINE +
  • socat options -b, -t, -D, -l, -v, -x become useless +
  • for both addresses, options ignoreeof, cr, and crnl become useless +
  • for the second address (the one with option nofork), options + append, cloexec, flock, user, group, mode, nonblock, + perm-late, setlk, and setpgid cannot be applied. Some of these could be + used on the first address though. +
  • +

    pipes
    + Creates a pair of unnamed pipes for interprocess communication instead of a + socket pair. +

    openpty
    + Establishes communication with the sub process using a pseudo terminal + created with openpty() instead of the default (socketpair or ptmx). +

    ptmx
    + Establishes communication with the sub process using a pseudo terminal + created by opening /dev/ptmx or /dev/ptc instead of the default + (socketpair). +

    pty
    + Establishes communication with the sub process using a pseudo terminal + instead of a socket pair. Creates the pty with an available mechanism. If + openpty and ptmx are both available, it uses ptmx because this is POSIX + compliant (example). +

    ctty
    + Makes the pty the controlling tty of the sub process (example). +

    stderr
    + Directs stderr of the sub process to its output channel by making stderr a + dup() of stdout (example). +

    fdin=<fdnum>
    + Assigns the sub processes input channel to its file descriptor + <fdnum> + instead of stdin (0). The program started from the subprocess has to use + this fd for reading data from socat (example). +

    fdout=<fdnum>
    + Assigns the sub processes output channel to its file descriptor + <fdnum> + instead of stdout (1). The program started from the subprocess has to use + this fd for writing data to socat (example). +

    sighup, sigint, sigquit
    + Has socat pass an eventual signal of this type to the sub process. + If no address has this option, socat terminates on these signals. +
    +


    +

    TERMIOS option group +

    For addresses that work on a tty (e.g., stdio, file:/dev/tty, exec:...,pty), the terminal parameters defined in the UN*X termios mechanism are made available as address option parameters. +Please note that changes of the parameters of your interactive terminal +remain effective after socat's termination, so you might have to enter "reset" +or "stty sane" in your shell afterwards. +For EXEC and SYSTEM addresses with option PTY, +these options apply to the pty by the child processes. +

    +

    b0
    + Disconnects the terminal. +

    b19200
    + Sets the serial line speed to 19200 baud. Some other rates are possible; use +something like socat -hh |grep ' b[1-9]' to find all speeds supported by +your implementation.
    +Note: On some operating systems, these options may not be +available. Use ispeed or ospeed +instead. +

    echo=<bool>
    + Enables or disables local echo (example). +

    icanon=<bool>
    + Sets or clears canonical mode, enabling line buffering and some special + characters. +

    raw
    + Sets raw mode, thus passing input and output almost unprocessed (example). +

    ignbrk=<bool>
    + Ignores or interpretes the BREAK character (e.g., ^C) +

    brkint=<bool>
    +

    bs0
    +

    bs1
    +

    bsdly=<0|1>
    +

    clocal=<bool>
    +

    + + + + + +

    cr0
    +cr1
    +cr2
    +cr3
    + Sets the carriage return delay to 0, 1, 2, or 3, respectively. + 0 means no delay, the other values are terminal dependent. +

    crdly=<0|1|2|3>
    +

    cread=<bool>
    +

    crtscts=<bool>
    +

    + + + + + +

    cs5
    +cs6
    +cs7
    +cs8
    + Sets the character size to 5, 6, 7, or 8 bits, respectively. +

    csize=<0|1|2|3>
    +

    cstopb=<bool>
    + Sets two stop bits, rather than one. +

    dsusp=<byte>
    + Sets the value for the VDSUSP character that suspends the current foreground + process and reactivates the shell (all except Linux). +

    echoctl=<bool>
    + Echos control characters in hat notation (e.g. ^A) +

    echoe=<bool>
    +

    echok=<bool>
    +

    echoke=<bool>
    +

    echonl=<bool>
    +

    echoprt=<bool>
    +

    eof=<byte>
    +

    eol=<byte>
    +

    eol2=<byte>
    +

    erase=<byte>
    +

    discard=<byte>
    +

    ff0
    +

    ff1
    +

    ffdly=<bool>
    +

    flusho=<bool>
    +

    hupcl=<bool>
    +

    icrnl=<bool>
    +

    iexten=<bool>
    +

    igncr=<bool>
    +

    ignpar=<bool>
    +

    imaxbel=<bool>
    +

    inlcr=<bool>
    +

    inpck=<bool>
    +

    intr=<byte>
    +

    isig=<bool>
    +

    ispeed=<unsigned-int>
    + Set the baud rate for incoming data on this line.
    + See also: ospeed, b19200 +dif(istrip=<bool>) +

    iuclc=<bool>
    +

    ixany=<bool>
    +

    ixoff=<bool>
    +

    ixon=<bool>
    +

    kill=<byte>
    +

    lnext=<byte>
    +

    min=<byte>
    +

    nl0
    + Sets the newline delay to 0. +

    nl1
    +

    nldly=<bool>
    +

    noflsh=<bool>
    +

    ocrnl=<bool>
    +

    ofdel=<bool>
    +

    ofill=<bool>
    +

    olcuc=<bool>
    +

    onlcr=<bool>
    +

    onlret=<bool>
    +

    onocr=<bool>
    +

    opost=<bool>
    + Enables or disables output processing; e.g., converts NL to CR-NL. +

    ospeed=<unsigned-int>
    + Set the baud rate for outgoing data on this line.
    + See also: ispeed, b19200 +

    parenb=<bool>
    + Enable parity generation on output and parity checking for input. +

    parmrk=<bool>
    +

    parodd=<bool>
    +

    pendin=<bool>
    +

    quit=<byte>
    +

    reprint=<byte>
    +

    sane
    + Brings the terminal to something like a useful default state. +

    start=<byte>
    +

    stop=<byte>
    +

    susp=<byte>
    +

    swtc=<byte>
    +

    tab0
    +

    tab1
    +

    tab2
    +

    tab3
    +

    tabdly=<unsigned-int>
    +

    time=<byte>
    +

    tostop=<bool>
    +

    vt0
    +

    vt1
    +

    vtdly=<bool>
    +

    werase=<byte>
    +

    xcase=<bool>
    +

    xtabs
    +
    +


    +

    PTY option group +

    These options are intended for use with the pty address +type. +

    +

    link=<filename>
    + Generates a symbolic link that points to the actual pseudo terminal + (pty). This might help + to solve the problem that ptys are generated with more or less + unpredictable names, making it difficult to directly access the socat + generated pty automatically. With this option, the user can specify a "fix" + point in the file hierarchy that helps him to access the actual pty + (example). + Beginning with socat version 1.4.3, the symbolic link is removed when + the address is closed (but see option unlink-close). +

    wait-slave
    + Blocks the open phase until a process opens the slave side of the pty. + Usually, socat continues after generating the pty with opening the next + address or with entering the transfer loop. With the wait-slave option, + socat waits until some process opens the slave side of the pty before + continuing. + This option only works if the operating system provides the poll() + system call. And it depends on an undocumented behaviour of pty's, so it + does not work on all operating systems. It has successfully been tested on + Linux, FreeBSD, NetBSD, and on Tru64 with openpty. +

    pty-intervall=<seconds>
    + When the wait-slave option is set, socat + periodically checks the HUP condition using poll() to find if the pty's + slave side has been opened. The default polling intervall is 1s. Use the + pty-intervall option [timeval] to change this value. +
    +


    +

    OPENSSL option group +

    These options apply to the openssl and +openssl-listen address types. +

    +

    cipher=<cipherlist>
    + Selects the list of ciphers that may be used for the connection. + See the man page of ciphers, section CIPHER LIST FORMAT, for + detailed information about syntax, values, and default of <cipherlist>.
    + Several cipher strings may be given, separated by ':'. + Some simple cipher strings: +
    +

    3DES
    Uses a cipher suite with triple DES. +

    MD5
    Uses a cipher suite with MD5. +

    aNULL
    Uses a cipher suite without authentication. +

    NULL
    Does not use encryption. +

    HIGH
    Uses a cipher suite with "high" encryption. +
    + Note that the peer must support the selected property, or the negotiation + will fail. +

    method=<ssl-method>
    + Sets the protocol version to be used. Valid strings (not case sensitive) + are: +
    +

    SSLv2
    Select SSL protocol version 2. +

    SSLv3
    Select SSL protocol version 3. +

    SSLv23
    Select SSL protocol version 2 or 3. This is the default when + this option is not provided. +

    TLSv1
    Select TLS protocol version 1. +
    +

    verify=<bool>
    + Controls check of the peer's certificate. Default is 1 (true). Disabling + verify might open your socket for everyone, making the encryption useless! +

    cert=<filename>
    + Specifies the file with the certificate and private key for authentication. + The certificate must be in OpenSSL format (*.pem). + With openssl-listen, use of this option is strongly + recommended. Except with cipher aNULL, "no shared ciphers" error will + occur when no certificate is given. +

    key=<filename>
    + Specifies the file with the private key. The private key may be in this + file or in the file given with the cert option. The party that has + to proof that it is the owner of a certificate needs the private key. +

    dhparams=<filename>
    + Specifies the file with the Diffie Hellman parameters. These parameters may + also be in the file given with the cert + option in which case the dhparams option is not needed. +

    cafile=<filename>
    + Specifies the file with the trusted (root) authority certificates. The file + must be in PEM format and should contain one or more certificates. The party + that checks the authentication of its peer trusts only certificates that are + in this file. +

    capath=<dirname>
    + Specifies the directory with the trusted (root) certificates. The directory + must contain certificates in PEM format and their hashes (see OpenSSL + documentation) +

    egd=<filename>
    + On some systems, openssl requires an explicit source of random data. Specify + the socket name where an entropy gathering daemon like egd provides random + data, e.g. /dev/egd-pool. +

    pseudo
    + On systems where openssl cannot find an entropy source and where no entropy + gathering daemon can be utilized, this option activates a mechanism for + providing pseudo entropy. This is archieved 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 random() calls.
    + NOTE:This mechanism is not sufficient for generation of secure keys! +

    fips
    + Enables FIPS mode if compiled in. For info about the FIPS encryption + implementation standard see http://oss-institute.org/fips-faq.html. + This mode might require that the involved certificates are generated with a + FIPS enabled version of openssl. Setting or clearing this option on one + socat address affects all OpenSSL addresses of this process. +
    +


    +

    RETRY option group +

    Options that control retry of some system calls, especially connection +attempts. +

    +

    retry=<num>
    + Number of retries before the connection or listen attempt is aborted. + Default is 0, which means just one attempt. +

    intervall=<timespec>
    + Time between consecutive attempts (seconds, + [timespec]). Default is 1 second. +

    forever
    + Performs an unlimited number of retry attempts. +
    +


    +

    TUN option group +

    Options that control Linux TUN/TAP interface device addresses. +

    +

    tun-device=<device-file>
    + Instructs socat to take another path for the TUN clone device. Default is + /dev/net/tun. +

    tun-name=<if-name>
    + Gives the resulting network interface a specific name instead of the system + generated (tun0, tun1, etc.) +

    tun-type=[tun|tap]
    + Sets the type of the TUN device; use this option to generate a TAP + device. See the Linux docu for the difference between these types. + When you try to establish a tunnel between two TUN devices, their types + should be the same. +

    iff-no-pi
    + Sets the IFF_NO_PI flag which controls if the device includes additional + packet information in the tunnel. + When you try to establish a tunnel between two TUN devices, these flags + should have the same values. +

    iff-up
    + Sets the TUN network interface status UP. Strongly recommended. +

    iff-broadcast
    + Sets the BROADCAST flag of the TUN network interface. +

    iff-debug
    + Sets the DEBUG flag of the TUN network interface. +

    iff-loopback
    + Sets the LOOPBACK flag of the TUN network interface. +

    iff-pointopoint
    + Sets the POINTOPOINT flag of the TUN device. +

    iff-notrailers
    + Sets the NOTRAILERS flag of the TUN device. +

    iff-running
    + Sets the RUNNING flag of the TUN device. +

    iff-noarp
    + Sets the NOARP flag of the TUN device. +

    iff-promisc
    + Sets the PROMISC flag of the TUN device. +

    iff-allmulti
    + Sets the ALLMULTI flag of the TUN device. +

    iff-master
    + Sets the MASTER flag of the TUN device. +

    iff-slave
    + Sets the SLAVE flag of the TUN device. +

    iff-multicast
    + Sets the MULTICAST flag of the TUN device. +

    iff-portsel
    + Sets the PORTSEL flag of the TUN device. +

    iff-automedia
    + Sets the AUTOMEDIA flag of the TUN device. +

    iff-dynamic
    + Sets the DYNAMIC flag of the TUN device. +
    +


    +

    +

    DATA VALUES

    + +

    This section explains the different data types that address parameters and +address options can take. +

    +

    address-range
    + Is currently only implemented for IPv4 and IPv6. See address-option + `range' +

    bool
    + "0" or "1"; if value is omitted, "1" is taken. +

    byte
    + An unsigned int number, read with strtoul(), lower or equal to + UCHAR_MAX. +

    command-line
    + A string specifying a program name and its arguments, separated by single + spaces. +

    data
    + A raw data specification following dalan syntax. The only documented + form is a string starting with 'x' followed by an even number of hex digits. +

    directory
    + A string with usual UN*X directory name semantics. +

    facility
    + The name of a syslog facility in lower case characters. +

    fdnum
    + An unsigned int type, read with strtoul(), specifying a UN*X file + descriptor. +

    filename
    + A string with usual UN*X filename semantics. +

    group
    + If the first character is a decimal digit, the value is read with + strtoul() as unsigned integer specifying a group id. Otherwise, it + must be an existing group name. +

    int
    + A number following the rules of the strtol() function with base + "0", i.e. decimal number, octal number with leading "0", or hexadecimal + number with leading "0x". The value must fit into a C int. +

    interface
    + A string specifying the device name of a network interface, e.g. "eth0". +

    IP address
    + An IPv4 address in numbers-and-dots notation, an IPv6 address in hex + notation enclosed in brackets, or a hostname that resolves to an IPv4 or an + IPv6 address.
    + Examples: 127.0.0.1, [::1], www.dest-unreach.org, dns1 +

    IPv4 address
    + An IPv4 address in numbers-and-dots notation or a hostname that resolves to + an IPv4 address.
    + Examples: 127.0.0.1, www.dest-unreach.org, dns2 +

    IPv6 address
    + An iPv6 address in hexnumbers-and-colons notation enclosed in brackets, or a + hostname that resolves to an IPv6 address.
    + Examples: [::1], [1234:5678:9abc:def0:1234:5678:9abc:def0], + ip6name.domain.org +

    long
    + A number read with strtol(). The value must fit into a C long. +

    long long
    + A number read with strtoll(). The value must fit into a C long long. +

    off_t
    + An implementation dependend signed number, usually 32 bits, read with strtol + or strtoll. +

    off64_t
    + An implementation dependend signed number, usually 64 bits, read with strtol + or strtoll. +

    mode_t
    + An unsigned integer, read with strtoul(), specifying mode (permission) + bits. +

    pid_t
    + A number, read with strtol(), specifying a process id. +

    port
    + A uint16_t (16 bit unsigned number) specifying a TCP or UDP port, read + with strtoul(). +

    protocol
    + An unsigned 8 bit number, read with strtoul(). +

    size_t
    + An unsigned number with size_t limitations, read with strtoul. +

    sockname
    + A socket address. See address-option `bind' +

    string
    + A sequence of characters, not containing '\0' and, depending on + the position within the command line, ':', ',', or "!!". Note + that you might have to escape shell meta characters in the command line. +

    TCP service
    + A service name, not starting with a digit, that is resolved by + getservbyname(), or an unsigned int 16 bit number read with + strtoul(). +

    timeval
    + A double float specifying seconds; the number is mapped into a + struct timeval, consisting of seconds and microseconds. +

    timespec
    + A double float specifying seconds; the number is mapped into a + struct timespec, consisting of seconds and nanoseconds. +

    UDP service
    + A service name, not starting with a digit, that is resolved by + getservbyname(), or an unsigned int 16 bit number read with + strtoul(). +

    unsigned int
    + A number read with strtoul(). The value must fit into a C unsigned + int. +

    user
    + If the first character is a decimal digit, the value is read with + strtoul() as unsigned integer specifying a user id. Otherwise, it must + be an existing user name. +
    +

    +

    EXAMPLES

    + +

    +

    +

    socat - TCP4:www.domain.org:80
    +

    Transfers data between STDIO (-) and a +TCP4 connection to port 80 of host +www.domain.org. This example results in an interactive connection similar to +telnet or netcat. The stdin terminal parameters are not changed, so you may +close the relay with ^D or abort it with ^C. +

    + + + + + +

    socat -d -d READLINE,history=$HOME/.http_history \
    +TCP4:www.domain.org:www,crnl
    +

    This is similar to the previous example, but you can edit the current line in a +bash like manner (READLINE) and use the +history file .http_history; socat +prints messages about progress (-d -d). The port is specified by service name +(www), and correct network line termination characters (crnl) instead of NL +are used. +

    +

    socat TCP4-LISTEN:www TCP4:www.domain.org:www
    +

    Installs a simple TCP port forwarder. With +TCP4-LISTEN it listens on local port "www" until a +connection comes in, accepts it, then connects to the remote host +(TCP4) and starts data transfer. It will not accept a +second connection. +

    + + + + + + + + +

    socat -d -d -lmlocal2 \
    +TCP4-LISTEN:80,bind=myaddr1,su=nobody,fork,range=10.0.0.0/8,reuseaddr \
    +TCP4:www.domain.org:80,bind=myaddr2
    +

    TCP port forwarder, each side bound to another local IP address +(bind). This example handles an almost +arbitrary number of parallel or consecutive connections by +fork'ing a new +process after each accept(). It provides a little security by +su'ing to user +nobody after forking; it only permits connections from the private 10 network (range); +due to reuseaddr, it allows immediate restart after master process's +termination, even if some child sockets are not completely shut down. +With -lmlocal2, socat logs to stderr until successfully +reaching the accept loop. Further logging is directed to syslog with facility +local2. +

    + + + + + + + + + +

    socat TCP4-LISTEN:5555,fork,tcpwrap=script \
    +EXEC:/bin/myscript,chroot=/home/sandbox,su-d=sandbox,pty,stderr
    +

    A simple server that accepts connections +(TCP4-LISTEN) and fork's a new +child process for each connection; every child acts as single relay. +The client must match the rules for daemon process name "script" in +/etc/hosts.allow and /etc/hosts.deny, otherwise it is refused access (see "man +5 hosts_access"). +For EXEC'uting the program, the child process +chroot's +to /home/sandbox, su's to user sandbox, and then starts +the program /home/sandbox/bin/myscript. Socat and +myscript communicate via a pseudo tty (pty); myscript's +stderr is redirected to stdout, +so its error messages are transferred via socat to the connected client. +

    + + + + + + + +

    socat EXEC:"mail.sh target@domain.com",fdin=3,fdout=4 \
    +TCP4:mail.relay.org:25,crnl,bind=alias1.server.org,mss=512
    +

    mail.sh is a shell script, distributed with socat, that implements a +simple +SMTP client. It is programmed to "speak" SMTP on its FDs 3 (in) and 4 (out). +The fdin and fdout options tell socat +to use these FDs for communication with +the program. Because mail.sh inherits stdin and stdout while socat does not +use them, the script can read a +mail body from stdin. Socat makes alias1 your local source address +(bind), cares for correct network line termination +(crnl) and sends +at most 512 data bytes per packet (mss). +

    + + +

    socat - /dev/ttyS0,raw,echo=0,crnl
    +

    Opens an interactive connection via the serial line, e.g. for talking with a +modem. raw and echo set ttyS0's terminal +parameters to practicable values, crnl +converts to correct newline characters. Consider using +READLINE instead of `-'. +

    + + + + + + + +

    socat UNIX-LISTEN:/tmp/.X11-unix/X1,fork \
    +SOCKS4:host.victim.org:127.0.0.1:6000,socksuser=nobody,sourceport=20
    +

    With UNIX-LISTEN, socat opens a listening +UNIX domain socket /tmp/.X11-unix/X1. This path corresponds +to local XWindow display :1 on your machine, so XWindow client connections to +DISPLAY=:1 are accepted. Socat then speaks with +the SOCKS4 server host.victim.org that might permit +sourceport 20 based connections due to an FTP related +weakness in its static IP filters. Socat +pretends to be invoked by socksuser nobody, and +requests to be connected to +loopback port 6000 (only weak sockd configurations will allow this). So we get +a connection to the victims XWindow server and, if it does not require MIT +cookies or Kerberos authentication, we can start work. Please note that there +can only be one connection at a time, because TCP can establish only one +session with a given set of addresses and ports. +

    + +

    socat -u /tmp/readdata,seek-end=0,ignoreeof -
    +

    This is an example for unidirectional data transfer +(-u). Socat transfers data +from file /tmp/readdata (implicit address GOPEN), starting +at its current end (seek-end=0 lets socat start +reading at current end of file; use seek=0 or no +seek option to first read the existing data) in a "tail -f" like mode +(ignoreeof). The "file" +might also be a listening UNIX domain socket (do not use a seek option then). +

    + + + + + +

    (echo PASSWORD; sleep 5; echo ls; sleep 1) |
    +socat - EXEC:'ssh -l user server',pty,setsid,ctty
    +

    EXEC'utes an ssh session to server. Uses a pty for communication between socat and +ssh, makes it ssh's controlling tty (ctty), +and makes this pty the owner of +a new process group (setsid), so ssh accepts the password from socat. +

    + + + + + + +

    socat -u TCP4-LISTEN:3334,reuseaddr,fork \
    +OPEN:/tmp/in.log,creat,append
    +

    Implements a simple network based message collector. +For each client connecting to port 3334, a new child process is generated (option fork). +All data sent by the clients are append'ed to the file /tmp/in.log. +If the file does not exist, socat creat's it. +Option reuseaddr allows immediate restart of the server +process. +

    + +

    +

    socat READLINE,noecho='[Pp]assword:' EXEC:'ftp ftp.server.com',pty,setsid,ctty
    +

    Wraps a command line history (READLINE) around the EXEC'uted ftp client utility. +This allows editing and reuse of FTP commands for relatively comfortable +browsing through the ftp directory hierarchy. The password is echoed! + pty is required to have ftp issue a prompt. +Nevertheless, there may occur some confusion with the password and FTP +prompts. +

    + + + +(socat PTY,link=$HOME/dev/vmodem0,raw,echo=0,waitslave EXEC:'"ssh modemserver.us.org socat - /dev/ttyS0,nonblock,raw,echo=0"') +

    Generates a pseudo terminal +device (PTY) on the client that can be reached under the +symbolic link $HOME/dev/vmodem0. +An application that expects a serial line or modem +can be configured to use $HOME/dev/vmodem0; its traffic will be directed +to a modemserver via ssh where another socat instance links it with +/dev/ttyS0. +

    + + + +

    socat TCP4-LISTEN:2022,reuseaddr,fork \
    +PROXY:proxy:www.domain.org:22,proxyport=3128,proxyauth=user:pass
    +

    starts a forwarder that accepts connections on port 2022, and directs them +through the proxy daemon listening on port 3128 +(proxyport) on host proxy, using the +CONNECT method, where they are authenticated as "user" with "pass" (proxyauth). The proxy +should establish connections to host www.domain.org on port 22 then. +

    +

    socat - SSL:server:4443,cafile=server.crt,cert=client.pem
    +

    is an OpenSSL client that tries to establish a secure connection to an SSL +server. Option cafile specifies a file that +contains trust certificates: we trust the server only when it presents one of +these certificates and proofs that it owns the related private key. +Otherwise the connection is terminated. +With cert a file containing the client certificate +and the associated private key is specified. This is required in case the +server wishes a client authentication; many Internet servers do not.
    +The first address ('-') can be replaced by almost any other socat address. +

    +

    socat SSL-LISTEN:4443,reuseaddr,pf=ip4,fork,cert=server.pem,cafile=client.crt PIPE
    +

    is an OpenSSL server that accepts TCP connections, presents the certificate +from the file server.pem and forces the client to present a certificate that is +verified against cafile.crt.
    +The second address ('PIPE') can be replaced by almost any other socat +address.
    +For instructions on generating and distributing OpenSSL keys and certificates +see the additional socat docu socat-openssl.txt. +

    echo |socat -u - file:/tmp/bigfile,create,largefile,seek=100000000000
    +

    creates a 100GB sparse file; this requires a file system type that +supports this (ext2, ext3, reiserfs, jfs; not minix, vfat). The operation of +writing 1 byte might take long (reiserfs: some minutes; ext2: "no" time), and +the resulting file can consume some disk space with just its inodes (reiserfs: +2MB; ext2: 16KB). +

    socat tcp-l:7777,reuseaddr,fork system:'filan -i 0 -s >&2',nofork
    +

    listens for incoming TCP connections on port 7777. For each accepted +connection, invokes a shell. This shell has its stdin and stdout directly +connected to the TCP socket (nofork). The shell starts filan and lets it print the socket addresses to +stderr (your terminal window). +

    echo -e "\0\14\0\0\c" |socat -u - file:/usr/bin/squid.exe,seek=0x00074420
    +

    functions as primitive binary editor: it writes the 4 bytes 000 014 000 000 to +the executable /usr/bin/squid at offset 0x00074420 (this is a real world patch +to make the squid executable from Cygwin run under Windows, actual per May 2004). +

    socat - tcp:www.blackhat.org:31337,readbytes=1000
    +

    connects to an unknown service and prevents being flooded. +

    +

    socat -U TCP:target:9999,end-close TCP-L:8888,reuseaddr,fork
    +

    merges data arriving from different TCP streams on port 8888 to just one stream +to target:9999. The end-close option prevents the child +processes forked off by the second address from terminating the shared +connection to 9999 (close(2) just unlinks the inode which stays active as long +as the parent process lives; shutdown(2) would actively terminate the +connection). +

    +

    socat - UDP4-DATAGRAM:192.168.1.0:123,sp=123,broadcast,range=192.168.1.0/24
    +

    sends a broadcast to the network 192.168.1.0/24 and receives the replies of the +timeservers there. Ignores NTP packets from hosts outside this network. +

    +

    socat - IP4-DATAGRAM:255.255.255.255:44,broadcast,range=10.0.0.0/8
    +

    sends a broadcast to the local network(s) using protocol 44. Accepts replies +from the private address range only. +

    +

    socat - UDP4-DATAGRAM:224.255.0.1:6666,bind=:6666,ip-add-membership=224.255.0.1:eth0
    +

    transfers data from stdin to the specified multicast address using UDP. Both +local and remote ports are 6666. Tells the interface eth0 to also accept +multicast packets of the given group. Multiple hosts on the local network can +run this command, so all data sent by any of the hosts will be received +by all the other ones. Note that there are many possible reasons for failure, +including IP-filters, routing issues, wrong interface selection by the +operating system, bridges, or a badly configured switch. +

    +

    socat TCP:host2:4443 TUN:192.168.255.1/24,up
    +

    establishes one side of a virtual (but not private!) network with host2 where a +similar process might run, with TCP-L and tun address 192.168.255.2. They +can reach each other using the addresses 192.168.255.1 and +192.168.255.2. Substitute the TCP link with an SSL connection protected by +client and server authentication (see OpenSSL +client and +server). +

    +

    +

    DIAGNOSTICS

    + +

    Socat uses a logging mechanism that allows to filter messages by severity. The +severities provided are more or less compatible to the appropriate syslog +priority. With one or up to four occurrences of the -d command line option, the +lowest priority of messages that are issued can be selected. Each message +contains a single uppercase character specifying the messages severity (one of +F, E, W, N, I, or D) +

    +

    FATAL:
    Conditions that require unconditional and immediate program termination. +

    ERROR:
    Conditions that prevent proper program processing. Usually the +program is terminated (see option -s). +

    WARNING:
    Something did not function correctly or is in a state where +correct further processing cannot be guaranteed, but might be possible. +

    NOTICE:
    Interesting actions of the program, e.g. for supervising socat in some kind of server mode. +

    INFO:
    Description of what the program does, and maybe why it +happens. Allows to monitor the lifecycles of file descriptors. +

    DEBUG:
    Description of how the program works, all system or library calls and their results. +
    +

    Log messages can be written to stderr, to a file, or to syslog. +

    On exit, socat gives status 0 if it terminated due to EOF or inactivity +timeout, with a positive value on error, and with a negative value on fatal +error. +

    +

    FILES

    + +

    /usr/bin/socat
    +/usr/bin/filan
    +/usr/bin/procan +

    +

    ENVIRONMENT VARIABLES

    + +

    +

    SOCAT_DEFAULT_LISTEN_IP
    (Values 4 or 6) Sets the IP version to be used +for listen, recv, and recvfrom addresses if no pf +(protocol-family) option is given. Is overridden by socat options +-4 or -6. +

    SOCAT_PREFERRED_RESOLVE_IP
    (Values 0, 4, or 6) Sets the IP version to +be used when resolving target host names when version is not specified by +address type, option pf (protocol-family), or +address format. If name resolution does not return a matching entry, the first +result (with differing IP version) is taken. With value 0, socat always selects +the first record and its IP version. +

    SOCAT_FORK_WAIT
    Specifies the time (seconds) to sleep the parent and +child processes after successful fork(). Useful for debugging. +

    HOSTNAME
    Is used to determine the hostname for logging (see +-lh). +

    LOGNAME
    Is used as name for the socks client user name if no +socksuser is given.
    +With options su and +su-d, LOGNAME is set to the given user name. +

    USER
    Is used as name for the socks client user name if no +socksuser is given and LOGNAME is empty.
    +With options su and +su-d, USER is set to the given user name. +

    SHELL
    +With options su and +su-d, SHELL is set to the login shell of the +given user. +

    PATH
    +Can be set with option path for exec and +system addresses. +

    HOME
    +With options su and +su-d, HOME is set to the home directory of the +given user. +

    +

    +

    CREDITS

    + +

    The work of the following groups and organizations was invaluable for this +project: +

    The FSF (GNU, http://www.fsf.org/ project +with their free and portable development software and +lots of other useful tools and libraries. +

    The Linux developers community (http://www.linux.org/) for providing a free, open source operating +system. +

    The Open Group (http://www.unix-systems.org/) for making their +standard specifications available on the Internet for free. +

    +

    VERSION

    + +

    This man page describes version 1.6.0 of socat. +

    +

    BUGS

    + +

    Addresses cannot be nested, so a single socat process cannot, e.g., drive ssl +over socks. +

    Address option ftruncate without value uses default 1 instead of 0. +

    Verbose modes (-x and/or -v) display line termination characters inconsistently +when address options cr or crnl are used: They show the data after +conversion in either direction. +

    The data transfer blocksize setting (-b) is ignored with address readline. +

    Send bug reports to <socat@dest-unreach.org> +

    +

    SEE ALSO

    + +

    +nc(1), netcat6(1), sock(1), rinetd(8), cage(1), socks.conf(5), openssl(1), +stunnel(8), pty(1), rlwrap(1), setsid(1) +

    Socat home page http://www.dest-unreach.org/socat/ +

    +

    AUTHOR

    + +

    Gerhard Rieger <rieger@dest-unreach.org> + + diff --git a/doc/socat.yo b/doc/socat.yo new file mode 100644 index 0000000..49bacab --- /dev/null +++ b/doc/socat.yo @@ -0,0 +1,3026 @@ +COMMENT($Id: socat.yo,v 1.99 2007/03/06 20:56:24 gerhard Exp $) +mailto(socat@dest-unreach.org) + +def(unix)(0)(UN*X) +def(unixdomain)(0)(UNIX domain) +def(socat)(0)(bf(socat)) +def(Socat)(0)(bf(Socat)) +def(filan)(0)(bf(filan)) +def(Filan)(0)(bf(Filan)) +def(procan)(0)(bf(procan)) +def(Procan)(0)(bf(Procan)) + +manpage(socat)(1)(March 2007)(socat)() + +whenhtml( +label(CONTENTS) +manpagesection(CONTENTS) +link(NAME)(NAME)nl() +link(SYNOPSIS)(SYNOPSIS)nl() +link(DESCRIPTION)(DESCRIPTION)nl() +link(OPTIONS)(OPTIONS)nl() +link(ADDRESS SPECIFICATIONS)(ADDRESS_SPECIFICATIONS)nl() +link(ADDRESS TYPES)(ADDRESS_TYPES)nl() +link(ADDRESS OPTIONS)(ADDRESS_OPTIONS)nl() +link(DATA VALUES)(VALUES)nl() +link(EXAMPLES)(EXAMPLES)nl() +link(DIAGNOSTICS)(DIAGNOSTICS)nl() +link(FILES)(FILES)nl() +link(ENVIRONMENT VARIABLES)(ENVIRONMENT_VARIABLES)nl() +link(CREDITS)(CREDITS)nl() +link(VERSION)(VERSION)nl() +link(BUGS)(BUGS)nl() +link(SEE ALSO)(SEEALSO)nl() +) + +label(NAME) +manpagename(socat) (Multipurpose relay (SOcket CAT)) + +label(SYNOPSIS) +manpagesynopsis() +tt(socat [options]

    )nl() +tt(socat -V)nl() +tt(socat -h[h[h]] | -?[?[?]])nl() +tt(filan)nl() +tt(procan) + +label(DESCRIPTION) +manpagedescription() + +Socat() is a command line based utility that establishes two bidirectional byte +streams and transfers data between them. Because the streams can be constructed +from a large set of different types of data sinks and sources +(see link(address types)(ADDRESS_TYPES)), and because lots of +link(address options)(ADDRESS_OPTIONS) may be applied to the streams, socat can +be used for many different purposes. +It might be one of the tools that one `has already needed'. + +Filan() is a utility that prints information about its active file +descriptors to stdout. It has been written for debugging socat(), but might be +useful for other purposes too. Use the -h option to find more infos. + +Procan() is a utility that prints information about process parameters to +stdout. It has been written to better understand +some UNIX process properties and for debugging socat(), but might be +useful for other purposes too. + +The life cycle of a socat() instance typically consists of four phases. + +In the em(init) phase, the command line options are parsed and logging is +initialized. + +During the em(open) phase, socat() opens the first address and afterwards the +second address. These steps are usually blocking; thus, especially for complex address types like socks, +connection requests or authentication dialogs must be completed before the next +step is started. + +In the em(transfer) phase, socat() watches both streams' read and write file +descriptors via code(select()), and, when data is available on one side em(and) +can be written to the other side, socat reads it, performs newline +character conversions if required, and writes the data to the write file +descriptor of the other stream, then continues waiting for more data in both +directions. + +When one of the streams effectively reaches EOF, the em(closing) phase +begins. Socat() transfers the EOF condition to the other stream, +i.e. tries to shutdown only its write stream, giving it a chance to +terminate gracefully. For a defined time socat() continues to transfer data in +the other direction, but then closes all remaining channels and terminates. + + +label(OPTIONS) +manpageoptions() + +Socat() provides some command line options that modify the behaviour of the +program. They have nothing to do with so called +link(address options)(ADDRESS_OPTIONS) that are used as parts of link(address specifications)(ADDRESS_SPECIFICATIONS). + +startdit() +dit(bf(tt(-V))) + Print version and available feature information to stdout, and exit. +dit(bf(tt(-h | -?))) + Print a help text to stdout describing command line options and available address + 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 + implementation. +dit(bf(tt(-hhh | -???))) + Like -hh, plus a list of all available address option names. +label(option_d)dit(bf(tt(-d))) + Without this option, only fatal and error messages are generated; applying + this option also prints warning messages. See link(DIAGNOSTICS)(DIAGNOSTICS) + for more information. +label(option_d_d)dit(bf(tt(-d -d))) Prints fatal, error, warning, and notice messages. +dit(bf(tt(-d -d -d))) Prints fatal, error, warning, notice, and info messages. +dit(bf(tt(-d -d -d -d))) Prints fatal, error, warning, notice, info, and debug + messages. +dit(bf(tt(-D))) + Logs information about file descriptors before starting the transfer phase. +dit(bf(tt(-ly[]))) + Writes messages to syslog instead of stderr; severity as defined with -d + option. With optional link()(TYPE_FACILITY), the syslog type can + be selected, default is "daemon". +dit(bf(tt(-lf))tt( )) + Writes messages to [link(filename)(TYPE_FILENAME)] instead of + stderr. +dit(bf(tt(-ls))) + Writes messages to stderr (this is the default). +label(option_lp)dit(bf(tt(-lp))tt()) + Overrides the program name printed in error messages. +dit(bf(tt(-lu))) + Extends the timestamp of error messages to microsecond resolution. Does not + work when logging to syslog. +label(option_lm)dit(bf(tt(-lm[]))) + Mixed log mode. During startup messages are printed to stderr; when socat() + starts the transfer phase loop or daemon mode (i.e. after opening all + streams and before starting data transfer, or, with listening sockets with + fork option, before the first accept call), it switches logging to syslog. + With optional link()(TYPE_FACILITY), the syslog type can be + selected, default is "daemon". +label(option_lh)dit(bf(tt(-lh))) + Adds hostname to log messages. Uses the value from environment variable + HOSTNAME or the value retrieved with tt(uname()) if HOSTNAME is not set. +dit(bf(tt(-v))) + Writes the transferred data not only to their target streams, but also to + stderr. The output format is text with some conversions for readability, and + prefixed with "> " or "< " indicating flow directions. +dit(bf(tt(-x))) + Writes the transferred data not only to their target streams, but also to + stderr. The output format is hexadecimal, prefixed with "> " or "< " + indicating flow directions. Can be combined with code(-v). +label(option_b)dit(bf(tt(-b))tt()) + Sets the data transfer block [link(size_t)(TYPE_SIZE_T)]. + At most bytes are transferred per step. Default is 8192 bytes. +label(option_s)dit(bf(tt(-s))) + By default, socat() terminates when an error occurred to prevent the process + from running when some option could not be applied. With this + option, socat() is sloppy with errors and tries to continue. Even with this + option, socat will exit on fatals, and will abort connection attempts when + security checks failed. +label(option_t)dit(bf(tt(-t))tt()) + When one channel has reached EOF, the write part of the other channel is shut + down. Then, socat() waits [link(timeval)(TYPE_TIMEVAL)] seconds + before terminating. Default is 0.5 seconds. This timeout only applies to + addresses where write and read part can be closed independently. When during + the timeout intervall the read part gives EOF, socat terminates without + awaiting the timeout. +label(option_T)dit(bf(tt(-T))tt()) + Total inactivity timeout: when socat is already in the transfer loop and + nothing has happened for [link(timeval)(TYPE_TIMEVAL)] seconds + (no data arrived, no interrupt occurred...) then it terminates. + 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 + second address is only used for writing (link(example)(EXAMPLE_option_u)). +label(option_U)dit(bf(tt(-U))) + Uses unidirectional mode in reverse direction. The first address is only + used for writing, and the second address is only used for reading. +label(option_g)dit(bf(tt(-g))) + During address option parsing, don't check if the option is considered + useful in the given address environment. Use it if you want to force, e.g., + appliance of a socket option to a serial device. +label(option_L)dit(bf(tt(-L))tt()) + If lockfile exists, exits with error. If lockfile does not exist, creates it + and continues, unlinks lockfile on exit. +label(option_W)dit(bf(tt(-W))tt()) + If lockfile exists, waits until it disappears. When lockfile does not exist, + creates it and continues, unlinks lockfile on exit. +label(option_4)dit(bf(tt(-4))) + Use IP version 4 in case that the addresses do not implicitly or explicitly + specify a version; this is the default. +label(option_6)dit(bf(tt(-6))) + Use IP version 6 in case that the addresses do not implicitly or explicitly + specify a version. +enddit() + + +label(ADDRESS_SPECIFICATIONS) +manpagesection(ADDRESS SPECIFICATIONS) + +With the address command line arguments, the user gives socat() instructions and +the necessary information for establishing the byte streams. + +An address specification usually consists of an address type +keyword, zero or more required address parameters separated by ':' from the keyword and +from each +other, and zero or more address options separated by ','. + +The keyword specifies the address type (e.g., TCP4, OPEN, EXEC). For some +keywords there exist synonyms ('-' for STDIO, TCP for TCP4). Keywords are case +insensitive. +For a few special address types, the keyword may be omitted: +Address specifications starting with a number are assumed to be FD (raw file +descriptor) addresses; +if a '/' is found before the first ':' or ',', GOPEN (generic file open) is +assumed. + +The required number and type of address parameters depend on the address +type. E.g., TCP4 requires a server specification (name or address), and a port +specification (number or service name). + +Zero or more address options may be given with each address. They influence the +address in some ways. +Options consist of an option keyword or an option keyword and a value, +separated by '='. Option keywords are case insensitive. +For filtering the options that are useful with an address +type, each option is member of one option group. For +each address type there is a set of option groups allowed. Only options +belonging to one of these address groups may be used (except with link(option -g)(option_g)). + +label(ADDRESS_DUAL) +Address specifications following the above schema are also called em(single) +address specifications. +Two single addresses can be combined with "!!" to form a em(dual) type +address for one channel. Here, the first address is used by socat() for reading +data, and the +second address for writing data. There is no way to specify an option only once +for being applied to both single addresses. + +Usually, addresses are opened in read/write +mode. When an address is part of a dual address specification, or when +link(option -u)(option_u) or link(-U)(option_U) is used, an address might be +used only for reading or for writing. Considering this is important with some +address types. + +With socat version 1.5.0 and higher, the lexical analysis tries to handle +quotes and parenthesis meaningfully and allows escaping of special characters. +If one of the characters ( { [ ' is found, the corresponding closing +character - ) } ] ' - is looked for; they may also be nested. Within these +constructs, socats special characters and strings : , !! are not handled +specially. All those characters and strings can be escaped with \ or within "" + +label(ADDRESS_TYPES) +manpagesection(ADDRESS TYPES) + +This section describes the available address types with their keywords, +parameters, and semantics. + +startdit() +label(ADDRESS_CREAT)dit(bf(tt(CREATE:))) + Opens link()(TYPE_FILENAME) with code(creat()) and uses the file + descriptor for writing. + This address type requires write-only context, because a file opened with + code(creat) cannot be read from. + must be a valid existing or not existing path. + If is a named pipe, code(creat()) might block; + if 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_MODE), + link(user)(OPTION_USER), + link(group)(OPTION_GROUP), + link(unlink-early)(OPTION_UNLINK_EARLY), + link(unlink-late)(OPTION_UNLINK_LATE), + link(append)(OPTION_APPEND)nl() + See also: link(OPEN)(ADDRESS_OPEN), link(GOPEN)(ADDRESS_GOPEN) +label(ADDRESS_EXEC)dit(bf(tt(EXEC:))) + Forks a sub process that establishes communication with its parent process + and invokes the specified program with code(execvp()). + link()(TYPE_COMMAND_LINE) is a simple command + with arguments separated by single spaces. If the program name + contains a '/', the part after the last '/' is taken as ARGV[0]. If the + program name is a relative + path, the code(execvp()) semantics for finding the program via + code($PATH) + apply. After successful program start, socat() writes data to stdin of the + process and reads from its stdout using a unixdomain() socket generated by + code(socketpair()) per default. (link(example)(EXAMPLE_ADDRESS_EXEC)) nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(EXEC)(GROUP_EXEC),link(FORK)(GROUP_FORK),link(TERMIOS)(GROUP_TERMIOS) nl() + Useful options: + link(path)(OPTION_PATH), + link(fdin)(OPTION_FDIN), + link(fdout)(OPTION_FDOUT), + link(chroot)(OPTION_CHROOT), + link(su)(OPTION_SUBSTUSER), + link(su-d)(OPTION_SUBSTUSER_DELAYED), + link(nofork)(OPTION_NOFORK), + link(pty)(OPTION_PTY), + link(stderr)(OPTION_STDERR), + link(ctty)(OPTION_CTTY), + link(setsid)(OPTION_SETSID), + link(pipes)(OPTION_PIPES), + link(login)(OPTION_LOGIN), + link(sigint)(OPTION_SIGINT), + link(sigquit)(OPTION_SIGQUIT)nl() + See also: link(SYSTEM)(ADDRESS_SYSTEM) +label(ADDRESS_FD)dit(bf(tt(FD:))) + Uses the file descriptor link()(TYPE_FDNUM). It must already exist as + valid unix() file descriptor.nl() + Option groups: link(FD)(GROUP_FD) (link(TERMIOS)(GROUP_TERMIOS),link(REG)(GROUP_REG),link(SOCKET)(GROUP_SOCKET)) nl() + See also: + link(STDIO)(ADDRESS_STDIO), + link(STDIN)(ADDRESS_STDIN), + link(STDOUT)(ADDRESS_STDOUT), + link(STDERR)(ADDRESS_STDERR) +label(ADDRESS_GOPEN)dit(bf(tt(GOPEN:))) + (Generic open) This address type tries to handle any file system entry + except directories usefully. link()(TYPE_FILENAME) may be a + relative or absolute path. If it already exists, its type is checked. + In case of a unixdomain() socket, socat() connects; if connecting fails, + socat() assumes a datagram socket and uses code(sendto()) calls. + If the entry is not a socket, socat() opens it applying the code(O_APPEND) + flag. + If it does not exist, it is opened with flag + code(O_CREAT) as a regular file (link(example)(EXAMPLE_ADDRESS_GOPEN)).nl() + Option groups: link(FD)(GROUP_FD),link(REG)(GROUP_REG),link(SOCKET)(GROUP_SOCKET),link(NAMED)(GROUP_NAMED),link(OPEN)(GROUP_OPEN) nl() + See also: + link(OPEN)(ADDRESS_OPEN), + link(CREATE)(ADDRESS_CREAT), + link(UNIX-CONNECT)(ADDRESS_UNIX_CONNECT) + +label(ADDRESS_IP_SENDTO)dit(bf(tt(IP-SENDTO::))) + Opens a raw IP socket. Depending on host specification or option link(pf)(OPTION_PROTOCOL_FAMILY), IP procotol version + 4 or 6 is used. It uses link()(TYPE_PROTOCOL) to send packets + to [link(IP address)(TYPE_IP_ADDRESS)] and receives packets from + host, ignores packets from other hosts. + Protocol 255 uses the raw socket with the IP header being part of the + data.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6) nl() + Useful options: + link(pf)(OPTION_PROTOCOL_FAMILY), + link(ttl)(OPTION_TTL) + See also: + link(IP4-SENDTO)(ADDRESS_IP4_SENDTO), + link(IP6-SENDTO)(ADDRESS_IP6_SENDTO), + link(IP-RECVFROM)(ADDRESS_IP_RECVFROM), + link(IP-RECV)(ADDRESS_IP_RECV), + link(UDP-SENDTO)(ADDRESS_UDP_SENDTO) + link(UNIX-SENDTO)(ADDRESS_UNIX_SENDTO) +label(ADDRESS_IP4_SENDTO)dit(bf(tt(IP4-SENDTO::))) + Like link(IP-SENDTO)(ADDRESS_IP_SENDTO), but always uses IPv4.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4) nl() +label(ADDRESS_IP6_SENDTO)dit(bf(tt(IP6-SENDTO::))) + Like link(IP-SENDTO)(ADDRESS_IP_SENDTO), but always uses IPv6.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP6)(GROUP_IP6) nl() + +label(ADDRESS_IP_DATAGRAM)dit(bf(tt(IP-DATAGRAM:
    :))) + Sends outgoing data to the specified address which may in particular be a + broadcast or multicast address. Packets arriving on the local socket are + checked if their source addresses match + eventual link(RANGE)(OPTION_RANGE) or link(TCPWRAP)(OPTION_TCPWRAPPERS) + options. This address type can for example be used for implementing + symmetric or asymmetric broadcast or multicast communications.nl() + Option groups: link(FD)(GROUP_FD), link(SOCKET)(GROUP_SOCKET), + link(IP4)(GROUP_IP4), link(IP6)(GROUP_IP6), link(RANGE)(GROUP_RANGE) nl() + Useful options: + link(range)(OPTION_RANGE), + link(tcpwrap)(OPTION_TCPWRAPPERS), + link(broadcast)(OPTION_SO_BROADCAST), + link(ip-multicast-loop)(OPTION_IP_MULTICAST_LOOP), + link(ip-multicast-ttl)(OPTION_IP_MULTICAST_TTL), + link(ip-multicast-if)(OPTION_IP_MULTICAST_IF), + link(ip-add-membership)(OPTION_IP_ADD_MEMBERSHIP), + link(ttl)(OPTION_TTL), + link(tos)(OPTION_TOS), + link(bind)(OPTION_BIND), + link(pf)(OPTION_PROTOCOL_FAMILY)nl() + See also: + link(IP4-DATAGRAM)(ADDRESS_IP4_DATAGRAM), + link(IP6-DATAGRAM)(ADDRESS_IP6_DATAGRAM), + link(IP-SENDTO)(ADDRESS_IP_SENDTO), + link(IP-RECVFROM)(ADDRESS_IP_RECVFROM), + link(IP-RECV)(ADDRESS_IP_RECV), + link(UDP-DATAGRAM)(ADDRESS_UDP_DATAGRAM) +label(ADDRESS_IP4_DATAGRAM)dit(bf(tt(IP4-DATAGRAM::))) + Like link(IP-DATAGRAM)(ADDRESS_IP_DATAGRAM), but always uses IPv4. + (link(example)(EXAMPLE_ADDRESS_IP4_BROADCAST_CLIENT))nl() + Option groups: link(FD)(GROUP_FD), link(SOCKET)(GROUP_SOCKET), + link(IP4)(GROUP_IP4), link(RANGE)(GROUP_RANGE) nl() +label(ADDRESS_IP6_DATAGRAM)dit(bf(tt(IP6-DATAGRAM::))) + Like link(IP-DATAGRAM)(ADDRESS_IP_DATAGRAM), but always uses IPv6. Please + note that IPv6 does not know broadcasts.nl() + Option groups: link(FD)(GROUP_FD), link(SOCKET)(GROUP_SOCKET), + link(IP6)(GROUP_IP6), link(RANGE)(GROUP_RANGE) nl() + +label(ADDRESS_IP_RECVFROM)dit(bf(tt(IP-RECVFROM:))) + Opens a raw IP socket of link()(TYPE_PROTOCOL). Depending on option link(pf)(OPTION_PROTOCOL_FAMILY), IP procotol version + 4 or 6 is used. It receives one packet from an unspecified peer and may send one or more answer packets to that peer. + This mode is particularly useful with fork option where each arriving packet - from arbitrary peers - is handled by its own sub process. + This allows a behaviour similar to typical UDP based servers like ntpd or named. + This address works well with IP-SENDTO address peers (see above). + Protocol 255 uses the raw socket with the IP header being part of the + data.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(pf)(OPTION_PROTOCOL_FAMILY), + link(fork)(OPTION_FORK), + link(range)(OPTION_RANGE), + link(ttl)(OPTION_TTL), + link(broadcast)(OPTION_SO_BROADCAST)nl() + See also: + link(IP4-RECVFROM)(ADDRESS_IP4_RECVFROM), + link(IP6-RECVFROM)(ADDRESS_IP6_RECVFROM), + link(IP-SENDTO)(ADDRESS_IP_SENDTO), + link(IP-RECV)(ADDRESS_IP_RECV), + link(UDP-RECVFROM)(ADDRESS_UDP_RECVFROM), + link(UNIX-RECVFROM)(ADDRESS_UNIX_RECVFROM) +label(ADDRESS_IP4_RECVFROM)dit(bf(tt(IP4-RECVFROM:))) + Like link(IP-RECVFROM)(ADDRESS_IP_RECVFROM), but always uses IPv4.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE) nl() +label(ADDRESS_IP6_RECVFROM)dit(bf(tt(IP6-RECVFROM:))) + Like link(IP-RECVFROM)(ADDRESS_IP_RECVFROM), but always uses IPv6.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP6)(GROUP_IP6),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE) nl() + +label(ADDRESS_IP_RECV)dit(bf(tt(IP-RECV:))) + Opens a raw IP socket of link()(TYPE_PROTOCOL). Depending on option link(pf)(OPTION_PROTOCOL_FAMILY), IP procotol version + 4 or 6 is used. It receives packets from multiple unspecified peers and merges the data. + No replies are possible. + It can be, e.g., addressed by socat IP-SENDTO address peers. + Protocol 255 uses the raw socket with the IP header being part of the + data.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(RANGE)(GROUP_RANGE) nl() + Useful options: + link(pf)(OPTION_PROTOCOL_FAMILY), + link(range)(OPTION_RANGE)nl() + See also: + link(IP4-RECV)(ADDRESS_IP4_RECV), + link(IP6-RECV)(ADDRESS_IP6_RECV), + link(IP-SENDTO)(ADDRESS_IP_SENDTO), + link(IP-RECVFROM)(ADDRESS_IP_RECVFROM), + link(UDP-RECV)(ADDRESS_UDP_RECV), + link(UNIX-RECV)(ADDRESS_UNIX_RECV) +label(ADDRESS_IP4_RECV)dit(bf(tt(IP4-RECV:))) + Like link(IP-RECV)(ADDRESS_IP_RECV), but always uses IPv4.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(RANGE)(GROUP_RANGE) nl() +label(ADDRESS_IP6_RECV)dit(bf(tt(IP6-RECV:))) + Like link(IP-RECV)(ADDRESS_IP_RECV), but always uses IPv6.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP6)(GROUP_IP6),link(RANGE)(GROUP_RANGE) nl() + +label(ADDRESS_OPEN)dit(bf(tt(OPEN:))) + Opens link()(TYPE_FILENAME) using the code(open()) system call + (link(example)(EXAMPLE_ADDRESS_OPEN)). + This operation fails on unixdomain() sockets. nl() + Note: This address type is rarly useful in bidirectional mode.nl() + Option groups: link(FD)(GROUP_FD),link(REG)(GROUP_REG),link(NAMED)(GROUP_NAMED),link(OPEN)(GROUP_OPEN) nl() + Useful options: + link(creat)(OPTION_CREAT), + link(excl)(OPTION_EXCL), + link(noatime)(OPTION_O_NOATIME), + link(nofollow)(OPTION_NOFOLLOW), + link(append)(OPTION_APPEND), + link(rdonly)(OPTION_RDONLY), + link(wronly)(OPTION_WRONLY), + link(lock)(OPTION_LOCK), + link(readbytes)(OPTION_READBYTES), + link(ignoreeof)(OPTION_IGNOREEOF)nl() + See also: + link(CREATE)(ADDRESS_CREAT), + link(GOPEN)(ADDRESS_GOPEN), + link(UNIX-CONNECT)(ADDRESS_UNIX_CONNECT) +label(ADDRESS_OPENSSL_CONNECT)dit(bf(tt(OPENSSL::))) + Tries to establish a SSL connection to [link(TCP + service)(TYPE_TCP_SERVICE)] on + [link(IP address)(TYPE_IP_ADDRESS)] using TCP/IP version 4 or 6 + depending on address specification, name resolution, or option + link(pf)(OPTION_PROTOCOL_FAMILY).nl() + NOTE: The server certificate is only checked for validity against + link(cafile)(OPTION_OPENSSL_CAFILE) or link(capath)(OPTION_OPENSSL_CAPATH), + but not for match with the server's name or its IP address!nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(TCP)(GROUP_TCP),link(OPENSSL)(GROUP_OPENSSL),link(RETRY)(GROUP_RETRY) nl() + Useful options: + link(cipher)(OPTION_OPENSSL_CIPHERLIST), + link(method)(OPTION_OPENSSL_METHOD), + link(verify)(OPTION_OPENSSL_VERIFY), + link(cafile)(OPTION_OPENSSL_CAFILE), + link(capath)(OPTION_OPENSSL_CAPATH), + link(certificate)(OPTION_OPENSSL_CERTIFICATE), + link(bind)(OPTION_BIND), + link(pf)(OPTION_PROTOCOL_FAMILY), + link(connect-timeout)(OPTION_CONNECT_TIMEOUT), + link(sourceport)(OPTION_SOURCEPORT), + link(retry)(OPTION_RETRY)nl() + See also: + link(OPENSSL-LISTEN)(ADDRESS_OPENSSL_LISTEN), + link(TCP)(ADDRESS_TCP_CONNECT) +label(ADDRESS_OPENSSL_LISTEN)dit(bf(tt(OPENSSL-LISTEN:))) + Listens on tcp [link(TCP service)(TYPE_TCP_SERVICE)]. + The IP version is 4 or the one specified with + link(pf)(OPTION_PROTOCOL_FAMILY). When a + connection is accepted, this address behaves as SSL server.nl() + Note: You probably want to use the link(certificate)(OPTION_OPENSSL_CERTIFICATE) option with this address.nl() + NOTE: The client certificate is only checked for validity against + link(cafile)(OPTION_OPENSSL_CAFILE) or link(capath)(OPTION_OPENSSL_CAPATH), + but not for match with the client's name or its IP address!nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(TCP)(GROUP_TCP),link(LISTEN)(GROUP_LISTEN),link(OPENSSL)(GROUP_OPENSSL),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE),link(RETRY)(GROUP_RETRY) nl() + Useful options: + link(pf)(OPTION_PROTOCOL_FAMILY), + link(cipher)(OPTION_OPENSSL_CIPHERLIST), + link(method)(OPTION_OPENSSL_METHOD), + link(verify)(OPTION_OPENSSL_VERIFY), + link(cafile)(OPTION_OPENSSL_CAFILE), + link(capath)(OPTION_OPENSSL_CAPATH), + link(certificate)(OPTION_OPENSSL_CERTIFICATE), + link(fork)(OPTION_FORK), + link(bind)(OPTION_BIND), + link(range)(OPTION_RANGE), + link(tcpwrap)(OPTION_TCPWRAPPERS), + link(su)(OPTION_SUBSTUSER), + link(reuseaddr)(OPTION_REUSEADDR), + link(retry)(OPTION_RETRY)nl() + See also: + link(OPENSSL)(ADDRESS_OPENSSL_CONNECT), + link(TCP)(ADDRESS_TCP_CONNECT) +label(ADDRESS_NAMED_PIPE)dit(bf(tt(PIPE:))) + If link()(TYPE_FILENAME) already exists, it is opened. + If is does not exist, a named pipe is created and opened. Beginning with + socat version 1.4.3, the named pipe is removed when the address is closed + (but see option link(unlink-close)(OPTION_UNLINK_CLOSE)nl() + Note: When a pipe is used for both reading and writing, it works + as echo service.nl() + Note: When a pipe is used for both reading and writing, and socat tries + to write more bytes than the pipe can buffer (Linux 2.4: 2048 bytes), socat + might block. Consider using socat option, e.g., code(-b 2048) nl() + 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(group)(OPTION_GROUP), + link(user)(OPTION_USER), + link(mode)(OPTION_MODE), + link(unlink-early)(OPTION_UNLINK_EARLY)nl() + 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 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 + option code(-b 2048) nl() + Option groups: link(FD)(GROUP_FD) nl() + See also: link(named pipe)(ADDRESS_NAMED_PIPE) +label(ADDRESS_PROXY_CONNECT)dit(bf(tt(PROXY:::))) + Connects to an HTTP proxy server on port 8080 using TCP/IP version 4 or 6 + depending on address specification, name resolution, or option + link(pf)(OPTION_PROTOCOL_FAMILY), and sends a CONNECT + request for hostname:port. If the proxy grants access and succeeds to + connect to the target, data transfer between socat and the target can + start. Note that the traffic need not be HTTP but can be an arbitrary + protocol. nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(TCP)(GROUP_TCP),link(HTTP)(GROUP_HTTP),link(RETRY)(GROUP_RETRY) nl() + Useful options: + link(proxyport)(OPTION_PROXYPORT), + link(ignorecr)(OPTION_IGNORECR), + link(proxyauth)(OPTION_PROXY_AUTHORIZATION), + link(resolve)(OPTION_PROXY_RESOLVE), + link(crnl)(OPTION_CRNL), + link(bind)(OPTION_BIND), + link(connect-timeout)(OPTION_CONNECT_TIMEOUT), + link(mss)(OPTION_MSS), + link(sourceport)(OPTION_SOURCEPORT), + link(retry)(OPTION_RETRY) nl() + See also: link(SOCKS)(ADDRESS_SOCKS4), link(TCP)(ADDRESS_TCP_CONNECT) +label(ADDRESS_PTY)dit(bf(tt(PTY))) + Generates a pseudo terminal (pty) and uses its master side. Another process + may open the pty's slave side using it like a serial line or terminal. + (link(example)(EXAMPLE_ADDRESS_PTY)). If + both the ptmx and the openpty mechanisms are available, ptmx is used + (POSIX).nl() + Option groups: link(FD)(GROUP_FD),link(NAMED)(GROUP_NAMED),link(PTY)(GROUP_PTY),link(TERMIOS)(GROUP_TERMIOS) nl() + Useful options: + link(link)(OPTION_SYMBOLIC_LINK), + link(openpty)(OPTION_OPENPTY), + link(wait-slave)(OPTION_PTY_WAIT_SLAVE), + link(mode)(OPTION_MODE), + link(user)(OPTION_USER), + link(group)(OPTION_GROUP)nl() + See also: + link(UNIX-LISTEN)(ADDRESS_UNIX_LISTEN), + link(PIPE)(ADDRESS_NAMED_PIPE), + link(EXEC)(ADDRESS_EXEC), link(SYSTEM)(ADDRESS_SYSTEM) +label(ADDRESS_READLINE)dit(bf(tt(READLINE))) + Uses GNU readline and history on stdio to allow editing and reusing input + lines (link(example)(EXAMPLE_ADDRESS_READLINE)). This requires the GNU readline and + history libraries. Note that stdio should be a (pseudo) terminal device, + otherwise readline does not seem to work.nl() + Option groups: link(FD)(GROUP_FD),link(READLINE)(GROUP_READLINE),link(TERMIOS)(GROUP_TERMIOS) nl() + Useful options: + link(history)(OPTION_HISTORY), + link(noecho)(OPTION_NOECHO)nl() + See also: + link(STDIO)(ADDRESS_STDIO) +label(ADDRESS_SOCKS4)dit(bf(tt(SOCKS4:::))) + Connects via [link(IP address)(TYPE_IP_ADDRESS)] + to [link(IPv4 address)(TYPE_IPV4_ADDRESS)] + on [link(TCP service)(TYPE_TCP_SERVICE)], + using socks version 4 protocol over IP version 4 or 6 depending on address specification, name resolution, or option + link(pf)(OPTION_PROTOCOL_FAMILY) (link(example)(EXAMPLE_ADDRESS_SOCKS4)).nl() + 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() + Useful options: + link(socksuser)(OPTION_SOCKSUSER), + link(socksport)(OPTION_SOCKSPORT), + link(sourceport)(OPTION_SOURCEPORT), + link(pf)(OPTION_PROTOCOL_FAMILY), + link(retry)(OPTION_RETRY)nl() + See also: + link(SOCKS4A)(ADDRESS_SOCKS4A), + link(PROXY)(ADDRESS_PROXY_CONNECT), + link(TCP)(ADDRESS_TCP_CONNECT) +label(ADDRESS_SOCKS4A)dit(bf(tt(SOCKS4A:::))) + like link(SOCKS4)(ADDRESS_SOCKS4), but uses socks protocol version 4a, thus + leaving host name resolution to the socks server.nl() + 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_STDERR)dit(bf(tt(STDERR))) + Uses file descriptor 2.nl() + Option groups: link(FD)(GROUP_FD) (link(TERMIOS)(GROUP_TERMIOS),link(REG)(GROUP_REG),link(SOCKET)(GROUP_SOCKET)) nl() + See also: link(FD)(ADDRESS_FD) +label(ADDRESS_STDIN)dit(bf(tt(STDIN))) + Uses file descriptor 0.nl() + Option groups: link(FD)(GROUP_FD) (link(TERMIOS)(GROUP_TERMIOS),link(REG)(GROUP_REG),link(SOCKET)(GROUP_SOCKET)) nl() + Useful options: + link(readbytes)(OPTION_READBYTES)nl() + See also: link(FD)(ADDRESS_FD) +label(ADDRESS_STDIO)dit(bf(tt(STDIO))) + Uses file descriptor 0 for reading, and 1 for writing.nl() + Option groups: link(FD)(GROUP_FD) (link(TERMIOS)(GROUP_TERMIOS),link(REG)(GROUP_REG),link(SOCKET)(GROUP_SOCKET)) nl() + Useful options: + link(readbytes)(OPTION_READBYTES)nl() + See also: link(FD)(ADDRESS_FD) +label(ADDRESS_STDOUT)dit(bf(tt(STDOUT))) + Uses file descriptor 1.nl() + Option groups: link(FD)(GROUP_FD) (link(TERMIOS)(GROUP_TERMIOS),link(REG)(GROUP_REG),link(SOCKET)(GROUP_SOCKET)) nl() + See also: link(FD)(ADDRESS_FD) +label(ADDRESS_SYSTEM)dit(bf(tt(SYSTEM:))) + Forks a sub process that establishes communication with its parent process + and invokes the specified program with code(system()). Please note that + [link(string)(TYPE_STRING)] must + not contain ',' or "!!", and that shell meta characters may have to be + protected. + After successful program start, socat() writes data to stdin of the + process and reads from its stdout.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(EXEC)(GROUP_EXEC),link(FORK)(GROUP_FORK),link(TERMIOS)(GROUP_TERMIOS) nl() + Useful options: + link(path)(OPTION_PATH), + link(fdin)(OPTION_FDIN), + link(fdout)(OPTION_FDOUT), + link(chroot)(OPTION_CHROOT), + link(su)(OPTION_SUBSTUSER), + link(su-d)(OPTION_SUBSTUSER_DELAYED), + link(nofork)(OPTION_NOFORK), + link(pty)(OPTION_PTY), + link(stderr)(OPTION_STDERR), + link(ctty)(OPTION_CTTY), + link(setsid)(OPTION_SETSID), + link(pipes)(OPTION_PIPES), + link(sigint)(OPTION_SIGINT), + link(sigquit)(OPTION_SIGQUIT)nl() + See also: link(EXEC)(ADDRESS_EXEC) +label(ADDRESS_TCP_CONNECT)dit(bf(tt(TCP::))) + Connects to [link(TCP service)(TYPE_TCP_SERVICE)] on + [link(IP address)(TYPE_IP_ADDRESS)] using TCP/IP version 4 or 6 + depending on address specification, name resolution, or option + link(pf)(OPTION_PROTOCOL_FAMILY).nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(TCP)(GROUP_TCP),link(RETRY)(GROUP_RETRY) nl() + Useful options: + link(crnl)(OPTION_CRNL), + link(bind)(OPTION_BIND), + link(pf)(OPTION_PROTOCOL_FAMILY), + link(connect-timeout)(OPTION_CONNECT_TIMEOUT), + link(tos)(OPTION_TOS), + link(mtudiscover)(OPTION_MTUDISCOVER), + link(mss)(OPTION_MSS), + link(nodelay)(OPTION_NODELAY), + link(nonblock)(OPTION_NONBLOCK), + link(sourceport)(OPTION_SOURCEPORT), + link(retry)(OPTION_RETRY), + link(readbytes)(OPTION_READBYTES)nl() + See also: + link(TCP4)(ADDRESS_TCP4_CONNECT), + link(TCP6)(ADDRESS_TCP6_CONNECT), + link(TCP-LISTEN)(ADDRESS_TCP_LISTEN), + link(UDP)(ADDRESS_UDP_CONNECT), + link(UNIX-CONNECT)(ADDRESS_UNIX_CONNECT) +label(ADDRESS_TCP4_CONNECT)dit(bf(tt(TCP4::))) + Like link(TCP)(ADDRESS_TCP_CONNECT), but only supports IPv4 protocol (link(example)(EXAMPLE_ADDRESS_TCP4_CONNECT)).nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(TCP)(GROUP_TCP),link(RETRY)(GROUP_RETRY) nl() +label(ADDRESS_TCP6_CONNECT)dit(bf(tt(TCP6::))) + Like link(TCP)(ADDRESS_TCP_CONNECT), but only supports IPv6 protocol.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP6)(GROUP_IP6),link(TCP)(GROUP_TCP),link(RETRY)(GROUP_RETRY) nl() +label(ADDRESS_TCP_LISTEN)dit(bf(tt(TCP-LISTEN:))) + Listens on [link(TCP service)(TYPE_TCP_SERVICE)] and accepts a + TCP/IP connection. The IP version is 4 or the one specified with + link(pf)(OPTION_PROTOCOL_FAMILY). + Note that opening + this address usually blocks until a client connects.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(LISTEN)(GROUP_LISTEN),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(TCP)(GROUP_TCP),link(RETRY)(GROUP_RETRY) nl() + Useful options: + link(crnl)(OPTION_CRNL), + link(fork)(OPTION_FORK), + link(bind)(OPTION_BIND), + link(range)(OPTION_RANGE), + link(tcpwrap)(OPTION_TCPWRAPPERS), + link(pf)(OPTION_PROTOCOL_FAMILY), + link(backlog)(OPTION_BACKLOG), + link(mss)(OPTION_MSS), + link(su)(OPTION_SUBSTUSER), + link(reuseaddr)(OPTION_REUSEADDR), + link(retry)(OPTION_RETRY), + link(retry)(OPTION_COOL_WRITE)nl() + See also: + link(TCP4-LISTEN)(ADDRESS_TCP4_CONNECT), + link(TCP6-LISTEN)(ADDRESS_TCP6_LISTEN), + link(UDP-LISTEN)(ADDRESS_UDP_LISTEN), + link(UNIX-LISTEN)(ADDRESS_UNIX_LISTEN), + link(OPENSSL-LISTEN)(ADDRESS_OPENSSL_LISTEN) +label(ADDRESS_TCP4_LISTEN)dit(bf(tt(TCP4-LISTEN:))) + Like link(TCP-LISTEN)(ADDRESS_TCP_LISTEN), but only supports IPv4 + protocol (link(example)(EXAMPLE_ADDRESS_TCP4_LISTEN)).nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(LISTEN)(GROUP_LISTEN),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE),link(IP4)(GROUP_IP4),link(TCP)(GROUP_TCP),link(RETRY)(GROUP_RETRY) nl() +label(ADDRESS_TCP6_LISTEN)dit(bf(tt(TCP6-LISTEN:))) + Like link(TCP-LISTEN)(ADDRESS_TCP_LISTEN), but only supports IPv6 + protocol.nl() + Additional useful option: + 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:/))) + Creates a Linux TUN/TAP device and assignes to it the address and netmask + defined by the parameters. The resulting network interface is ready for use + by other processes; socat serves its "wire side". This address requires read + and write access to the tunnel cloning device, usually code(/dev/net/tun). + nl() + Option groups: link(FD)(GROUP_FD),link(NAMED)(GROUP_NAMED),link(OPEN)(GROUP_OPEN),link(TUN)(GROUP_TUN) nl() + Useful options: + link(iff-up)(OPTION_IFF_UP), + link(tun-device)(OPTION_TUN_DEVICE), + link(tun-name)(OPTION_TUN_NAME), + link(tun-type)(OPTION_TUN_TYPE), + link(iff-no-pi)(OPTION_IFF_NO_PI) nl() + See also: + link(ip-recv)(ADDRESS_IP_RECV) +label(ADDRESS_UDP_CONNECT)dit(bf(tt(UDP::))) + Connects to [link(UDP service)(TYPE_UDP_SERVICE)] on + [link(IP address)(TYPE_IP_ADDRESS)] using UDP/IP version 4 or 6 + depending on address specification, name resolution, or option + link(pf)(OPTION_PROTOCOL_FAMILY).nl() + Please note that, + due to UDP protocol properties, no real connection is established; data has + to be sent for `connecting' to the server, and no end-of-file condition can + be transported.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), + link(tos)(OPTION_TOS), + link(bind)(OPTION_BIND), + link(sourceport)(OPTION_SOURCEPORT), + link(pf)(OPTION_PROTOCOL_FAMILY)nl() + See also: + link(UDP4)(ADDRESS_UDP4_CONNECT), + link(UDP6)(ADDRESS_UDP6_CONNECT), + link(UDP-LISTEN)(ADDRESS_UDP_LISTEN), + link(TCP)(ADDRESS_TCP_CONNECT), + link(IP)(ADDRESS_IP_SENDTO) +label(ADDRESS_UDP4_CONNECT)dit(bf(tt(UDP4::))) + Like link(UDP)(ADDRESS_UDP_CONNECT), but only supports IPv4 protocol.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4) nl() +label(ADDRESS_UDP6_CONNECT)dit(bf(tt(UDP6::))) + Like link(UDP)(ADDRESS_UDP_CONNECT), but only supports IPv6 protocol.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP6)(GROUP_IP6) nl() +label(ADDRESS_UDP_DATAGRAM)dit(bf(tt(UDP-DATAGRAM:
    :))) + Sends outgoing data to the specified address which may in particular be a + broadcast or multicast address. Packets arriving on the local socket are + checked for the correct remote port and if their source addresses match + eventual link(RANGE)(OPTION_RANGE) or link(TCPWRAP)(OPTION_TCPWRAPPERS) + options. This address type can for example be used for implementing + symmetric or asymmetric broadcast or multicast communications.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(RANGE)(GROUP_RANGE) nl() + Useful options: + link(range)(OPTION_RANGE), + link(tcpwrap)(OPTION_TCPWRAPPERS), + link(broadcast)(OPTION_SO_BROADCAST), + link(ip-multicast-loop)(OPTION_IP_MULTICAST_LOOP), + link(ip-multicast-ttl)(OPTION_IP_MULTICAST_TTL), + link(ip-multicast-if)(OPTION_IP_MULTICAST_IF), + link(ip-add-membership)(OPTION_IP_ADD_MEMBERSHIP), + link(ttl)(OPTION_TTL), + link(tos)(OPTION_TOS), + link(bind)(OPTION_BIND), + link(sourceport)(OPTION_SOURCEPORT), + link(pf)(OPTION_PROTOCOL_FAMILY)nl() + See also: + link(UDP4-DATAGRAM)(ADDRESS_UDP4_DATAGRAM), + link(UDP6-DATAGRAM)(ADDRESS_UDP6_DATAGRAM), + link(UDP-SENDTO)(ADDRESS_UDP_SENDTO), + link(UDP-RECVFROM)(ADDRESS_UDP_RECVFROM), + link(UDP-RECV)(ADDRESS_UDP_RECV), + link(UDP-CONNECT)(ADDRESS_UDP_CONNECT), + link(UDP-LISTEN)(ADDRESS_UDP_LISTEN), + link(IP-DATAGRAM)(ADDRESS_IP_DATAGRAM) +label(ADDRESS_UDP4_DATAGRAM)dit(bf(tt(UDP4-DATAGRAM:
    :))) + Like link(UDP-DATAGRAM)(ADDRESS_UDP_DATAGRAM), but only supports IPv4 + protocol (link(example1)(EXAMPLE_ADDRESS_UDP4_BROADCAST_CLIENT), + link(example2)(EXAMPLE_ADDRESS_UDP4_MULTICAST)).nl() + Option groups: link(FD)(GROUP_FD), link(SOCKET)(GROUP_SOCKET), + link(IP4)(GROUP_IP4), link(RANGE)(GROUP_RANGE) +label(ADDRESS_UDP6_DATAGRAM)dit(bf(tt(UDP6-DATAGRAM:
    :))) + Like link(UDP-DATAGRAM)(ADDRESS_UDP_DATAGRAM), but only supports IPv6 + protocol.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET), + link(IP6)(GROUP_IP6),link(RANGE)(GROUP_RANGE) +label(ADDRESS_UDP_LISTEN)dit(bf(tt(UDP-LISTEN:))) + Waits for a UDP/IP packet arriving on + [link(UDP service)(TYPE_UDP_SERVICE)] and `connects' back to sender. + The accepted IP version is 4 or the one specified with option + link(pf)(OPTION_PROTOCOL_FAMILY). + Please note that, + due to UDP protocol properties, no real connection is established; data has + to arrive from the peer first, and no end-of-file condition can be + transported. Note that opening + this address usually blocks until a client connects.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(LISTEN)(GROUP_LISTEN),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6) nl() + Useful options: + link(fork)(OPTION_FORK), + link(bind)(OPTION_BIND), + link(range)(OPTION_RANGE), + link(pf)(OPTION_PROTOCOL_FAMILY) nl() + See also: + link(UDP)(ADDRESS_UDP_CONNECT), + link(UDP4-LISTEN)(ADDRESS_UDP4_LISTEN), + link(UDP6-LISTEN)(ADDRESS_UDP6_LISTEN), + link(TCP-LISTEN)(ADDRESS_TCP_LISTEN) +label(ADDRESS_UDP4_LISTEN)dit(bf(tt(UDP4-LISTEN:))) + Like link(UDP-LISTEN)(ADDRESS_UDP_LISTEN), but only support IPv4 + protocol.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(LISTEN)(GROUP_LISTEN),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE),link(IP4)(GROUP_IP4) nl() +label(ADDRESS_UDP6_LISTEN)dit(bf(tt(UDP6-LISTEN:))) + Like link(UDP-LISTEN)(ADDRESS_UDP_LISTEN), but only support IPv6 + protocol.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) nl() +label(ADDRESS_UDP_SENDTO)dit(bf(tt(UDP-SENDTO::))) + Communicates with the specified peer socket, defined by [link(UDP + service)(TYPE_UDP_SERVICE)] on + [link(IP address)(TYPE_IP_ADDRESS)], using UDP/IP version 4 or 6 + depending on address specification, name resolution, or option + 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() + 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), + link(tos)(OPTION_TOS), + link(bind)(OPTION_BIND), + link(sourceport)(OPTION_SOURCEPORT), + link(pf)(OPTION_PROTOCOL_FAMILY)nl() + See also: + link(UDP4-SENDTO)(ADDRESS_UDP4_SENDTO), + link(UDP6-SENDTO)(ADDRESS_UDP6_SENDTO), + link(UDP-RECVFROM)(ADDRESS_UDP_RECVFROM), + link(UDP-RECV)(ADDRESS_UDP_RECV), + link(UDP-CONNECT)(ADDRESS_UDP_CONNECT), + link(UDP-LISTEN)(ADDRESS_UDP_LISTEN), + link(IP-SENDTO)(ADDRESS_IP_SENDTO) +label(ADDRESS_UDP4_SENDTO)dit(bf(tt(UDP4-SENDTO::))) + Like link(UDP-SENDTO)(ADDRESS_UDP_SENDTO), but only supports IPv4 + protocol.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4) +label(ADDRESS_UDP6_SENDTO)dit(bf(tt(UDP6-SENDTO::))) + Like link(UDP-SENDTO)(ADDRESS_UDP_SENDTO), but only supports IPv6 + protocol.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP6)(GROUP_IP6) + +label(ADDRESS_UDP_RECVFROM)dit(bf(tt(UDP-RECVFROM:))) + Creates a UDP socket on [link(UDP service)(TYPE_UDP_SERVICE)] using + UDP/IP version 4 or 6 + depending on option link(pf)(OPTION_PROTOCOL_FAMILY). + It receives one packet from an unspecified peer and may send one or more + answer packets to that peer. This mode is particularly useful with fork + option + where each arriving packet - from arbitrary peers - is handled by its own sub + process. This allows a behaviour similar to typical UDP based servers like ntpd + or named. This address works well with socat SENDTO address peers.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), + link(ttl)(OPTION_TTL), + link(tos)(OPTION_TOS), + link(bind)(OPTION_BIND), + link(sourceport)(OPTION_SOURCEPORT), + link(pf)(OPTION_PROTOCOL_FAMILY)nl() + See also: + link(UDP4-RECVFROM)(ADDRESS_UDP4_RECVFROM), + link(UDP6-RECVFROM)(ADDRESS_UDP6_RECVFROM), + link(UDP-SENDTO)(ADDRESS_UDP_SENDTO), + link(UDP-RECV)(ADDRESS_UDP_RECV), + link(UDP-CONNECT)(ADDRESS_UDP_CONNECT), + link(UDP-LISTEN)(ADDRESS_UDP_LISTEN), + link(IP-RECVFROM)(ADDRESS_IP_RECVFROM), + link(UNIX-RECVFROM)(ADDRESS_UNIX_RECVFROM) +label(ADDRESS_UDP4_RECVFROM)dit(bf(tt(UDP4-RECVFROM:))) + Like link(UDP-RECVFROM)(ADDRESS_UDP_RECVFROM), but only supports IPv4 protocol.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE) +label(ADDRESS_UDP6_RECVFROM)dit(bf(tt(UDP6-RECVFROM:))) + Like link(UDP-RECVFROM)(ADDRESS_UDP_RECVFROM), but only supports IPv6 protocol.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP6)(GROUP_IP6),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE) + +label(ADDRESS_UDP_RECV)dit(bf(tt(UDP-RECV:))) + Creates a UDP socket on [link(UDP service)(TYPE_UDP_SERVICE)] using UDP/IP version 4 or 6 + depending on option link(pf)(OPTION_PROTOCOL_FAMILY). + It receives packets from multiple unspecified peers and merges the data. + No replies are possible. It works well with, e.g., socat UDP-SENDTO address peers; it behaves similar to a syslog server.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(RANGE)(GROUP_RANGE) nl() + Useful options: + link(fork)(OPTION_FORK), + link(pf)(OPTION_PROTOCOL_FAMILY), + link(bind)(OPTION_BIND), + link(sourceport)(OPTION_SOURCEPORT), + link(ttl)(OPTION_TTL), + link(tos)(OPTION_TOS)nl() + See also: + link(UDP4-RECV)(ADDRESS_UDP4_RECV), + link(UDP6-RECV)(ADDRESS_UDP6_RECV), + link(UDP-SENDTO)(ADDRESS_UDP_SENDTO), + link(UDP-RECVFROM)(ADDRESS_UDP_RECVFROM), + link(UDP-CONNECT)(ADDRESS_UDP_CONNECT), + link(UDP-LISTEN)(ADDRESS_UDP_LISTEN), + link(IP-RECV)(ADDRESS_IP_RECV), + link(UNIX-RECV)(ADDRESS_UNIX_RECV) +label(ADDRESS_UDP4_RECV)dit(bf(tt(UDP4-RECV:))) + Like link(UDP-RECV)(ADDRESS_UDP_RECV), but only supports IPv4 protocol.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(RANGE)(GROUP_RANGE) +label(ADDRESS_UDP6_RECV)dit(bf(tt(UDP6-RECV:))) + Like link(UDP-RECV)(ADDRESS_UDP_RECV), but only supports IPv6 protocol.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP6)(GROUP_IP6),link(RANGE)(GROUP_RANGE) + +label(ADDRESS_UNIX_CONNECT)dit(bf(tt(UNIX-CONNECT:))) + Connects to link()(TYPE_FILENAME) assuming it is a unixdomain() + socket. + If does not exist, this is an error; + if is not a unixdomain() socket, this is an error; + if is a unixdomain() socket, but no process is listening, this is + an error.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET), + link(NAMED)(GROUP_NAMED),link(RETRY)(GROUP_RETRY), + link(UNIX)(GROUP_SOCK_UNIX) nl()) + Useful options: + link(bind)(OPTION_BIND)nl() + See also: + link(UNIX-LISTEN)(ADDRESS_UNIX_LISTEN), + link(UNIX-SENDTO)(ADDRESS_UNIX_SENDTO), + link(TCP)(ADDRESS_TCP_CONNECT) + +label(ADDRESS_UNIX_LISTEN)dit(bf(tt(UNIX-LISTEN:))) + Listens on link()(TYPE_FILENAME) using a unixdomain() stream + socket and accepts a connection. + If exists and is not a socket, this is an error. + If exists and is a unixdomain() socket, binding to the address + fails (use option link(unlink-early)(OPTION_UNLINK_EARLY)!). + Note that opening this address usually blocks until a client connects. + Beginning with socat version 1.4.3, the file system entry is removed when + this address is closed (but see option link(unlink-close)(OPTION_UNLINK_CLOSE)) (link(example)(EXAMPLE_ADDRESS_UNIX_LISTEN)).nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET), + link(NAMED)(GROUP_NAMED),link(LISTEN)(GROUP_LISTEN), + link(CHILD)(GROUP_CHILD),link(RETRY)(GROUP_RETRY), + link(UNIX)(GROUP_SOCK_UNIX) nl() + Useful options: + link(fork)(OPTION_FORK), + link(umask)(OPTION_UMASK), + link(mode)(OPTION_MODE), + link(user)(OPTION_USER), + link(group)(OPTION_GROUP), + link(unlink-early)(OPTION_UNLINK_EARLY)nl() + See also: + link(UNIX-CONNECT)(ADDRESS_UNIX_CONNECT), + link(UNIX-RECVFROM)(ADDRESS_UNIX_RECVFROM), + link(UNIX-RECV)(ADDRESS_UNIX_RECV), + link(TCP-LISTEN)(ADDRESS_TCP4_LISTEN) + +label(ADDRESS_UNIX_SENDTO)dit(bf(tt(UNIX-SENDTO:))) + Communicates with the specified peer socket, defined by [link()(TYPE_FILENAME)] assuming it is a unixdomain() datagram socket. + It sends packets to and receives packets from that peer socket only. + It works well with socat UNIX-RECVFROM and UNIX-RECV address peers.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET), + link(NAMED)(GROUP_NAMED),link(UNIX)(GROUP_SOCK_UNIX)nl() + Useful options: + link(bind)(OPTION_BIND)nl() + See also: + link(UNIX-RECVFROM)(ADDRESS_UNIX_RECVFROM), + link(UNIX-RECV)(ADDRESS_UNIX_RECV), + link(UNIX-CONNECT)(ADDRESS_UNIX_CONNECT), + link(UDP-SENDTO)(ADDRESS_UDP_SENDTO), + link(IP-SENDTO)(ADDRESS_IP_SENDTO) + +label(ADDRESS_UNIX_RECVFROM)dit(bf(tt(UNIX-RECVFROM:))) + Creates a unixdomain() datagram socket [link()(TYPE_FILENAME)]. + Receives one packet and may send one or more answer packets to that peer. + This mode is particularly useful with fork option where each arriving packet - from arbitrary peers - is handled by its own sub process. + This address works well with socat UNIX-SENDTO address peers.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET), + link(NAMED)(GROUP_NAMED),link(CHILD)(GROUP_CHILD), + link(UNIX)(GROUP_SOCK_UNIX) nl() + Useful options: + link(fork)(OPTION_FORK)nl() + See also: + link(UNIX-SENDTO)(ADDRESS_UNIX_SENDTO), + link(UNIX-RECV)(ADDRESS_UNIX_RECV), + link(UNIX-LISTEN)(ADDRESS_UNIX_LISTEN), + link(UDP-RECVFROM)(ADDRESS_UDP_RECVFROM), + link(IP-RECVFROM)(ADDRESS_IP_RECVFROM) + +label(ADDRESS_UNIX_RECV)dit(bf(tt(UNIX-RECV:))) + Creates a unixdomain() datagram socket [link()(TYPE_FILENAME)]. + Receives packets from multiple unspecified peers and merges the data. + No replies are possible. It can be, e.g., addressed by socat UNIX-SENDTO address peers. + It behaves similar to a syslog server. + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET), + link(NAMED)(GROUP_NAMED),link(UNIX)(GROUP_SOCK_UNIX) nl() + See also: + link(UNIX-SENDTO)(ADDRESS_UNIX_SENDTO), + link(UNIX-RECVFROM)(ADDRESS_UNIX_RECVFROM), + link(UNIX-LISTEN)(ADDRESS_UNIX_LISTEN), + link(UDP-RECV)(ADDRESS_UDP_RECV), + link(IP-RECV)(ADDRESS_IP_RECV) + +label(ADDRESS_UNIX_CLIENT)dit(bf(tt(UNIX-CLIENT:))) + Communicates with the specified peer socket, defined by + [link()(TYPE_FILENAME)] assuming it is a unixdomain() socket. + It first tries to connect and, if that fails, assumes it is a datagram + socket, thus supporting both types.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET), + link(NAMED)(GROUP_NAMED),link(UNIX)(GROUP_SOCK_UNIX) nl() + Useful options: + link(bind)(OPTION_BIND)nl() + See also: + link(UNIX-CONNECT)(ADDRESS_UNIX_CONNECT), + link(UNIX-SENDTO)(ADDRESS_UNIX_SENDTO), + link(GOPEN)(ADDRESS_GOPEN) + +dit(bf(tt(ABSTRACT-CONNECT:))) +dit(bf(tt(ABSTRACT-LISTEN:))) +dit(bf(tt(ABSTRACT-SENDTO:))) +dit(bf(tt(ABSTRACT-RECVFROM:))) +dit(bf(tt(ABSTRACT-RECV:))) +dit(bf(tt(ABSTRACT-CLIENT:))) + The ABSTRACT addresses are almost identical to the related UNIX addresses + except that they do not address file system based sockets but an alternate + unixdomain() address space. To archieve this the socket address strings are + prefixed with "\0" internally. This feature is available (only?) on Linux. + Option groups are the same as with the related UNIX addresses, except that + the ABSTRACT addresses are not member of the NAMED group. +enddit() + + +label(ADDRESS_OPTIONS) +manpagesection(ADDRESS OPTIONS) + +Address options can be applied to address specifications to influence the +process of opening the addresses and the +properties of the resulting data channels. + +For technical reasons not every option can be +applied to every address type; e.g., applying a socket option to a regular file +will fail. To catch most useless combinations as early as in the open phase, +the concept of em(option groups) was introduced. Each option belongs to one +or more option groups. Options can be used only with address types that support +at least one of their option groups (but see link(option -g)(option_g)). + +Address options have data types that their values must conform to. +Every address option consists of just a keyword or a keyword followed by +"=value", where value must conform to the options type. +COMMENT(Options that trigger a call with +trivial parameters are described with type BOOL which might be misleading.) +Some address options manipulate parameters of system calls; +e.g., option sync sets the code(O_SYNC) flag with the code(open()) call. +Other options cause a system or library call; e.g., with option `ttl=value' +the code(setsockopt(fd, SOL_IP, IP_TTL, value, sizeof(int))) call is applied. +Other +options set internal socat() variables that are used during data transfer; +e.g., `crnl' causes explicit character conversions. +A few options have more complex implementations; e.g., su-d +(substuser-delayed) inquires some user and group infos, stores them, and +applies them later after a possible code(chroot()) call. + +If multiple options are given to an address, their sequence in the address specification has (almost) no +effect on the sequence of their execution/application. Instead, socat() has +built in an em(option phase) model that tries to bring the options in a useful +order. Some options exist in different forms (e.g., +unlink, unlink-early, unlink-late) to control the time of their execution. + +If the same option is specified more than once within one address +specification, with equal or different values, the effect depends on the kind of option. Options +resulting in function calls like code(setsockopt()) cause multiple +invocations. With options that set parameters for a required call like +code(open()) +or set internal flags, the value of the last option occurrence is effective. + +The existence or semantics of many options are system dependent. Socat() +usually does NOT try to emulate missing libc or kernel features, it just +provides an +interface to the underlying system. So, if an operating system lacks a feature, +the related option is simply not available on this platform. + +The following paragraphs introduce just the more common address options. For +a more comprehensive reference and to find information about canonical option +names, alias names, option phases, and platforms see file file(xio.help). +nl() nl() + +startdit()enddit()nl() + + +label(GROUP_FD)em(bf(FD option group)) + +This option group contains options that are applied to a unix() +style file descriptor, no matter how it was generated. +Because all current socat() address types are file descriptor based, these +options may be applied to any address. nl() +Note: Some of these options are also member of another option group, that +provides an other, non-fd based mechanism. +For these options, it depends on the actual address type and its option groups +which mechanism is used. The second, non-fd based mechanism is prioritized. +startdit() +label(OPTION_CLOEXEC)dit(bf(tt(cloexec=))) + Sets the code(FD_CLOEXEC) flag with the code(fcntl()) system call to value + link()(TYPE_BOOL). If set, + the file descriptor is closed on code(exec()) family function calls. Socat() + internally handles + this flag for the fds it controls, so in most cases there will be no need to + apply this option. +label(OPTION_SETLK_WR)dit(bf(tt(setlk))) + Tries to set a discretionary write lock to the whole file using the code(fcntl(fd, + F_SETLK, ...)) system call. If the file is already locked, this call results + in an error. + On Linux, when the file permissions for group are "S" (g-x,g+s), and the + file system is locally mounted with the "mand" option, the lock is + mandatory, i.e. prevents other processes from opening the file. +label(OPTION_SETLKW_WR)dit(bf(tt(setlkw))) + Tries to set a discretionary waiting write lock to the whole file using the + code(fcntl(fd, F_SETLKW, ...)) system call. If the file is already locked, + this call blocks. + See option link(setlk)(OPTION_SETLK_WR) for information about making this + lock mandatory. +label(OPTION_SETLK_RD)dit(bf(tt(setlk-rd))) + Tries to set a discretionary read lock to the whole file using the code(fcntl(fd, + F_SETLK, ...)) system call. If the file is already write locked, this call + results in an error. + See option link(setlk)(OPTION_SETLK_WR) for information about making this + lock mandatory. +label(OPTION_SETLKW_RD)dit(bf(tt(setlkw-rd))) + Tries to set a discretionary waiting read lock to the whole file using the + code(fcntl(fd, F_SETLKW, ...)) system call. If the file is already write + locked, this call blocks. + See option link(setlk)(OPTION_SETLK_WR) for information about making this + lock mandatory. +label(OPTION_FLOCK_EX)dit(bf(tt(flock-ex))) + Tries to set a blocking exclusive advisory lock to the file using the + code(flock(fd, LOCK_EX)) system call. Socat() hangs in this call if the file + is locked by another process. +label(OPTION_FLOCK_EX_NB)dit(bf(tt(flock-ex-nb))) + Tries to set a nonblocking exclusive advisory lock to the file using the + code(flock(fd, LOCK_EX|LOCK_NB)) system call. If the file is already locked, + this option results in an error. +label(OPTION_FLOCK_SH)dit(bf(tt(flock-sh))) + Tries to set a blocking shared advisory lock to the file using the + code(flock(fd, LOCK_SH)) system call. Socat() hangs in this call if the file + is locked by another process. +label(OPTION_FLOCK_SH_NB)dit(bf(tt(flock-sh-nb))) + Tries to set a nonblocking shared advisory lock to the file using the + code(flock(fd, LOCK_SH|LOCK_NB)) system call. If the file is already locked, + this option results in an error. +label(OPTION_LOCK)dit(bf(tt(lock))) + Sets a blocking lock on the file. Uses the setlk or flock mechanism + depending on availability on the particular platform. If both are available, + the POSIX variant (setlkw) is used. +label(OPTION_USER)dit(bf(tt(user=))) + Sets the link()(TYPE_USER) (owner) of the stream. + If the address is member of the NAMED option group, + socat() uses the code(chown()) system call after opening the + file or binding to the unixdomain() socket (race condition!). + Without filesystem entry, socat() sets the user of the stream + using the code(fchown()) system call. + These calls might require root privilege. +label(OPTION_USER_LATE)dit(bf(tt(user-late=))) + Sets the owner of the fd to link()(TYPE_USER) with the code(fchown()) + system call after opening + or connecting the channel. + This is useful only on file system entries. +label(OPTION_GROUP)dit(bf(tt(group=))) + Sets the link()(TYPE_GROUP) of the stream. + If the address is member of the NAMED option group, + socat() uses the code(chown()) system call after opening the + file or binding to the unixdomain() socket (race condition!). + Without filesystem entry, socat() sets the group of the stream + with the code(fchown()) system call. + These calls might require group membership or root privilege. +label(OPTION_GROUP_LATE)dit(bf(tt(group-late=))) + Sets the group of the fd to link()(TYPE_GROUP) with the + code(fchown()) system call after opening + or connecting the channel. + This is useful only on file system entries. +label(OPTION_MODE)dit(bf(tt(mode=))) + Sets the [link(mode_t)(TYPE_MODE_T)] (permissions) of the stream. + If the address is member of the NAMED option group and + uses the code(open()) or code(creat()) call, the mode is applied with these. + If the address is member of the NAMED option group without using these + 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. +label(OPTION_PERM_LATE)dit(bf(tt(perm-late=))) + Sets the permissions of the fd to value + [link(mode_t)(TYPE_MODE_T)] using the code(fchmod()) system call after + opening or connecting the channel. + This is useful only on file system entries. +label(OPTION_APPEND)dit(bf(tt(append=))) + Always writes data to the actual end of file. + If the address is member of the OPEN option group, + 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=))) + 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. + If the address is member of the OPEN option group, + socat() uses the code(O_NONBLOCK) flag with the code(open()) system call. + Otherwise, socat() applies the code(fcntl(fd, F_SETFL, O_NONBLOCK)) call. +COMMENT(label(OPTION_NDELAY)dit(bf(tt(ndelay=))) + Tries to open or use file in nonblocking mode. Has no effect because socat() + works with code(select()).) +COMMENT(label(OPTION_ASYNC)dit(bf(tt(async=))) + Enables SIGIO for this fd. Has no effect, because socat() ignores SIGIO.) +label(OPTION_O_BINARY)dit(bf(tt(binary))) + Opens the file in binary mode to avoid implicit line terminator + conversions (Cygwin). +label(OPTION_O_TEXT)dit(bf(tt(text))) + Opens the file in text mode to force implicit line terminator conversions + (Cygwin). +label(OPTION_O_NOINHERIT)dit(bf(tt(noinherit))) + Does not keep this file open in a spawned process (Cygwin). +label(OPTION_COOL_WRITE)dit(bf(tt(cool-write))) + Takes it easy when write fails with EPIPE or ECONNRESET and logs the message + with em(notice) level instead of em(error). + This prevents the log file from being filled with useless error messages + when socat is used as a high volume server or proxy where clients often + abort the connection.nl() + This option is experimental. +label(OPTION_END_CLOSE)dit(bf(tt(end-close))) + Changes the (address dependent) method of ending a connection to just close + the file descriptors. This is useful when the connection is to be reused by + or shared with other processes (link(example)(EXAMPLE_END_CLOSE)).nl() + Normally, socket connections will be ended with tt(shutdown(2)) which + terminates the socket even if it is shared by multiple processes. + tt(close(2)) "unlinks" the socket from the process but keeps it active as + long as there are still links from other processes.nl() + Similarly, when an address of type EXEC or SYSTEM is ended, socat usually + will explicitely kill the sub process. With this option, it will just close + the file descriptors. +enddit() + +startdit()enddit()nl() + + +label(GROUP_NAMED)em(bf(NAMED option group)) + +These options work on file system entries.nl() +See also options link(user)(OPTION_USER), link(group)(OPTION_GROUP), and +link(mode)(OPTION_MODE). + +startdit() +label(OPTION_USER_EARLY)dit(bf(tt(user-early=))) + Changes the link()(TYPE_USER) (owner) of the file system entry before + accessing it, using the + code(chown()) system call. This call might require root privilege. +label(OPTION_GROUP_EARLY)dit(bf(tt(group-early=))) + Changes the link()(TYPE_GROUP) of the file system entry before + accessing it, using the + code(chown()) system call. This call might require group membership or root + privilege. +label(OPTION_PERM_EARLY)dit(bf(tt(perm-early=))) + Changes the [link(mode_t)(TYPE_MODE_T)] of the file system entry + before accessing it, using the + code(chmod()) system call. This call might require ownership or root + privilege. +label(OPTION_UMASK)dit(bf(tt(umask=))) + Sets the umask of the process to [link(mode_t)(TYPE_MODE_T)] before + accessing the file system entry (useful + with unixdomain() sockets!). This call might affect all further operations + of the socat() process! +label(OPTION_UNLINK_EARLY)dit(bf(tt(unlink-early))) + Unlinks (removes) the file before opening it and even before applying + user-early etc. +label(OPTION_UNLINK)dit(bf(tt(unlink))) + Unlinks (removes) the file before accessing it, but after user-early etc. +label(OPTION_UNLINK_LATE)dit(bf(tt(unlink-late))) + Unlinks (removes) the file after opening it to make it inaccessible for + other processes after a short race condition. +label(OPTION_UNLINK_CLOSE)dit(bf(tt(unlink-close))) + Removes the addresses file system entry when closing the address. + For link(named pipes)(ADDRESS_NAMED_PIPE), + link(listening unix domain sockets)(ADDRESS_UNIX_LISTEN), + and the link(symbolic links)(OPTION_SYMBOLIC_LINK) of link(pty addresses)(ADDRESS_PTY), + the default is 1; for link(created files)(ADDRESS_CREAT), + link(opened files)(ADDRESS_OPEN), + link(generic opened files)(ADDRESS_GOPEN), and + link(client unix domain sockets)(ADDRESS_UNIX_CONNECT) the default is 0. +enddit() + +startdit()enddit()nl() + + +label(GROUP_OPEN)em(bf(OPEN option group)) + +The OPEN group options allow to set flags with the code(open()) system call. +E.g., option `creat' sets the code(O_CREAT) flag.nl() +See also options link(append)(OPTION_APPEND) and +link(nonblock)(OPTION_NONBLOCK). +startdit() +label(OPTION_CREAT)dit(bf(tt(creat=))) + Creates the file if it does not exist (link(example)(EXAMPLE_OPTION_CREAT)). +label(OPTION_DSYNC)dit(bf(tt(dsync=))) + Blocks code(write()) calls until metainfo is physically written to media. +label(OPTION_EXCL)dit(bf(tt(excl=))) + With option creat, if file exists this is an error. +label(OPTION_LARGEFILE)dit(bf(tt(largefile=))) + On 32 bit systems, allows a file larger than 2^31 bytes. +label(OPTION_O_NOATIME)dit(bf(tt(noatime))) + Sets the O_NOATIME options, so reads do not change the access timestamp. +label(OPTION_NOCTTY)dit(bf(tt(noctty=))) + Does not make this file the controlling terminal. +label(OPTION_NOFOLLOW)dit(bf(tt(nofollow=))) + Does not follow symbolic links. +label(OPTION_NSHARE)dit(bf(tt(nshare=))) + Does not allow to share this file with other processes. +label(OPTION_RSHARE)dit(bf(tt(rshare=))) + Does not allow other processes to open this file for writing. +label(OPTION_RSYNC)dit(bf(tt(rsync=))) + Blocks code(write()) until metainfo is physically written to media. +label(OPTION_SYNC)dit(bf(tt(sync=))) + Blocks code(write()) until data is physically written to media. +COMMENT(label(OPTION_DEFER)dit(bf(tt(defer=))) + Temporarily stores write data in paging space.) +COMMENT(label(OPTION_DELAY)dit(bf(tt(delay=))) + Blocks code(open()) until share conditions are fulfilled.) +COMMENT(label(OPTION_DIRECT)dit(bf(tt(direct=)))) +COMMENT(label(OPTION_DIRECTORY)dit(bf(tt(directory=))) + Fails if file is not a directory. Not useful with socat().) +label(OPTION_RDONLY)dit(bf(tt(rdonly=))) + Opens the file for reading only. +COMMENT(label(OPTION_RDWR)dit(bf(tt(rdwr=))) + Opens the file for reading and writing.) +label(OPTION_WRONLY)dit(bf(tt(wronly=))) + Opens the file for writing only. +label(OPTION_TRUNC)dit(bf(tt(trunc))) + Truncates the file to size 0 during opening it. +enddit() + + +startdit()enddit()nl() + + +label(GROUP_REG)em(bf(REG and BLK option group)) + +These options are usually applied to a unix() file descriptor, but their +semantics make sense only on a file supporting random access. +startdit() +label(OPTION_SEEK)dit(bf(tt(seek=))) + Applies the code(lseek(fd, , SEEK_SET)) (or code(lseek64)) system + call, thus positioning the file pointer absolutely to + [link(off_t)(TYPE_OFF) or link(off64_t)(TYPE_OFF64)]. +label(OPTION_SEEK_CUR)dit(bf(tt(seek-cur=))) + Applies the code(lseek(fd, , SEEK_CUR)) (or code(lseek64)) system + call, thus positioning the file pointer [link(off_t)(TYPE_OFF) or + link(off64_t)(TYPE_OFF64)] bytes relatively to its current position (which + is usually 0). +label(OPTION_SEEK_END)dit(bf(tt(seek-end=))) + Applies the code(lseek(fd, , SEEK_END)) (or code(lseek64)) system + call, thus positioning the file pointer [link(off_t)(TYPE_OFF) or + link(off64_t)(TYPE_OFF64)] bytes relatively to the files current end. +label(OPTION_FTRUNCATE)dit(bf(tt(ftruncate=))) + Applies the code(ftruncate(fd, )) + (or code(ftruncate64) if available) system call, thus + truncating the file at the position [link(off_t)(TYPE_OFF) or + link(off64_t)(TYPE_OFF64)]. + +label(OPTION_EXT2_SECRM_FL)dit(bf(tt(secrm=))) +label(OPTION_EXT2_UNRM)dit(bf(tt(unrm=))) +label(OPTION_EXT2_COMPR)dit(bf(tt(compr=))) +label(OPTION_EXT2_SYNC)dit(bf(tt(ext2-sync=))) +label(OPTION_EXT2_IMMUTABLE)dit(bf(tt(immutable=))) +label(OPTION_EXT2_APPEND)dit(bf(tt(ext2-append=))) +label(OPTION_EXT2_NODUMP)dit(bf(tt(nodump=))) +label(OPTION_EXT2_NOATIME)dit(bf(tt(ext2-noatime=))) +label(OPTION_EXT2_JOURNAL_DATA)dit(bf(tt(journal-data=))) +label(OPTION_EXT2_NOTAIL)dit(bf(tt(notail=))) +label(OPTION_EXT2_DIRSYNC)dit(bf(tt(dirsync=))) + These options change non standard file attributes on operating systems and + file systems that support these features, like Linux with ext2fs, + ext3fs, or reiserfs. See man 1 chattr for information on these options. + Please note that there might be a race condition between creating the file + and applying these options. +enddit() + +startdit()enddit()nl() + + +label(GROUP_PROCESS)em(bf(PROCESS option group)) + +Options of this group change the process properties instead of just affecting +one data channel. +For EXEC and SYSTEM addresses and for LISTEN and CONNECT type addresses with +option FORK, +these options apply to the child processes instead of the main socat process. +startdit() +label(OPTION_CHROOT)dit(bf(tt(chroot=))) + Performs a code(chroot()) operation to link()(TYPE_DIRECTORY) + after processing the address (link(example)(EXAMPLE_OPTION_CHROOT)). This call might require root privilege. +label(OPTION_CHROOT_EARLY)dit(bf(tt(chroot-early=))) + Performs a code(chroot()) operation to link()(TYPE_DIRECTORY) + before opening the address. This call might require root privilege. +label(OPTION_SETGID)dit(bf(tt(setgid=))) + Changes the primary link()(TYPE_GROUP) of the process after + processing the address. This call might require root privilege. +label(OPTION_SETGID_EARLY)dit(bf(tt(setgid-early=))) + Changes the primary link()(TYPE_GROUP) of the process before opening + the address. This call might require root privilege. +label(OPTION_SETUID)dit(bf(tt(setuid=))) + Changes the link()(TYPE_USER) (owner) of the process after processing + the address. This call might require root privilege. +label(OPTION_SETUID_EARLY)dit(bf(tt(setuid-early=))) + Changes the link()(TYPE_USER) (owner) of the process before opening + the address. This call might require root privilege. +label(OPTION_SUBSTUSER)dit(bf(tt(su=))) + Changes the link()(TYPE_USER) (owner) and groups of the process after + processing the address (link(example)(EXAMPLE_OPTION_SUBSTUSER)). This call might require root privilege. +label(OPTION_SUBSTUSER_DELAYED)dit(bf(tt(su-d=))) + Short name for bf(tt(substuser-delayed)). + Changes the link()(TYPE_USER) + (owner) and groups of the process after processing the address (link(example)(EXAMPLE_OPTION_SUBSTUSER_DELAYED)). + The user and his groups are retrieved em(before) a possible + code(chroot()). This call might require root privilege. +label(OPTION_SETPGID)dit(bf(tt(setpgid=))) + Makes the process a member of the specified process group + link()(TYPE_PID_T). If no value + is given, or if the value is 0 or 1, the process becomes leader of a new + process group. +label(OPTION_SETSID)dit(bf(tt(setsid))) + Makes the process the leader of a new session (link(example)(EXAMPLE_OPTION_SETSID)). +enddit() + +startdit()enddit()nl() + + +label(GROUP_READLINE)em(bf(READLINE option group)) + +These options apply to the readline address type. +startdit() +label(OPTION_HISTORY)dit(bf(tt(history=))) + Reads and writes history from/to link()(TYPE_FILENAME) (link(example)(EXAMPLE_OPTION_HISTORY)). +label(OPTION_NOPROMPT)dit(bf(tt(noprompt))) + Since version 1.4.0, socat per default tries to determine a prompt - + that is then passed to the readline call - by remembering the last + incomplete line of the output. With this option, socat does not pass a + prompt to readline, so it begins line editing in the first column + of the terminal. +label(OPTION_NOECHO)dit(bf(tt(noecho=))) + 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 + typed. The pattern is a regular expression, e.g. + "^[Pp]assword:.*$" or "([Uu]ser:|[Pp]assword:)". See regex(7) for details. + (link(example)(EXAMPLE_OPTION_NOECHO)) +label(OPTION_PROMPT)dit(bf(tt(prompt=))) + Passes the string as prompt to the readline function. readline prints this + prompt when stepping through the history. If this string matches a constant + prompt issued by an interactive program on the other socat address, + consistent look and feel can be archieved. +enddit() + +startdit()enddit()nl() + + +label(GROUP_APPLICATION)em(bf(APPLICATION option group)) + +This group contains options that work at data level. +Note that these options only apply to the "raw" data transferred by socat, +but not to protocol data used by addresses like +link(PROXY)(ADDRESS_PROXY_CONNECT). +startdit() +label(OPTION_CR)dit(bf(tt(cr))) + Converts the default line termination character NL ('\n', 0x0a) to/from CR + ('\r', 0x0d) when writing/reading on this channel. +label(OPTION_CRNL)dit(bf(tt(crnl))) + Converts the default line termination character NL ('\n', 0x0a) to/from CRNL + ("\r\n", 0x0d0a) when writing/reading on this channel (link(example)(EXAMPLE_OPTION_CRNL)). + Note: socat simply strips all CR characters. +label(OPTION_IGNOREEOF)dit(bf(tt(ignoreeof))) + When EOF occurs on this channel, socat() ignores it and tries to read more + data (like "tail -f") (link(example)(EXAMPLE_OPTION_IGNOREEOF)). +label(OPTION_READBYTES)dit(bf(tt(readbytes=))) + socat() reads only so many bytes from this address (the address provides + only so many bytes for transfer and pretends to be at EOF afterwards). + Must be greater than 0. +label(OPTION_LOCKFILE)dit(bf(tt(lockfile=))) + If lockfile exists, exits with error. If lockfile does not exist, creates it + and continues, unlinks lockfile on exit. +label(OPTION_WAITLOCK)dit(bf(tt(waitlock=))) + If lockfile exists, waits until it disappears. When lockfile does not exist, + creates it and continues, unlinks lockfile on exit. +enddit() + +startdit()enddit()nl() + + +label(GROUP_SOCKET)em(bf(SOCKET option group)) + +These options are intended for all kinds of sockets, e.g. IP or unixdomain(). Most are applied with a code(setsockopt()) call. +startdit() +label(OPTION_BIND)dit(bf(tt(bind=))) + Binds the socket to the given socket address using the code(bind()) system + call. The form of is socket domain dependent: + IP4 and IP6 allow the form [hostname|hostaddress][:(service|port)] (link(example)(EXAMPLE_OPTION_BIND_TCP4)), + unixdomain() sockets require link()(TYPE_FILENAME). +label(OPTION_CONNECT_TIMEOUT)dit(bf(tt(connect-timeout=))) + Abort the connection attempt after [link(timeval)(TYPE_TIMEVAL)] + with error status. +label(OPTION_INTERFACE)dit(bf(tt(interface=))) + Binds the socket to the given link()(TYPE_INTERFACE). + This option might require root privilege. +label(OPTION_SO_BROADCAST)dit(bf(tt(broadcast))) + For datagram sockets, allows sending to broadcast addresses and receiving + packets addressed to broadcast addresses. +label(OPTION_BSDCOMPAT)dit(bf(tt(bsdcompat))) + Emulates some (old?) bugs of the BSD socket implementation. +label(OPTION_DEBUG)dit(bf(tt(debug))) + Enables socket debugging. +label(OPTION_DONTROUTE)dit(bf(tt(dontroute))) + Only communicates with directly connected peers, does not use routers. +label(OPTION_KEEPALIVE)dit(bf(tt(keepalive))) + Enables sending keepalives on the socket. +label(OPTION_LINGER)dit(bf(tt(linger=))) + Blocks code(shutdown()) or code(close()) until data transfers have finished + or the given timeout [link(int)(TYPE_INT)] expired. +COMMENT(label(OPTION_NOREUSEADDR)dit(bf(tt(noreuseaddr))) + Set the code(SO_NOREUSEADDR) socket option.) +label(OPTION_OOBINLINE)dit(bf(tt(oobinline))) + Places out-of-band data in the input data stream. +label(OPTION_PRIORITY)dit(bf(tt(priority=))) + Sets the protocol defined [link()(TYPE_INT)] for outgoing + packets. +label(OPTION_RCVBUF)dit(bf(tt(rcvbuf=))) + Sets the size of the receive buffer after the code(socket()) call to + [link(int)(TYPE_INT)]. With TCP + sockets, this value corresponds to the socket's maximal window size. +label(OPTION_RCVBUF_LATE)dit(bf(tt(rcvbuf-late=))) + Sets the size of the receive buffer when the socket is already + connected to [link(int)(TYPE_INT)]. + With TCP sockets, this value corresponds to the socket's + maximal window size. +label(OPTION_RCVLOWAT)dit(bf(tt(rcvlowat=))) + Specifies the minimum number of received bytes [link(int)(TYPE_INT)] until + the socket layer will pass the buffered data to socat(). +label(OPTION_RCVTIMEO)dit(bf(tt(rcvtimeo=))) + Sets the receive timeout [link(timeval)(TYPE_TIMEVAL)]. +label(OPTION_REUSEADDR)dit(bf(tt(reuseaddr))) + Allows other sockets to bind to an address even if parts of it (e.g. the + local port) are already in use by socat() (link(example)(EXAMPLE_OPTION_REUSEADDR)). +label(OPTION_SNDBUF)dit(bf(tt(sndbuf=))) + Sets the size of the send buffer after the code(socket()) call to + [link(int)(TYPE_INT)]. +label(OPTION_SNDBUF_LATE)dit(bf(tt(sndbuf-late=))) + Sets the size of the send buffer when the socket is connected to + [link(int)(TYPE_INT)]. +label(OPTION_SNDLOWAT)dit(bf(tt(sndlowat=))) + Specifies the minimum number of bytes in the send buffer until the socket + layer will send the data to [link(int)(TYPE_INT)]. +label(OPTION_SNDTIMEO)dit(bf(tt(sndtimeo=))) + Sets the send timeout to seconds [link(timeval)(TYPE_TIMEVAL)]. +label(OPTION_TYPE)dit(bf(tt(type=))) + Sets the type of the socket, usually as argument to the code(socket()) or + code(socketpair()) call, to [link(int)(TYPE_INT)]. + Under Linux, 1 means stream oriented socket, 2 means datagram socket, and 3 + means raw socket. +COMMENT(label(OPTION_USELOOPBACK)dit(bf(tt(useloopback))) + Sets the code(SO_USELOOPBACK) socket option.) +COMMENT(label(OPTION_ACCEPTCONN)dit(bf(tt(acceptconn))) + Tries to set the code(SO_ACCEPTCONN) socket option.) +COMMENT(label(OPTION_ATTACHFILTER)dit(bf(tt(attachfilter))) + Tries to set the code(SO_ATTACH_FILTER) socket option.) +COMMENT(label(OPTION_AUDIT)dit(bf(tt(audit))) + Sets the code(SO_AUDIT) socket option.) +COMMENT(label(OPTION_CHSUMRECV)dit(bf(tt(cksumrecv))) + Sets the code(SO_CKSUMRECV) socket option.) +COMMENT(label(OPTION_DETACHFILTER)dit(bf(tt(detachfilter))) + Tries to set the code(SO_DETACH_FILTER) socket option.) +COMMENT(label(OPTION_DGRAMERRIND)dit(bf(tt(dgramerrind))) + Sets the code(SO_DGRAM_ERRIND) socket option.) +COMMENT(label(OPTION_DONTLINGER)dit(bf(tt(dontlinger))) + Sets the code(SO_DONTLINGER) socket option.) +COMMENT(label(OPTION_ERROR)dit(bf(tt(error))) + Tries to set this read only socket option.) +COMMENT(label(OPTION_FIOSETOWN)dit(bf(tt(fiosetown=))) + Sets the receiver of SIGIO.) +COMMENT(label(OPTION_KERNACCEPT)dit(bf(tt(kernaccept))) + Sets the code(SO_KERNACCEPT) socket option.) +COMMENT(label(OPTION_NOCHECK)dit(bf(tt(nocheck))) + Sets the code(SO_NO_CHECK) socket option. Undocumented...) +COMMENT(label(OPTION_PASSCRED)dit(bf(tt(passcred))) + Set the code(SO_PASSCRED) socket option.) +COMMENT(label(OPTION_PEERCRED)dit(bf(tt(peercred))) + This is a read-only socket option.) +COMMENT(label(OPTION_PROTOTYPE)dit(bf(tt(prototype))) + Tries to set the code(SO_PROTOTYPE) socket option.) +COMMENT(label(OPTION_REUSEPORT)dit(bf(tt(reuseport))) + Set the code(SO_REUSEPORT) socket option.) +COMMENT(label(OPTION_SECUTIYAUTHENTICATION)dit(bf(tt(securityauthentication))) + Set the code(SO_SECURITY_AUTHENTICATION) socket option.) +COMMENT(label(OPTION_SECURITYENCRYPTIONNETWORK)dit(bf(tt(securityencryptionnetwork))) + Set the code(SO_SECURITY_ENCRYPTION_NETWORK) socket option.) +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=))) + Set the SIOCSPGRP with code(ioclt()) to enable SIGIO.) +COMMENT(label(OPTION_USEIFBUFS)dit(bf(tt(useifbufs))) + Set the code(SO_USE_IFBUFS) socket option.) +label(OPTION_PROTOCOL_FAMILY)dit(bf(tt(pf=))) + Forces the use of the specified IP version. can be + something like "ip4" or "ip6". +enddit() + +startdit()enddit()nl() + + +label(GROUP_SOCK_UNIX)em(bf(UNIX option group)) + +These options apply to UNIX domain based addresses. +startdit() +label(OPTION_UNIX_TIGHTSOCKLEN)dit(bf(tt(unix-tightsocklen=[0|1]))) + On socket operations, pass a socket address length that does not include the + whole code(struct sockaddr_un) record but (besides other components) only + the relevant part of the filename or abstract string. Default is 1. +enddit() + +label(GROUP_IP4) +label(GROUP_IP)em(bf(IP4 and IP6 option groups)) + +These options can be used with IPv4 and IPv6 based sockets. +startdit() +label(OPTION_TOS)dit(bf(tt(tos=))) + Sets the TOS (type of service) field of outgoing packets to + [link(byte)(TYPE_BYTE)] (see RFC 791). +label(OPTION_TTL)dit(bf(tt(ttl=))) + Sets the TTL (time to live) field of outgoing packets to + [link(byte)(TYPE_BYTE)]. +label(OPTION_IPOPTIONS)dit(bf(tt(ipoptions=))) + Sets IP options like source routing. Must be given in binary form, + recommended format is a leading "x" followed by an even number of hex + digits. This option may be used multiple times, data are appended. + E.g., to connect to host 10.0.0.1 via some gateway using a loose source + route, use the gateway as address parameter and set a loose source route + using the option code(ipoptions=x8307040a000001).nl() + IP options are defined in RFC 791. COMMENT(, RFC 2113)nl() +COMMENT( x00 end of option list + x01 no operation (nop) + x0211 security + x03 loose source route + x09 strict source route + x07 record route + x0804 stream ID + x44 internet timestamp) +label(OPTION_MTUDISCOVER)dit(bf(tt(mtudiscover=<0|1|2>))) + Takes 0, 1, 2 to never, want, or always use path MTU discover on this + socket. +COMMENT(label(OPTION_HRDINCL)dit(bf(tt(hdrincl))) + Tell the raw socket that the application data includes the IP header.) +COMMENT(label(OPTION_IP_MULTICAST_LOOP)dit(bf(tt(multicastloop))) + Allow looping back outgoing multicast to the local interface.) +COMMENT(label(OPTION_IP_MULTICAST_TTL)dit(bf(tt(multicastttl))) + Set the TTL for outgoing multicast packets.) +COMMENT(label(OPTION_PKTINFO)dit(bf(tt(pktinfo))) + Set the IP_PKTINFO socket option.) +COMMENT(label(OPTION_PKTOPTS)dit(bf(tt(pktopts))) + Set the IP_PKTOPTIONS socket option.) +COMMENT(label(OPTION_RECVERR)dit(bf(tt(recverr))) + Set the IP_RECVERR socket option.) +COMMENT(label(OPTION_RECVOPTS)dit(bf(tt(recvopts))) + Set the IP_RECVOPTS socket option.) +COMMENT(label(OPTION_RECVTOS)dit(bf(tt(recvtos))) + Set the IP_RECVTOS socket option.) +COMMENT(label(OPTION_RECVTTL)dit(bf(tt(recvttl))) + Set the IP_RECVTTL socket option.) +COMMENT(label(OPTION_RETOPTS)dit(bf(tt(retopts))) + Set the IP_RETOPTS socket option.) +COMMENT(label(OPTION_ROUTERALERT)dit(bf(tt(routeralert))) + Set the IP_ROUTER_ALERT socket option.) +label(OPTION_IP_ADD_MEMBERSHIP) +dit(bf(tt(ip-add-membership=))) +dit(bf(tt(ip-add-membership=))) +dit(bf(tt(ip-add-membership=))) +dit(bf(tt(ip-add-membership=))) +dit(bf(tt(ip-add-membership=))) + Makes the socket member of the specified multicast group. This is currently + only implemented for IPv4. The option takes the IP address of the multicast + group and info about the desired network interface. The most common syntax + is the first one, while the others are only available on systems that + provide tt(struct mreqn) (Linux).nl() + The indices of active network interfaces can be shown using the utility + procan(). +label(OPTION_IP_MULTICAST_IF) +dif(bf(tt(ip-multicast-if=))) + Specifies hostname or address of the network interface to be used for + multicast traffic. +label(OPTION_IP_MULTICAST_LOOP) +dif(bf(tt(ip-multicast-loop=))) + Specifies if outgoing multicast traffic should loop back to the interface. +label(OPTION_IP_MULTICAST_TTL) +dif(bf(tt(ip-multicast-ttl=))) + Sets the TTL used for outgoing multicast traffic. Default is 1. +label(OPTION_RES_DEBUG)dit(bf(tt(res-debug))) +label(OPTION_RES_AAONLY)dit(bf(tt(res-aaonly))) +label(OPTION_RES_USEVC)dit(bf(tt(res-usevc))) +label(OPTION_RES_PRIMARY)dit(bf(tt(res-primary))) +label(OPTION_RES_IGNTC)dit(bf(tt(res-igntc))) +label(OPTION_RES_RECURSE)dit(bf(tt(res-recurse))) +label(OPTION_RES_DEFNAMES)dit(bf(tt(res-defnames))) +label(OPTION_RES_STAYOPEN)dit(bf(tt(res-stayopen))) +label(OPTION_RES_DNSRCH)dit(bf(tt(res-dnsrch))) + These options set the corresponding resolver (name resolution) option flags. + Append "=0" to clear a default option. See man resolver(5) for more + information on these options. Note: these options are valid only for the + address they are applied to. + +enddit() + +startdit()enddit()nl() + + +label(GROUP_IP6)em(bf(IP6 option group)) + +These options can only be used on IPv6 based sockets. See link(IP +options)(GROUP_IP) for options that can be applied to both IPv4 and IPv6 +sockets. +startdit() +label(OPTION_IPV6_V6ONLY)dit(bf(tt(ipv6only=))) + Sets the IPV6_V6ONLY socket option. If 0, the TCP stack will also accept + connections using IPv4 protocol on the same port. The default is system + dependent. +enddit() + +startdit()enddit()nl() + + +label(GROUP_TCP)em(bf(TCP option group)) + +These options may be applied to TCP sockets. They work by invoking code(setsockopt()) with the appropriate parameters. +startdit() +label(OPTION_CORK)dit(bf(tt(cork))) + Doesn't send packets smaller than MSS (maximal segment size). +label(OPTION_DEFER-ACCEPT)dit(bf(tt(defer-accept))) + While listening, accepts connections only when data from the peer arrived. +label(OPTION_KEEPCNT)dit(bf(tt(keepcnt=))) + Sets the number of keepalives before shutting down the socket to + [link(int)(TYPE_INT)]. +label(OPTION_KEEPIDLE)dit(bf(tt(keepidle=))) + Sets the idle time before sending the first keepalive to + [link(int)(TYPE_INT)]. +label(OPTION_KEEPINTVL)dit(bf(tt(keepintvl=))) + Sets the intervall between two keepalives to + [link(int)(TYPE_INT)]. +label(OPTION_LINGER2)dit(bf(tt(linger2=))) + Sets the time to keep the socket in FIN-WAIT-2 state to + [link(int)(TYPE_INT)]. +label(OPTION_MSS)dit(bf(tt(mss=))) + Sets the MSS (maximum segment size) after the code(socket()) call to + [link(int)(TYPE_INT)]. This + value is then proposed to the peer with the SYN or SYN/ACK packet + (link(example)(EXAMPLE_OPTION_MSS)). +label(OPTION_MSS_LATE)dit(bf(tt(mss-late=))) + Sets the MSS of the socket after connection has been established to + [link(int)(TYPE_INT)]. +label(OPTION_NODELAY)dit(bf(tt(nodelay))) + Turns off the Nagle algorithm for measuring the RTT (round trip time). +label(OPTION_RFC1323)dit(bf(tt(rfc1323))) + Enables RFC1323 TCP options: TCP window scale, round-trip time measurement + (RTTM), and protect against wrapped sequence numbers (PAWS) (AIX). +label(OPTION_STDURG)dit(bf(tt(stdurg))) + Enables RFC1122 compliant urgent pointer handling (AIX). +label(OPTION_SYNCNT)dit(bf(tt(syncnt=))) + Sets the maximal number of SYN retransmits during connect to + [link(int)(TYPE_INT)]. +COMMENT(label(OPTION_INFO)dit(bf(tt(info))) + Tries to set the read-only TCP_INFO socket option.) +COMMENT(label(OPTION_WINDOW_CLAMP)dit(bf(tt(window-clamp))) + Sets the TCP_WINDOW_CLAMP socket option.) +label(OPTION_TCP_MD5SIG)dit(bf(tt(md5sig))) + Enables generation of MD5 digests on the packets (FreeBSD). +label(OPTION_TCP_NOOPT)dit(bf(tt(noopt))) + Disables use of TCP options (FreeBSD, MacOSX). +label(OPTION_TCP_NOPUSH)dit(bf(tt(nopush))) + sets the TCP_NOPUSH socket option (FreeBSD, MacOSX). +label(OPTION_TCP_SACK_DISABLE)dit(bf(tt(sack-disable))) + Disables use the selective acknowledge feature (OpenBSD). +label(OPTION_TCP_SIGNATURE_ENABLE)dit(bf(tt(signature-enable))) + Enables generation of MD5 digests on the packets (OpenBSD). +label(OPTION_TCP_ABORT_THRESHOLD)dit(bf(tt(abort-threshold=))) + Sets the time to wait for an answer of the peer on an established connection + (HP-UX). +label(OPTION_TCP_CONN_ABORT_THRESHOLD)dit(bf(tt(conn-abort-threshold=))) + Sets the time to wait for an answer of the server during the initial connect + (HP-UX). +label(OPTION_TCP_KEEPINIT)dit(bf(tt(keepinit))) + Sets the time to wait for an answer of the server during connect() before + giving up. Value in half seconds, default is 150 (75s) (Tru64). +label(OPTION_TCP_PAWS)dit(bf(tt(paws))) + Enables the "protect against wrapped sequence numbers" feature (Tru64). +label(OPTION_TCP_SACKENA)dit(bf(tt(sackena))) + Enables selective acknowledge (Tru64). +label(OPTION_TCP_TSOPTENA)dit(bf(tt(tsoptena))) + Enables the time stamp option that allows RTT recalculation on existing + connections (Tru64). +enddit() + +startdit()enddit()nl() + + +em(bf(UDP and TCP option groups)) + +Here we find options that are related to the network port mechanism and that +thus can be used with UDP and TCP, client and server addresses. +startdit() +label(OPTION_SOURCEPORT)dit(bf(tt(sourceport=))) + For outgoing (client) TCP and UDP connections, it sets the source + link()(TYPE_PORT) using an extra code(bind()) call. + With TCP or UDP listen addresses, socat immediately shuts down the + connection if the client does not use this sourceport (link(example)(EXAMPLE_OPTION_SOURCEPORT)). +label(OPTION_LOWPORT)dit(bf(tt(lowport))) + Outgoing (client) TCP and UDP connections with this option use + an unused random source port between 640 and 1023 incl. On UNIX class operating + systems, this requires root privilege, and thus indicates that the + client process is authorized by local root. + TCP and UDP listen addresses with this option immediately shut down the + connection if the client does not use a sourceport <= 1023. + This mechanism can provide limited authorization under some circumstances. +enddit() + +startdit()enddit()nl() + + +label(GROUP_SOCKS)em(bf(SOCKS option group)) + +When using SOCKS type addresses, some socks specific options can be set. +startdit() +label(OPTION_SOCKSPORT)dit(bf(tt(socksport=))) + Overrides the default "socks" service or port 1080 for the socks server + port with link()(TYPE_TCP_SERVICE). +label(OPTION_SOCKSUSER)dit(bf(tt(socksuser=))) + Sends the [link(string)(TYPE_STRING)] in the username field to the + socks server. Default is the actual user name ($LOGNAME or $USER) (link(example)(EXAMPLE_OPTION_SOCKSUSER)). +enddit() + +startdit()enddit()nl() + + +label(GROUP_HTTP)em(bf(HTTP option group)) + +Options that can be provided with HTTP type addresses. The only HTTP address +currently implemented is link(proxy-connect)(ADDRESS_PROXY_CONNECT). + +startdit() +label(OPTION_PROXYPORT)dit(bf(tt(proxyport=))) + Overrides the default HTTP proxy port 8080 with + link()(TYPE_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 + to ignore CR in the answer. Nevertheless, socat sends CR+NL to the proxy. +label(OPTION_PROXY_AUTHORIZATION)dit(bf(tt(proxyauth=:))) + Provide "basic" authentication to the proxy server. The argument to the + option is used with a "Proxy-Authorization: Base" header in base64 encoded + form.nl() + Note: username and password are visible for every user on the local machine + in the process list; username and password are transferred to the proxy + server unencrypted (base64 encoded) and might be sniffed. +label(OPTION_PROXY_RESOLVE)dit(bf(tt(resolve))) + Per default, socat sends to the proxy a CONNECT request containing the + target hostname. With this option, socat resolves the hostname locally and + sends the IP address. Please note that, according to RFC 2396, only name + resolution to IPv4 addresses is implemented. +enddit() + +startdit()enddit()nl() + + +label(GROUP_RANGE)em(bf(RANGE option group)) + +These options check if a connecting client should be granted access. They can +be applied to listening and receiving network sockets. tcp-wrappers options +fall into this group. +startdit() +label(OPTION_RANGE)dit(bf(tt(range=))) + After accepting a connection, tests if the peer is within em(range). For + IPv4 addresses, address-range takes the form address/bits, e.g. + 10.0.0.0/8, or address:mask, e.g. 10.0.0.0:255.0.0.0 (link(example)(EXAMPLE_OPTION_RANGE)); for IPv6, it is [ip6-address/bits], e.g. [::1/128]. + If the client address does not match, socat() issues a warning and keeps + listening/receiving. +label(OPTION_TCPWRAPPERS)dit(bf(tt(tcpwrap[=]))) + Uses Wietse Venema's libwrap (tcpd) library to determine + if the client is allowed to connect. The configuration files are + /etc/hosts.allow and /etc/hosts.deny per default, see "man 5 hosts_access" + for more information. The optional (type link(string)(TYPE_STRING)) + is passed to the wrapper functions as daemon process name (link(example)(EXAMPLE_OPTION_TCPWRAPPERS)). + If omitted, the basename of socats invocation (argv[0]) is passed. + If both tcpwrap and range options are applied to an address, both + conditions must be fulfilled to allow the connection. +label(OPTION_TCPWRAP_HOSTS_ALLOW_TABLE)dit(bf(tt(allow-table=))) + Takes the specified file instead of /etc/hosts.allow. +label(OPTION_TCPWRAP_HOSTS_DENY_TABLE)dit(bf(tt(deny-table=))) + Takes the specified file instead of /etc/hosts.deny. +label(OPTION_TCPWRAP_ETC)dit(bf(tt(tcpwrap-etc=))) + Looks for hosts.allow and hosts.deny in the specified directory. Is + overridden by options link(hosts-allow)(OPTION_TCPWRAP_HOSTS_ALLOW_TABLE) + and link(hosts-deny)(OPTION_TCPWRAP_HOSTS_DENY_TABLE). +enddit() + +startdit()enddit()nl() + + +label(GROUP_LISTEN)em(bf(LISTEN option group)) + +Options specific to listening sockets. +startdit() +label(OPTION_BACKLOG)dit(bf(tt(backlog=))) + Sets the backlog value passed with the code(listen()) system call to + [link(int)(TYPE_INT)]. Default is 5. +enddit() +startdit()enddit()nl() + + +label(GROUP_CHILD)em(bf(CHILD option group)) + +Options for addresses with multiple connections via child processes. +startdit() +label(OPTION_FORK)dit(bf(tt(fork))) + After establishing a connection, handles its channel in a child process and + keeps the parent process attempting to produce more connections, either by + listening or by connecting in a loop (link(example)(EXAMPLE_OPTION_FORK)).nl() + SSL-CONNECT and SSL-LISTEN differ in when they actually fork off the child: +SSL-LISTEN forks em(before) the SSL handshake, while SSL-CONNECT forks +em(afterwards). + RETRY and FOREVER options are not inherited by the child process.nl() +enddit() + +startdit()enddit()nl() + + +label(GROUP_EXEC)em(bf(EXEC option group)) + +Options for addresses that invoke a program. +startdit() +label(OPTION_PATH)dit(bf(tt(path=))) + Overrides the PATH environment variable for searching the program with + link()(TYPE_STRING). This + code($PATH) value is effective in the child process too. +label(OPTION_LOGIN)dit(bf(tt(login))) + Prefixes code(argv[0]) for the code(execvp()) call with '-', thus making a + shell behave as login shell. +enddit() + +startdit()enddit()nl() + + +label(GROUP_FORK)em(bf(FORK option group)) + +EXEC or SYSTEM addresses invoke a program using a child process and transfer data between socat() and the program. The interprocess communication mechanism can be influenced with the following options. Per +default, a code(socketpair()) is created and assigned to stdin and stdout of +the child process, while stderr is inherited from the socat() process, and the +child process uses file descriptors 0 and 1 for communicating with the main +socat process. +startdit() +label(OPTION_NOFORK)dit(bf(tt(nofork))) + Does not fork a subprocess for executing the program, instead calls execvp() + or system() directly from the actual socat instance. This avoids the + overhead of another process between the program and its peer, + but introduces a lot of restrictions: + startit() + it() this option can only be applied to the second socat() address. + it() it cannot be applied to a part of a link(dual)(ADDRESS_DUAL) address. + 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 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 + used on the first address though. + endit() +label(OPTION_PIPES)dit(bf(tt(pipes))) + Creates a pair of unnamed pipes for interprocess communication instead of a + socket pair. +label(OPTION_OPENPTY)dit(bf(tt(openpty))) + Establishes communication with the sub process using a pseudo terminal + created with code(openpty()) instead of the default (socketpair or ptmx). +label(OPTION_PTMX)dit(bf(tt(ptmx))) + Establishes communication with the sub process using a pseudo terminal + created by opening file(/dev/ptmx) or file(/dev/ptc) instead of the default + (socketpair). +label(OPTION_PTY)dit(bf(tt(pty))) + Establishes communication with the sub process using a pseudo terminal + instead of a socket pair. Creates the pty with an available mechanism. If + openpty and ptmx are both available, it uses ptmx because this is POSIX + compliant (link(example)(EXAMPLE_OPTION_PTY)). +label(OPTION_CTTY)dit(bf(tt(ctty))) + Makes the pty the controlling tty of the sub process (link(example)(EXAMPLE_OPTION_CTTY)). +label(OPTION_STDERR)dit(bf(tt(stderr))) + Directs stderr of the sub process to its output channel by making stderr a + code(dup()) of stdout (link(example)(EXAMPLE_OPTION_STDERR)). +label(OPTION_FDIN)dit(bf(tt(fdin=))) + Assigns the sub processes input channel to its file descriptor + link()(TYPE_FDNUM) + instead of stdin (0). The program started from the subprocess has to use + this fd for reading data from socat() (link(example)(EXAMPLE_OPTION_FDIN)). +label(OPTION_FDOUT)dit(bf(tt(fdout=))) + Assigns the sub processes output channel to its file descriptor + link()(TYPE_FDNUM) + instead of stdout (1). The program started from the subprocess has to use + this fd for writing data to socat() (link(example)(EXAMPLE_OPTION_FDOUT)). +label(OPTION_SIGHUP)label(OPTION_SIGINT)label(OPTION_SIGQUIT)dit(bf(tt(sighup)), bf(tt(sigint)), bf(tt(sigquit))) + Has socat() pass an eventual signal of this type to the sub process. + If no address has this option, socat terminates on these signals. +enddit() + +startdit()enddit()nl() + + +label(GROUP_TERMIOS)em(bf(TERMIOS option group)) + +For addresses that work on a tty (e.g., stdio, file:/dev/tty, exec:...,pty), the terminal parameters defined in the unix() termios mechanism are made available as address option parameters. +Please note that changes of the parameters of your interactive terminal +remain effective after socat()'s termination, so you might have to enter "reset" +or "stty sane" in your shell afterwards. +For EXEC and SYSTEM addresses with option PTY, +these options apply to the pty by the child processes. + +startdit() +label(OPTION_B0)dit(bf(tt(b0))) + Disconnects the terminal. +label(OPTION_B19200)dit(bf(tt(b19200))) + Sets the serial line speed to 19200 baud. Some other rates are possible; use +something like tt(socat -hh |grep ' b[1-9]') to find all speeds supported by +your implementation.nl() +Note: On some operating systems, these options may not be +available. Use link(ispeed)(OPTION_ISPEED) or link(ospeed)(OPTION_OSPEED) +instead. +label(OPTION_ECHO)dit(bf(tt(echo=))) + Enables or disables local echo (link(example)(EXAMPLE_OPTION_ECHO)). +label(OPTION_ICANON)dit(bf(tt(icanon=))) + Sets or clears canonical mode, enabling line buffering and some special + characters. +label(OPTION_RAW)dit(bf(tt(raw))) + Sets raw mode, thus passing input and output almost unprocessed (link(example)(EXAMPLE_OPTION_RAW)). +label(OPTION_IGNBRK)dit(bf(tt(ignbrk=))) + Ignores or interpretes the BREAK character (e.g., ^C) +label(OPTION_BRKINT)dit(bf(tt(brkint=))) +label(OPTION_BS0)dit(bf(tt(bs0))) +label(OPTION_BS1)dit(bf(tt(bs1))) +label(OPTION_BSDLY)dit(bf(tt(bsdly=<0|1>))) +label(OPTION_CLOCAL)dit(bf(tt(clocal=))) + +label(OPTION_CR0)label(OPTION_CR1)label(OPTION_CR2)label(OPTION_CR3) +mancommand(\.LP) +mancommand(\.nf) +mancommand(\fBcr0 +cr1 +cr2 +cr3\fP) +mancommand(\.fi) +mancommand(\.IP) +htmlcommand(
    cr0
    +cr1
    +cr2
    +cr3
    ) + Sets the carriage return delay to 0, 1, 2, or 3, respectively. + 0 means no delay, the other values are terminal dependent. + +label(OPTION_CRDLY)dit(bf(tt(crdly=<0|1|2|3>))) +label(OPTION_CREAD)dit(bf(tt(cread=))) +label(OPTION_CRTSCTS)dit(bf(tt(crtscts=))) + +label(OPTION_CS5)label(OPTION_CS6)label(OPTION_CS7)label(OPTION_CS8) +mancommand(\.LP) +mancommand(\.nf) +mancommand(\fBcs5 +cs6 +cs7 +cs8\fP) +mancommand(\.fi) +mancommand(\.IP) +htmlcommand(
    cs5
    +cs6
    +cs7
    +cs8
    ) + Sets the character size to 5, 6, 7, or 8 bits, respectively. + +label(OPTION_CSIZE)dit(bf(tt(csize=<0|1|2|3>))) +label(OPTION_CSTOPB)dit(bf(tt(cstopb=))) + Sets two stop bits, rather than one. +label(OPTION_VDSUSP)dit(bf(tt(dsusp=))) + Sets the value for the VDSUSP character that suspends the current foreground + process and reactivates the shell (all except Linux). +label(OPTION_ECHOCTL)dit(bf(tt(echoctl=))) + Echos control characters in hat notation (e.g. ^A) +label(OPTION_ECHOE)dit(bf(tt(echoe=))) +label(OPTION_ECHOK)dit(bf(tt(echok=))) +label(OPTION_ECHOKE)dit(bf(tt(echoke=))) +label(OPTION_ECHONL)dit(bf(tt(echonl=))) +label(OPTION_ECHOPRT)dit(bf(tt(echoprt=))) +label(OPTION_EOF)dit(bf(tt(eof=))) +label(OPTION_EOL)dit(bf(tt(eol=))) +label(OPTION_EOL2)dit(bf(tt(eol2=))) +label(OPTION_ERASE)dit(bf(tt(erase=))) +label(OPTION_DISCARD)dit(bf(tt(discard=))) +label(OPTION_FF0)dit(bf(tt(ff0))) +label(OPTION_FF1)dit(bf(tt(ff1))) +label(OPTION_FFDLY)dit(bf(tt(ffdly=))) +label(OPTION_FLUSHO)dit(bf(tt(flusho=))) +label(OPTION_HUPCL)dit(bf(tt(hupcl=))) +label(OPTION_ICRNL)dit(bf(tt(icrnl=))) +label(OPTION_IEXTEN)dit(bf(tt(iexten=))) +label(OPTION_IGNCR)dit(bf(tt(igncr=))) +label(OPTION_IGNPAR)dit(bf(tt(ignpar=))) +label(OPTION_IMAXBEL)dit(bf(tt(imaxbel=))) +label(OPTION_INLCR)dit(bf(tt(inlcr=))) +label(OPTION_INPCK)dit(bf(tt(inpck=))) +label(OPTION_INTR)dit(bf(tt(intr=))) +label(OPTION_ISIG)dit(bf(tt(isig=))) +label(OPTION_ISPEED)dit(bf(tt(ispeed=))) + Set the baud rate for incoming data on this line.nl() + See also: link(ospeed)(OPTION_OSPEED), link(b19200)(OPTION_B19200) +label(OPTION_ISTRIP)dif(bf(tt(istrip=))) +label(OPTION_IUCLC)dit(bf(tt(iuclc=))) +label(OPTION_IXANY)dit(bf(tt(ixany=))) +label(OPTION_IXOFF)dit(bf(tt(ixoff=))) +label(OPTION_IXON)dit(bf(tt(ixon=))) +label(OPTION_KILL)dit(bf(tt(kill=))) +label(OPTION_LNEXT)dit(bf(tt(lnext=))) +label(OPTION_MIN)dit(bf(tt(min=))) +label(OPTION_NL0)dit(bf(tt(nl0))) + Sets the newline delay to 0. +label(OPTION_NL1)dit(bf(tt(nl1))) +label(OPTION_NLDLY)dit(bf(tt(nldly=))) +label(OPTION_NOFLSH)dit(bf(tt(noflsh=))) +label(OPTION_OCRNL)dit(bf(tt(ocrnl=))) +label(OPTION_OFDEL)dit(bf(tt(ofdel=))) +label(OPTION_OFILL)dit(bf(tt(ofill=))) +label(OPTION_OLCUC)dit(bf(tt(olcuc=))) +label(OPTION_ONLCR)dit(bf(tt(onlcr=))) +label(OPTION_ONLRET)dit(bf(tt(onlret=))) +label(OPTION_ONOCR)dit(bf(tt(onocr=))) +label(OPTION_OPOST)dit(bf(tt(opost=))) + Enables or disables output processing; e.g., converts NL to CR-NL. +label(OPTION_OSPEED)dit(bf(tt(ospeed=))) + Set the baud rate for outgoing data on this line.nl() + See also: link(ispeed)(OPTION_ISPEED), link(b19200)(OPTION_B19200) +label(OPTION_PARENB)dit(bf(tt(parenb=))) + Enable parity generation on output and parity checking for input. +label(OPTION_PARMRK)dit(bf(tt(parmrk=))) +label(OPTION_PARODD)dit(bf(tt(parodd=))) +label(OPTION_PENDIN)dit(bf(tt(pendin=))) +label(OPTION_QUIT)dit(bf(tt(quit=))) +label(OPTION_REPRINT)dit(bf(tt(reprint=))) +label(OPTION_SANE)dit(bf(tt(sane))) + Brings the terminal to something like a useful default state. +label(OPTION_START)dit(bf(tt(start=))) +label(OPTION_STOP)dit(bf(tt(stop=))) +label(OPTION_SUSP)dit(bf(tt(susp=))) +label(OPTION_SWTC)dit(bf(tt(swtc=))) +label(OPTION_TAB0)dit(bf(tt(tab0))) +label(OPTION_TAB1)dit(bf(tt(tab1))) +label(OPTION_TAB2)dit(bf(tt(tab2))) +label(OPTION_TAB3)dit(bf(tt(tab3))) +label(OPTION_TABDLY)dit(bf(tt(tabdly=))) +label(OPTION_TIME)dit(bf(tt(time=))) +label(OPTION_TOSTOP)dit(bf(tt(tostop=))) +label(OPTION_VT0)dit(bf(tt(vt0))) +label(OPTION_VT1)dit(bf(tt(vt1))) +label(OPTION_VTDLY)dit(bf(tt(vtdly=))) +label(OPTION_WERASE)dit(bf(tt(werase=))) +label(OPTION_XCASE)dit(bf(tt(xcase=))) +label(OPTION_XTABS)dit(bf(tt(xtabs))) +enddit() + +startdit()enddit()nl() + + +label(GROUP_PTY)em(bf(PTY option group)) + +These options are intended for use with the link(pty)(ADDRESS_PTY) address +type. + +startdit() +label(OPTION_SYMBOLIC_LINK)dit(bf(tt(link=))) + Generates a symbolic link that points to the actual pseudo terminal + (pty). This might help + to solve the problem that ptys are generated with more or less + unpredictable names, making it difficult to directly access the socat + generated pty automatically. With this option, the user can specify a "fix" + point in the file hierarchy that helps him to access the actual pty + (link(example)(EXAMPLE_OPTION_SYMBOLIC_LINK)). + Beginning with socat() version 1.4.3, the symbolic link is removed when + the address is closed (but see option link(unlink-close)(OPTION_UNLINK_CLOSE)). +label(OPTION_PTY_WAIT_SLAVE)dit(bf(tt(wait-slave))) + Blocks the open phase until a process opens the slave side of the pty. + Usually, socat continues after generating the pty with opening the next + address or with entering the transfer loop. With the wait-slave option, + socat waits until some process opens the slave side of the pty before + continuing. + This option only works if the operating system provides the tt(poll()) + system call. And it depends on an undocumented behaviour of pty's, so it + does not work on all operating systems. It has successfully been tested on + Linux, FreeBSD, NetBSD, and on Tru64 with openpty. +label(OPTION_PTY_INTERVALL)dit(bf(tt(pty-intervall=))) + When the link(wait-slave)(OPTION_PTY_WAIT_SLAVE) option is set, socat + periodically checks the HUP condition using tt(poll()) to find if the pty's + slave side has been opened. The default polling intervall is 1s. Use the + pty-intervall option [link(timeval)(TYPE_TIMEVAL)] to change this value. +enddit() + + +startdit()enddit()nl() + + +label(GROUP_OPENSSL)em(bf(OPENSSL option group)) + +These options apply to the link(openssl)(ADDRESS_OPENSSL_CONNECT) and +link(openssl-listen)(ADDRESS_OPENSSL_LISTEN) address types. + +startdit() +label(OPTION_OPENSSL_CIPHERLIST)dit(bf(tt(cipher=))) + Selects the list of ciphers that may be used for the connection. + See the man page of code(ciphers), section bf(CIPHER LIST FORMAT), for + detailed information about syntax, values, and default of .nl() + Several cipher strings may be given, separated by ':'. + Some simple cipher strings: + startdit() + dit(3DES) Uses a cipher suite with triple DES. + dit(MD5) Uses a cipher suite with MD5. + dit(aNULL) Uses a cipher suite without authentication. + dit(NULL) Does not use encryption. + dit(HIGH) Uses a cipher suite with "high" encryption. + enddit() + Note that the peer must support the selected property, or the negotiation + will fail. +label(OPTION_OPENSSL_METHOD)dit(bf(tt(method=))) + Sets the protocol version to be used. Valid strings (not case sensitive) + are: + startdit() + dit(tt(SSLv2)) Select SSL protocol version 2. + dit(tt(SSLv3)) Select SSL protocol version 3. + dit(tt(SSLv23)) Select SSL protocol version 2 or 3. This is the default when + this option is not provided. + dit(tt(TLSv1)) Select TLS protocol version 1. + enddit() +label(OPTION_OPENSSL_VERIFY)dit(bf(tt(verify=))) + Controls check of the peer's certificate. Default is 1 (true). Disabling + verify might open your socket for everyone, making the encryption useless! +label(OPTION_OPENSSL_CERTIFICATE)dit(bf(tt(cert=))) + Specifies the file with the certificate and private key for authentication. + The certificate must be in OpenSSL format (*.pem). + With openssl-listen, use of this option is strongly + recommended. Except with cipher aNULL, "no shared ciphers" error will + occur when no certificate is given. +label(OPTION_OPENSSL_KEY)dit(bf(tt(key=))) + Specifies the file with the private key. The private key may be in this + file or in the file given with the link(cert)(OPTION_OPENSSL_CERTIFICATE) option. The party that has + to proof that it is the owner of a certificate needs the private key. +label(OPTION_OPENSSL_DHPARAMS)dit(bf(tt(dhparams=))) + Specifies the file with the Diffie Hellman parameters. These parameters may + also be in the file given with the link(cert)(OPTION_OPENSSL_CERTIFICATE) + option in which case the dhparams option is not needed. +label(OPTION_OPENSSL_CAFILE)dit(bf(tt(cafile=))) + Specifies the file with the trusted (root) authority certificates. The file + must be in PEM format and should contain one or more certificates. The party + that checks the authentication of its peer trusts only certificates that are + in this file. +label(OPTION_OPENSSL_CAPATH)dit(bf(tt(capath=))) + Specifies the directory with the trusted (root) certificates. The directory + must contain certificates in PEM format and their hashes (see OpenSSL + documentation) +label(OPTION_OPENSSL_EGD)dit(bf(tt(egd=))) + On some systems, openssl requires an explicit source of random data. Specify + the socket name where an entropy gathering daemon like egd provides random + data, e.g. /dev/egd-pool. +label(OPTION_OPENSSL_PSEUDO)dit(bf(tt(pseudo))) + On systems where openssl cannot find an entropy source and where no entropy + gathering daemon can be utilized, this option activates a mechanism for + providing pseudo entropy. This is archieved 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 random() calls.nl() + NOTE:This mechanism is not sufficient for generation of secure keys! +label(OPTION_OPENSSL_FIPS)dit(bf(tt(fips))) + Enables FIPS mode if compiled in. For info about the FIPS encryption + implementation standard see lurl(http://oss-institute.org/fips-faq.html). + This mode might require that the involved certificates are generated with a + FIPS enabled version of openssl. Setting or clearing this option on one + socat address affects all OpenSSL addresses of this process. +enddit() + +startdit()enddit()nl() + + +label(GROUP_RETRY)em(bf(RETRY option group)) + +Options that control retry of some system calls, especially connection +attempts. + +startdit() +label(OPTION_RETRY)dit(bf(tt(retry=))) + Number of retries before the connection or listen attempt is aborted. + Default is 0, which means just one attempt. +label(OPTION_INTERVALL)dit(bf(tt(intervall=))) + Time between consecutive attempts (seconds, + [link(timespec)(TYPE_TIMESPEC)]). Default is 1 second. +label(OPTION_FOREVER)dit(bf(tt(forever))) + Performs an unlimited number of retry attempts. +enddit() + +startdit()enddit()nl() + + +label(GROUP_TUN)em(bf(TUN option group)) + +Options that control Linux TUN/TAP interface device addresses. + +startdit() +label(OPTION_TUN_DEVICE)dit(bf(tt(tun-device=))) + Instructs socat to take another path for the TUN clone device. Default is + tt(/dev/net/tun). +label(OPTION_TUN_NAME)dit(bf(tt(tun-name=))) + Gives the resulting network interface a specific name instead of the system + generated (tun0, tun1, etc.) +label(OPTION_TUN_TYPE)dit(bf(tt(tun-type=[tun|tap]))) + Sets the type of the TUN device; use this option to generate a TAP + device. See the Linux docu for the difference between these types. + When you try to establish a tunnel between two TUN devices, their types + should be the same. +label(OPTION_IFF_NO_PI)dit(bf(tt(iff-no-pi))) + Sets the IFF_NO_PI flag which controls if the device includes additional + packet information in the tunnel. + When you try to establish a tunnel between two TUN devices, these flags + should have the same values. +label(OPTION_IFF_UP)dit(bf(tt(iff-up))) + Sets the TUN network interface status UP. Strongly recommended. +label(OPTION_IFF_BROADCAST)dit(bf(tt(iff-broadcast))) + Sets the BROADCAST flag of the TUN network interface. +label(OPTION_IFF_DEBUG)dit(bf(tt(iff-debug))) + Sets the DEBUG flag of the TUN network interface. +label(OPTION_IFF_LOOPBACK)dit(bf(tt(iff-loopback))) + Sets the LOOPBACK flag of the TUN network interface. +label(OPTION_IFF_POINTOPOINT)dit(bf(tt(iff-pointopoint))) + Sets the POINTOPOINT flag of the TUN device. +label(OPTION_IFF_NOTRAILERS)dit(bf(tt(iff-notrailers))) + Sets the NOTRAILERS flag of the TUN device. +label(OPTION_IFF_RUNNING)dit(bf(tt(iff-running))) + Sets the RUNNING flag of the TUN device. +label(OPTION_IFF_NOARP)dit(bf(tt(iff-noarp))) + Sets the NOARP flag of the TUN device. +label(OPTION_IFF_PROMISC)dit(bf(tt(iff-promisc))) + Sets the PROMISC flag of the TUN device. +label(OPTION_IFF_ALLMULTI)dit(bf(tt(iff-allmulti))) + Sets the ALLMULTI flag of the TUN device. +label(OPTION_IFF_MASTER)dit(bf(tt(iff-master))) + Sets the MASTER flag of the TUN device. +label(OPTION_IFF_SLAVE)dit(bf(tt(iff-slave))) + Sets the SLAVE flag of the TUN device. +label(OPTION_IFF_MULTICAST)dit(bf(tt(iff-multicast))) + Sets the MULTICAST flag of the TUN device. +label(OPTION_IFFPORTSEL_)dit(bf(tt(iff-portsel))) + Sets the PORTSEL flag of the TUN device. +label(OPTION_IFF_AUTOMEDIA)dit(bf(tt(iff-automedia))) + Sets the AUTOMEDIA flag of the TUN device. +label(OPTION_IFF_DYNAMIC)dit(bf(tt(iff-dynamic))) + Sets the DYNAMIC flag of the TUN device. +enddit() + +startdit()enddit()nl() + + +label(VALUES) +manpagesection(DATA VALUES) + +This section explains the different data types that address parameters and +address options can take. + +startdit() +label(TYPE_ADDRESS_RANGE)dit(address-range) + Is currently only implemented for IPv4 and IPv6. See address-option + link(`range')(OPTION_RANGE) +label(TYPE_BOOL)dit(bool) + "0" or "1"; if value is omitted, "1" is taken. +label(TYPE_BYTE)dit(byte) + An unsigned int number, read with code(strtoul()), lower or equal to + code(UCHAR_MAX). +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) + A raw data specification following em(dalan) syntax. The only documented + form is a string starting with 'x' followed by an even number of hex digits. +label(TYPE_DIRECTORY)dit(directory) + A string with usual unix() directory name semantics. +label(TYPE_FACILITY)dit(facility) + The name of a syslog facility in lower case characters. +label(TYPE_FDNUM)dit(fdnum) + An unsigned int type, read with code(strtoul()), specifying a unix() file + descriptor. +label(TYPE_FILENAME)dit(filename) + A string with usual unix() filename semantics. +label(TYPE_GROUP)dit(group) + If the first character is a decimal digit, the value is read with + code(strtoul()) as unsigned integer specifying a group id. Otherwise, it + must be an existing group name. +label(TYPE_INT)dit(int) + A number following the rules of the code(strtol()) function with base + "0", i.e. decimal number, octal number with leading "0", or hexadecimal + number with leading "0x". The value must fit into a C int. +label(TYPE_INTERFACE)dit(interface) + A string specifying the device name of a network interface, e.g. "eth0". +label(TYPE_IP_ADDRESS)dit(IP address) + An IPv4 address in numbers-and-dots notation, an IPv6 address in hex + notation enclosed in brackets, or a hostname that resolves to an IPv4 or an + IPv6 address.nl() + Examples: 127.0.0.1, [::1], www.dest-unreach.org, dns1 +label(TYPE_IPV4_ADDRESS)dit(IPv4 address) + An IPv4 address in numbers-and-dots notation or a hostname that resolves to + an IPv4 address.nl() + Examples: 127.0.0.1, www.dest-unreach.org, dns2 +label(TYPE_IPV6_ADDRESS)dit(IPv6 address) + An iPv6 address in hexnumbers-and-colons notation enclosed in brackets, or a + hostname that resolves to an IPv6 address.nl() + Examples: [::1], [1234:5678:9abc:def0:1234:5678:9abc:def0], + ip6name.domain.org +label(TYPE_LONG)dit(long) + A number read with code(strtol()). The value must fit into a C 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 + or strtoll. +label(TYPE_OFF64)dit(off64_t) + An implementation dependend 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) + bits. +label(TYPE_PID_T)dit(pid_t) + A number, read with code(strtol()), specifying a process id. +label(TYPE_PORT)dit(port) + A uint16_t (16 bit unsigned number) specifying a TCP or UDP port, read + with code(strtoul()). +label(TYPE_PROTOCOL)dit(protocol) + An unsigned 8 bit number, read with code(strtoul()). +label(TYPE_SIZE_T)dit(size_t) + An unsigned number with size_t limitations, read with code(strtoul). +label(TYPE_SOCKNAME)dit(sockname) + A socket address. See address-option link(`bind')(OPTION_BIND) +label(TYPE_STRING)dit(string) + A sequence of characters, not containing '\0' and, depending on + the position within the command line, ':', ',', or "!!". Note + that you might have to escape shell meta characters in the command line. +label(TYPE_TCP_SERVICE)dit(TCP service) + A service name, not starting with a digit, that is resolved by + code(getservbyname()), or an unsigned int 16 bit number read with + code(strtoul()). +label(TYPE_TIMEVAL)dit(timeval) + A double float specifying seconds; the number is mapped into a + struct timeval, consisting of seconds and microseconds. +label(TYPE_TIMESPEC)dit(timespec) + A double float specifying seconds; the number is mapped into a + struct timespec, consisting of seconds and nanoseconds. +label(TYPE_UDP_SERVICE)dit(UDP service) + A service name, not starting with a digit, that is resolved by + code(getservbyname()), or an unsigned int 16 bit number read with + code(strtoul()). +label(TYPE_UNSIGNED_INT)dit(unsigned int) + A number read with code(strtoul()). The value must fit into a C unsigned + int. +label(TYPE_USER)dit(user) + If the first character is a decimal digit, the value is read with + code(strtoul()) as unsigned integer specifying a user id. Otherwise, it must + be an existing user name. +enddit() + + +label(EXAMPLES) +manpagesection(EXAMPLES) + + +startdit() + +label(EXAMPLE_ADDRESS_TCP4_CONNECT) +dit(bf(tt(socat - TCP4:www.domain.org:80))) + +Transfers data between link(STDIO)(ADDRESS_STDIO) (-) and a +link(TCP4)(ADDRESS_TCP4_CONNECT) connection to port 80 of host +www.domain.org. This example results in an interactive connection similar to +telnet or netcat. The stdin terminal parameters are not changed, so you may +close the relay with ^D or abort it with ^C. + +label(EXAMPLE_ADDRESS_READLINE) +label(EXAMPLE_OPTION_HISTORY) +mancommand(\.LP) +mancommand(\.nf) +mancommand(\fBsocat -d -d READLINE,history=$HOME/.http_history \\ +TCP4:www.domain.org:www,crnl\fP) +mancommand(\.fi) + +htmlcommand(
    socat -d -d READLINE,history=$HOME/.http_history \
    +TCP4:www.domain.org:www,crnl
    ) + +This is similar to the previous example, but you can edit the current line in a +bash like manner (link(READLINE)(ADDRESS_READLINE)) and use the +link(history)(OPTION_HISTORY) file .http_history; socat() +prints messages about progress (link(-d -d)(option_d_d)). The port is specified by service name +(www), and correct network line termination characters (link(crnl)(OPTION_CRNL)) instead of NL +are used. + + +label(EXAMPLE_ADDRESS_TCP4_LISTEN) +dit(bf(tt(socat TCP4-LISTEN:www TCP4:www.domain.org:www))) + +Installs a simple TCP port forwarder. With +link(TCP4-LISTEN)(ADDRESS_TCP4_LISTEN) it listens on local port "www" until a +connection comes in, accepts it, then connects to the remote host +(link(TCP4)(ADDRESS_TCP4_CONNECT)) and starts data transfer. It will not accept a +second connection. + +label(EXAMPLE_OPTION_BIND_TCP4) +label(EXAMPLE_OPTION_REUSEADDR) +label(EXAMPLE_OPTION_FORK) +label(EXAMPLE_OPTION_SUBSTUSER) +label(EXAMPLE_OPTION_RANGE) +mancommand(\.LP) +mancommand(\.nf) +mancommand(\fBsocat -d -d -lmlocal2 \\ +TCP4-LISTEN:80,bind=myaddr1,reuseaddr,fork,su=nobody,range=10.0.0.0/8 \\ +TCP4:www.domain.org:80,bind=myaddr2\fP) +mancommand(\.fi) + +htmlcommand(
    socat -d -d -lmlocal2 \
    +TCP4-LISTEN:80,bind=myaddr1,su=nobody,fork,range=10.0.0.0/8,reuseaddr \
    +TCP4:www.domain.org:80,bind=myaddr2
    ) + +TCP port forwarder, each side bound to another local IP address +(link(bind)(OPTION_BIND)). This example handles an almost +arbitrary number of parallel or consecutive connections by +link(fork)(OPTION_FORK)'ing a new +process after each code(accept()). It provides a little security by +link(su)(OPTION_SUBSTUSER)'ing to user +nobody after forking; it only permits connections from the private 10 network (link(range)(OPTION_RANGE)); +due to link(reuseaddr)(OPTION_REUSEADDR), it allows immediate restart after master process's +termination, even if some child sockets are not completely shut down. +With link(-lmlocal2)(option_lm), socat logs to stderr until successfully +reaching the accept loop. Further logging is directed to syslog with facility +local2. + +label(EXAMPLE_ADDRESS_EXEC) +label(EXAMPLE_OPTION_TCPWRAPPERS) +label(EXAMPLE_OPTION_CHROOT) +label(EXAMPLE_OPTION_SUBSTUSER_DELAYED) +label(EXAMPLE_OPTION_PTY) +label(EXAMPLE_OPTION_STDERR) +mancommand(\.LP) +mancommand(\.nf) +mancommand(\fBsocat TCP4-LISTEN:5555,fork,tcpwrap=script \\ +EXEC:/bin/myscript,chroot=/home/sandbox,su-d=sandbox,pty,stderr\fP) +mancommand(\.fi) + +htmlcommand(
    socat TCP4-LISTEN:5555,fork,tcpwrap=script \
    +EXEC:/bin/myscript,chroot=/home/sandbox,su-d=sandbox,pty,stderr
    ) + +A simple server that accepts connections +(link(TCP4-LISTEN)(ADDRESS_TCP4_LISTEN)) and link(fork)(OPTION_FORK)'s a new +child process for each connection; every child acts as single relay. +The client must match the rules for daemon process name "script" in +/etc/hosts.allow and /etc/hosts.deny, otherwise it is refused access (see "man +5 hosts_access"). +For link(EXEC)(ADDRESS_EXEC)'uting the program, the child process +link(chroot)(OPTION_CHROOT)'s +to file(/home/sandbox), link(su)(OPTION_SUBSTUSER)'s to user sandbox, and then starts +the program file(/home/sandbox/bin/myscript). Socat() and +myscript communicate via a pseudo tty (link(pty)(OPTION_PTY)); myscript's +link(stderr)(OPTION_STDERR) is redirected to stdout, +so its error messages are transferred via socat() to the connected client. + +label(EXAMPLE_OPTION_FDIN) +label(EXAMPLE_OPTION_FDOUT) +label(EXAMPLE_OPTION_CRNL) +label(EXAMPLE_OPTION_MSS) +mancommand(\.LP) +mancommand(\.nf) +mancommand(\fBsocat EXEC:"mail.sh target@domain.com",fdin=3,fdout=4 \\ +TCP4:mail.relay.org:25,crnl,bind=alias1.server.org,mss=512\fP) +mancommand(\.fi) + +htmlcommand(
    socat EXEC:"mail.sh target@domain.com",fdin=3,fdout=4 \
    +TCP4:mail.relay.org:25,crnl,bind=alias1.server.org,mss=512
    ) + +file(mail.sh) is a shell script, distributed with socat(), that implements a +simple +SMTP client. It is programmed to "speak" SMTP on its FDs 3 (in) and 4 (out). +The link(fdin)(OPTION_FDIN) and link(fdout)(OPTION_FDOUT) options tell socat() +to use these FDs for communication with +the program. Because mail.sh inherits stdin and stdout while socat() does not +use them, the script can read a +mail body from stdin. Socat() makes alias1 your local source address +(link(bind)(OPTION_BIND)), cares for correct network line termination +(link(crnl)(OPTION_CRNL)) and sends +at most 512 data bytes per packet (link(mss)(OPTION_MSS)). + + +label(EXAMPLE_ADDRESS_GOPEN) +label(EXAMPLE_OPTION_RAW) +label(EXAMPLE_OPTION_ECHO) +dit(bf(tt(socat - /dev/ttyS0,raw,echo=0,crnl))) + +Opens an interactive connection via the serial line, e.g. for talking with a +modem. link(raw)(OPTION_RAW) and link(echo)(OPTION_ECHO) set ttyS0's terminal +parameters to practicable values, link(crnl)(OPTION_CRNL) +converts to correct newline characters. Consider using +link(READLINE)(ADDRESS_READLINE) instead of `-'. + + +label(EXAMPLE_ADDRESS_UNIX_LISTEN) +label(EXAMPLE_ADDRESS_SOCKS4) +label(EXAMPLE_OPTION_SOCKSUSER) +label(EXAMPLE_OPTION_SOURCEPORT) +mancommand(\.LP) +mancommand(\.nf) +mancommand(\fBsocat UNIX-LISTEN:/tmp/.X11-unix/X1,fork \\ +SOCKS4:host.victim.org:127.0.0.1:6000,socksuser=nobody,sourceport=20\fP) +mancommand(\.fi) + +htmlcommand(
    socat UNIX-LISTEN:/tmp/.X11-unix/X1,fork \
    +SOCKS4:host.victim.org:127.0.0.1:6000,socksuser=nobody,sourceport=20
    ) + +With link(UNIX-LISTEN)(ADDRESS_UNIX_LISTEN), socat() opens a listening +unixdomain() socket file(/tmp/.X11-unix/X1). This path corresponds +to local XWindow display :1 on your machine, so XWindow client connections to +DISPLAY=:1 are accepted. Socat() then speaks with +the link(SOCKS4)(ADDRESS_SOCKS4) server host.victim.org that might permit +link(sourceport)(OPTION_SOURCEPORT) 20 based connections due to an FTP related +weakness in its static IP filters. Socat() +pretends to be invoked by link(socksuser)(OPTION_SOCKSUSER) nobody, and +requests to be connected to +loopback port 6000 (only weak sockd configurations will allow this). So we get +a connection to the victims XWindow server and, if it does not require MIT +cookies or Kerberos authentication, we can start work. Please note that there +can only be one connection at a time, because TCP can establish only one +session with a given set of addresses and ports. + + +label(EXAMPLE_option_u) +label(EXAMPLE_OPTION_IGNOREEOF) +dit(bf(tt(socat -u /tmp/readdata,seek-end=0,ignoreeof -))) + +This is an example for unidirectional data transfer +(link(-u)(option_u)). Socat() transfers data +from file /tmp/readdata (implicit address link(GOPEN)(ADDRESS_GOPEN)), starting +at its current end (link(seek-end)(OPTION_SEEK_END)=0 lets socat() start +reading at current end of file; use link(seek)(OPTION_SEEK)=0 or no +seek option to first read the existing data) in a "tail -f" like mode +(link(ignoreeof)(OPTION_IGNOREEOF)). The "file" +might also be a listening unixdomain() socket (do not use a seek option then). + + +label(EXAMPLE_OPTION_SETSID) +label(EXAMPLE_OPTION_CTTY) +mancommand(\.LP) +mancommand(\.nf) +mancommand(\fB(sleep 5; echo PASSWORD; sleep 5; echo ls; sleep 1) | +socat - EXEC:'ssh -l user server',pty,setsid,ctty\fP) +mancommand(\.fi) + +htmlcommand(
    (echo PASSWORD; sleep 5; echo ls; sleep 1) |
    +socat - EXEC:'ssh -l user server',pty,setsid,ctty
    ) + +link(EXEC)(ADDRESS_EXEC)'utes an ssh session to server. Uses a link(pty)(OPTION_PTY) for communication between socat() and +ssh, makes it ssh's controlling tty (link(ctty)(OPTION_CTTY)), +and makes this pty the owner of +a new process group (link(setsid)(OPTION_SETSID)), so ssh accepts the password from socat(). + + +label(EXAMPLE_ADDRESS_OPEN) +label(EXAMPLE_OPTION_CREAT) +label(EXAMPLE_OPTION_APPEND) +mancommand(\.LP) +mancommand(\.nf) +mancommand(\fBsocat -u TCP4-LISTEN:3334,reuseaddr,fork \\ +OPEN:/tmp/in.log,creat,append\fP) +mancommand(\.fi) + +htmlcommand(
    socat -u TCP4-LISTEN:3334,reuseaddr,fork \
    +OPEN:/tmp/in.log,creat,append
    ) + +Implements a simple network based message collector. +For each client connecting to port 3334, a new child process is generated (option link(fork)(OPTION_FORK)). +All data sent by the clients are link(append)(OPTION_APPEND)'ed to the file /tmp/in.log. +If the file does not exist, socat link(creat)(OPTION_CREAT)'s it. +Option link(reuseaddr)(OPTION_REUSEADDR) allows immediate restart of the server +process. + +COMMENT( +dit(bf(tt(socat TCP4-LISTEN:3335,reuseaddr,fork OPEN:/tmp/motd,rdonly))) + +Implements a simple network based motd server. +For each client connecting to port 3335, a new child process is generated +(option link(fork)(OPTION_FORK)). +The contents of the file /tmp/motd is sent to each client. +Messages sent by clients result in an error due to option link(rdonly)(OPTION_RDONLY). +Option link(reuseaddr)(OPTION_REUSEADDR) allows immediate restart of the server +process. +) +COMMENT( +dit(bf(tt(socat - TCP4-LISTEN:8080,mtudiscover=0,rcvbuf=2048))) + +Changes some socket parameters to confuse active OS fingerprinting methods. +link(mtudiscover)(OPTION_MTUDISCOVER)=0 sets the DF (don'ft fragment flag) in +the IP packets to 0 and link(rcvbuf)(OPTION_RCVBUF) changes the initial TCP +window size. +) + +label(EXAMPLE_OPTION_NOECHO) +dit(bf(tt(socat READLINE,noecho='[Pp]assword:' EXEC:'ftp ftp.server.com',pty,setsid,ctty))) + +Wraps a command line history (link(READLINE)(ADDRESS_READLINE)) around the link(EXEC)(ADDRESS_EXEC)'uted ftp client utility. +This allows editing and reuse of FTP commands for relatively comfortable +browsing through the ftp directory hierarchy. The password is echoed! + link(pty)(OPTION_PTY) is required to have ftp issue a prompt. +Nevertheless, there may occur some confusion with the password and FTP +prompts. + + +label(EXAMPLE_ADDRESS_PTY) +label(EXAMPLE_OPTION_SYMBOLIC_LINK) +label(EXAMPLE_OPTION_WAITSLAVE) +label(EXAMPLE_OPTION_NONBLOCK) +(bf(tt(socat PTY,link=$HOME/dev/vmodem0,raw,echo=0,waitslave EXEC:'"ssh modemserver.us.org socat - /dev/ttyS0,nonblock,raw,echo=0"'))) + +Generates a pseudo terminal +device (link(PTY)(ADDRESS_PTY)) on the client that can be reached under the +symbolic link(link)(OPTION_SYMBOLIC_LINK) file($HOME/dev/vmodem0). +An application that expects a serial line or modem +can be configured to use file($HOME/dev/vmodem0); its traffic will be directed +to a modemserver via ssh where another socat instance links it with +file(/dev/ttyS0). + + +mancommand(\.LP) +mancommand(\.nf) +mancommand(\fBsocat TCP4-LISTEN:2022,reuseaddr,fork \\ +PROXY:proxy:www.domain.org:22,proxyport=3128,proxyauth=user:pass\fP) +mancommand(\.fi) + +htmlcommand(
    socat TCP4-LISTEN:2022,reuseaddr,fork \
    +PROXY:proxy:www.domain.org:22,proxyport=3128,proxyauth=user:pass
    ) + +starts a forwarder that accepts connections on port 2022, and directs them +through the link(proxy)(ADDRESS_PROXY_CONNECT) daemon listening on port 3128 +(link(proxyport)(OPTION_PROXYPORT)) on host proxy, using the +CONNECT method, where they are authenticated as "user" with "pass" (link(proxyauth)(OPTION_PROXY_AUTHORIZATION)). The proxy +should establish connections to host www.domain.org on port 22 then. + + +label(EXAMPLE_ADDRESS_OPENSSL_CONNECT) +dit(bf(tt(socat - SSL:server:4443,cafile=server.crt,cert=client.pem))) + +is an OpenSSL client that tries to establish a secure connection to an SSL +server. Option link(cafile)(OPTION_OPENSSL_CAFILE) specifies a file that +contains trust certificates: we trust the server only when it presents one of +these certificates and proofs that it owns the related private key. +Otherwise the connection is terminated. +With link(cert)(OPTION_OPENSSL_CERTIFICATE) a file containing the client certificate +and the associated private key is specified. This is required in case the +server wishes a client authentication; many Internet servers do not.nl() +The first address ('-') can be replaced by almost any other socat address. + + +label(EXAMPLE_ADDRESS_OPENSSL_LISTEN) +dit(bf(tt(socat SSL-LISTEN:4443,reuseaddr,pf=ip4,fork,cert=server.pem,cafile=client.crt PIPE))) + +is an OpenSSL server that accepts TCP connections, presents the certificate +from the file server.pem and forces the client to present a certificate that is +verified against cafile.crt.nl() +The second address ('PIPE') can be replaced by almost any other socat +address.nl() +For instructions on generating and distributing OpenSSL keys and certificates +see the additional socat docu tt(socat-openssl.txt). + + +dit(bf(tt(echo |socat -u - file:/tmp/bigfile,create,largefile,seek=100000000000))) + +creates a 100GB sparse file; this requires a file system type that +supports this (ext2, ext3, reiserfs, jfs; not minix, vfat). The operation of +writing 1 byte might take long (reiserfs: some minutes; ext2: "no" time), and +the resulting file can consume some disk space with just its inodes (reiserfs: +2MB; ext2: 16KB). + + +dit(bf(tt(socat tcp-l:7777,reuseaddr,fork system:'filan -i 0 -s >&2',nofork))) + +listens for incoming TCP connections on port 7777. For each accepted +connection, invokes a shell. This shell has its stdin and stdout directly +connected to the TCP socket (link(nofork)(OPTION_NOFORK)). The shell starts filan and lets it print the socket addresses to +stderr (your terminal window). + + +dit(bf(tt(echo -e "\0\14\0\0\c" |socat -u - file:/usr/bin/squid.exe,seek=0x00074420))) + +functions as primitive binary editor: it writes the 4 bytes 000 014 000 000 to +the executable /usr/bin/squid at offset 0x00074420 (this is a real world patch +to make the squid executable from Cygwin run under Windows, actual per May 2004). + + +dit(bf(tt(socat - tcp:www.blackhat.org:31337,readbytes=1000))) + +connects to an unknown service and prevents being flooded. + + +label(EXAMPLE_END_CLOSE) +dit(bf(tt(socat -U TCP:target:9999,end-close TCP-L:8888,reuseaddr,fork))) + +merges data arriving from different TCP streams on port 8888 to just one stream +to target:9999. The link(end-close)(OPTION_END_CLOSE) option prevents the child +processes forked off by the second address from terminating the shared +connection to 9999 (close(2) just unlinks the inode which stays active as long +as the parent process lives; shutdown(2) would actively terminate the +connection). + + +label(EXAMPLE_ADDRESS_UDP4_BROADCAST_CLIENT) +dit(bf(tt(socat - UDP4-DATAGRAM:192.168.1.0:123,sp=123,broadcast,range=192.168.1.0/24))) + +sends a broadcast to the network 192.168.1.0/24 and receives the replies of the +timeservers there. Ignores NTP packets from hosts outside this network. + + +label(EXAMPLE_ADDRESS_IP4_BROADCAST_CLIENT) +dit(bf(tt(socat - IP4-DATAGRAM:255.255.255.255:44,broadcast,range=10.0.0.0/8))) + +sends a broadcast to the local network(s) using protocol 44. Accepts replies +from the private address range only. + + +label(EXAMPLE_ADDRESS_UDP4_MULTICAST) +dit(bf(tt(socat - UDP4-DATAGRAM:224.255.0.1:6666,bind=:6666,ip-add-membership=224.255.0.1:eth0))) + +transfers data from stdin to the specified multicast address using UDP. Both +local and remote ports are 6666. Tells the interface eth0 to also accept +multicast packets of the given group. Multiple hosts on the local network can +run this command, so all data sent by any of the hosts will be received +by all the other ones. Note that there are many possible reasons for failure, +including IP-filters, routing issues, wrong interface selection by the +operating system, bridges, or a badly configured switch. + + +label(EXAMPLE_ADDRESS_TUN) +dit(bf(tt(socat TCP:host2:4443 TUN:192.168.255.1/24,up))) + +establishes one side of a virtual (but not private!) network with host2 where a +similar process might run, with TCP-L and tun address 192.168.255.2. They +can reach each other using the addresses 192.168.255.1 and +192.168.255.2. Substitute the TCP link with an SSL connection protected by +client and server authentication (see OpenSSL +link(client)(EXAMPLE_ADDRESS_OPENSSL_CONNECT) and +link(server)(EXAMPLE_ADDRESS_OPENSSL_LISTEN)). + +enddit() + + +label(DIAGNOSTICS) +manpagediagnostics() + +Socat() uses a logging mechanism that allows to filter messages by severity. The +severities provided are more or less compatible to the appropriate syslog +priority. With one or up to four occurrences of the -d command line option, the +lowest priority of messages that are issued can be selected. Each message +contains a single uppercase character specifying the messages severity (one of +F, E, W, N, I, or D) + +description( +dit(FATAL:) Conditions that require unconditional and immediate program termination. +dit(ERROR:) Conditions that prevent proper program processing. Usually the +program is terminated (see link(option -s)(option_s)). +dit(WARNING:) Something did not function correctly or is in a state where +correct further processing cannot be guaranteed, but might be possible. +dit(NOTICE:) Interesting actions of the program, e.g. for supervising socat() in some kind of server mode. +dit(INFO:) Description of what the program does, and maybe why it +happens. Allows to monitor the lifecycles of file descriptors. +dit(DEBUG:) Description of how the program works, all system or library calls and their results. +) + +Log messages can be written to stderr, to a file, or to syslog. + +On exit, socat() gives status 0 if it terminated due to EOF or inactivity +timeout, with a positive value on error, and with a negative value on fatal +error. + + +label(FILES) +manpagefiles() + +/usr/bin/socat nl() +/usr/bin/filan nl() +/usr/bin/procan + + +label(ENVIRONMENT_VARIABLES) +manpagesection(ENVIRONMENT VARIABLES) + +startdit() +dit(bf(SOCAT_DEFAULT_LISTEN_IP)) (Values 4 or 6) Sets the IP version to be used +for listen, recv, and recvfrom addresses if no link(pf)(OPTION_PROTOCOL_FAMILY) +(protocol-family) option is given. Is overridden by socat options +link(-4)(option_4) or link(-6)(option_6). + +dit(bf(SOCAT_PREFERRED_RESOLVE_IP)) (Values 0, 4, or 6) Sets the IP version to +be used when resolving target host names when version is not specified by +address type, option link(pf)(OPTION_PROTOCOL_FAMILY) (protocol-family), or +address format. If name resolution does not return a matching entry, the first +result (with differing IP version) is taken. With value 0, socat always selects +the first record and its IP version. + +dit(bf(SOCAT_FORK_WAIT)) Specifies the time (seconds) to sleep the parent and +child processes after successful fork(). Useful for debugging. + +dit(bf(HOSTNAME)) Is used to determine the hostname for logging (see +link(-lh)(option_lh)). + +dit(bf(LOGNAME)) Is used as name for the socks client user name if no +link(socksuser)(OPTION_SOCKSUSER) is given.nl() +With options link(su)(OPTION_SUBSTUSER) and +link(su-d)(OPTION_SUBSTUSER_DELAYED), LOGNAME is set to the given user name. + +dit(bf(USER)) Is used as name for the socks client user name if no +link(socksuser)(OPTION_SOCKSUSER) is given and LOGNAME is empty.nl() +With options link(su)(OPTION_SUBSTUSER) and +link(su-d)(OPTION_SUBSTUSER_DELAYED), USER is set to the given user name. + +dit(bf(SHELL)) +With options link(su)(OPTION_SUBSTUSER) and +link(su-d)(OPTION_SUBSTUSER_DELAYED), SHELL is set to the login shell of the +given user. + +dit(bf(PATH)) +Can be set with option link(path)(OPTION_PATH) for link(exec)(ADDRESS_EXEC) and +link(system)(ADDRESS_SYSTEM) addresses. + +dit(bf(HOME)) +With options link(su)(OPTION_SUBSTUSER) and +link(su-d)(OPTION_SUBSTUSER_DELAYED), HOME is set to the home directory of the +given user. + +enddit() + +label(CREDITS) +manpagesection(CREDITS) + +The work of the following groups and organizations was invaluable for this +project: + +The em(FSF) (GNU, lurl(http://www.fsf.org/) project +with their free and portable development software and +lots of other useful tools and libraries. + +The em(Linux developers community) (lurl(http://www.linux.org/)) for providing a free, open source operating +system. + +The em(Open Group) (lurl(http://www.unix-systems.org/)) for making their +standard specifications available on the Internet for free. + + +label(VERSION) +manpagesection(VERSION) + +This man page describes version 1.6.0 of socat(). + + +label(BUGS) +manpagebugs() + +Addresses cannot be nested, so a single socat process cannot, e.g., drive ssl +over socks. + +Address option ftruncate without value uses default 1 instead of 0. + +Verbose modes (-x and/or -v) display line termination characters inconsistently +when address options cr or crnl are used: They show the data em(after) +conversion in either direction. + +The data transfer blocksize setting (-b) is ignored with address readline. + +Send bug reports to + + +label(SEEALSO) +manpageseealso() + +COMMENT(procan\(1), filan\(1), ) +nc(1), netcat6(1), sock(1), rinetd(8), cage(1), socks.conf(5), openssl(1), +stunnel(8), pty(1), rlwrap(1), setsid(1) + +Socat() home page lurl(http://www.dest-unreach.org/socat/) + +label(AUTHOR) +manpageauthor() + +Gerhard Rieger diff --git a/doc/xio.help b/doc/xio.help new file mode 100644 index 0000000..937a93d --- /dev/null +++ b/doc/xio.help @@ -0,0 +1,4959 @@ +# $Id: xio.help,v 1.115 2007/03/06 20:57:34 gerhard Exp $ +# Copyright Gerhard Rieger 2001-2007 + +Operating systems: + +The options and features described in this document have been implemented (but +not always tested) on the operating systems listed below, unless otherwise +noted: + +SuSE 10.1 Linux on x86 +Solaris 8 on Sparc with gcc +FreeBSD 6.1 on x86 +HP-UX B 11.11 on PA-RISC with gcc + +=============================================================================== + +The following sections describe the syntax and semantics of the socat command +line stream arguments. + +Usually a socat stream argument defines a one- or bidirectional stream. There +are two principal forms: +* a single stream. Depending on use of the -u or -U options and implicit +semantics of the stream, such an argument may be resolved to a one- or +twodirectional stream. +* two onedirectional streams, separated by '!!'. An argument of this form +always specifies a twodirectional stream. The first single stream is only used +for reading data, and the second is only used for writing data. + + +The general structure of a single stream is: +keyword[:required-parameters][,options] + +The options part starts with the first ',' of the argument. The required +parameters are separated by ':' from their predecessor. The last required +parameter is terminated by the end of the argument or by the first ',' that +iitroduces the first option. The options are separated with ','. The last +option is terminated by end-of-string or by '!!'. + +The are some abbreviations defined that allow to drop the keyword. In these +cases the argument syntax is: +required-parameter[:required-parameters][,options] +The implemented abbreviations are: +short form canonical form +number FD:number # decimal number +path GOPEN:path # must must contain at least one '/' and must not contain ':' or ',' and must not start with a decimal digit + +=============================================================================== + + +Addresses: + +Every address specification starts with a keyword or an abbreviation. These +keywords are case insensitive. +Note: because the option group ANY applies for all addresses, it is not +mentioned explicitely below. + + +Bidirectional only addresses: +----------------------------- + +PIPE +FIFO +ECHO + +Opens an unnamed pipe (fifo) where outbound traffic is sent to and inbound +traffic is read from. The special semantics of pipes results in an echo like +behaviour. +Option groups: FD, FIFO (no specific FIFO options are defined yet) + + +Onedirectional only addresses: +------------------------------ + +Currently all addresses may be used bidirectional. +Note: for regular files, behaviour when being used bidirectionally is +undefined. + + +One- and bidirectional addresses: +--------------------------------- + +STDIO +- ("minus") + +Uses stdin (FD 0) for inbound traffic and/or stdout (FD 1) for outbound traffic +on this address. +Option groups: FD; others dependent on actual types of stdin and stdout (FIFO, +CHR, BLK, REG, and/or SOCKET). + + +STDIN + +Uses stdin for traffic. This might fail for outbound traffic. +Option groups: FD; dependent on actual type of stdin (FIFO, CHR, BLK, REG, or +SOCKET). + + +STDOUT + +Uses stdout for traffic. This might fail for inbound traffic. +Option groups: FD; dependent on actual type of stdout (FIFO, CHR, BLK, REG, or +SOCKET). + + +STDERR + +Uses stdout for traffic. This might fail for inbound traffic. +Option group: FD; dependent on actual types of sterr (FIFO, CHR, BLK, REG, or +SOCKET). + + +FD:num +num + +Uses the already existing file descriptor for traffic. +Option groups: FD; dependent on actual types of file descriptor (FIFO, CHR, +BLK, REG, or SOCKET). + + +READLINE + +Uses the GNU readline function and history capabilies (best known from bash). +It always works on stdin and stdout; if stdio is not a tty, readline does not +seem to work correctly. +Because readline is blocking during line editing, it does not fit well into +socats I/O philosophy. +socat integrates readline by waiting in the select call as usual; when stdin +reports available data, socat invokes readline(). readline blocks until the +user presses ENTER or EOF. Data on socats other stream is not handling in this +time. +socat controls the ECHO flag of the stdin tty (off during select(), on for +readline()). +When using socat with readline as front end to a service like telnet, POP3 or +an other authenticated service, please note that the password is entered as +ordinary data, thus appears on the screen! +Option groups: FD, READLINE, TERMIOS +Useful options: history-file + + +OPEN:path + +Applies an open() system call to the given path. If the path does not exist a +file is created only if the option create is used; if a file, pipe, or device +with this name already exists it is opened. Open for reading and/or writing +depends on the rw parameter of the xioopen call, or on usage in a socat +argument. If no perm option is used, xioopen uses 600 (which might be modified +by umask then). +Applying this function to files conforms to the semantics as described by the +open(2) man page. +Opening device files, like /dev/ttyS*, might block until the device gets active +(until some peer is connected) +With existing named pipes (fifos) please note the usual semantics: +Opening the pipe in read/write mode results in an echo service; +Opening the pipe in read mode blocks until a writer opens the pipe (close +by writer gives EOF for the reader); with option nonblock the open call does +not block. +Opening the pipe in write mode blocks until a reader opens the pipe (close +by reader gives "broken pipe" error on next write); with option nonblock the +open call terminates with error "no such device or address" in absence of a +reader. +Opening a named UNIX stream socket with or without a listening peer might +succeed depending on the operating system, but +the resulting file descriptor erronously reports available data immediately, +and the following read() or write() call always fails with "invalid +argument". Even worse, while such a filesystem entry is identified as socket by +"file" command and by fstat(), getsockopt() after open() gives error "Socket operation on non-socket". +Use GOPEN for reasonable behaviour! +Option groups: FD, OPEN, NAMED, and specific for data object type (FILE, FIFO, +CHRDEV+TERMIOS, BLKDEV, or SOCKET). + + +GOPEN:path +path + +"Generic open". Tries to open the given path in a smarter way. If the path +exists and is a socket, it is connected to; if connecting fails, +socat assumes a datagram socket and later uses sendto() calls for data +transfer. +If the path exists and is not a socket, it is opened: +in RDONLY environment for reading from position 0, +in WRONLY environment for appending (O_APPEND), +in RDWR env. for reading and/or writing starting from position 0. +If the path does not exist: +in RDONLY environment this is an error +in WRONLY environment the file is created (O_CREAT) +in RDWR env. for reading and/or writing starting from position 0. +However, these flags may be overriden by user supplied options +(e.g., "append=0") +Option groups: FD, NAMED, and specific for data object type (FILE, FIFO, +CHRDEV+TERMIOS, BLKDEV, or SOCKET). + + +CREATE:path +CREAT:path + +Opens the named file with creat(). With UNIX semantics, this address is just a +variation of the OPEN address, see there for more details. +Note: The creat() system call does not create a completely new file, but +inherits some properties of the old file if it exists, e.g. permissions. Use +option "unlink-early" to remove the old entry before. +Option groups: FD, NAMED, FILE +Useful options: unlink-late + + +PIPE:path +FIFO:path + +Creates and opens a pipe if path does not exist; opens path if it already +exists. +Option groups: FD, NAMED, FIFO +Note: this address uses the mknod(2) system call to create the named pipe. On +FreeBSD, this call requires root privilege + + +EXEC:cmdline + +Forks off a child process after establishing a bidirectional communication +channel (with socketpair, pipes, or pty). The child then starts "cmdline" with +execvp(). +Note: spaces and shell meta characters in cmdline must be quoted if socat is +invoked from the command line. +Option groups: FD, FORK, EXEC, SOCKET, SOCK_UNIX, FIFO, TERMIOS +Useful options: path, fdin, fdout, chroot, su, pty, stderr +Note: on AIX, search permissions on /dev/pts/ are required to use option pty. + + +SYSTEM:cmdline + +Forks off a child process after establishing a bidirectional communication +channel (with socketpair, pipes, or pty). The child then starts "cmdline" with +system(). +Note: spaces and shell meta characters in cmdline must be quoted if socat is +invoked from the command line. +Option groups: FD, FORK, EXEC, SOCKET, SOCK_UNIX, FIFO, TERMIOS +Useful options: path, fdin, fdout, chroot, su, pty, stderr +Note: there are slightly different semantics with options pty or pipes, because +they do not communicate an EOF condition to the shell process. Therefore, the +shell process and its child do not terminate due to EOF, but are explicitly +killed during close of the socat file handle. Consider using +exec:'/bin/sh -c command',pty... + + +UNIX:path +LOCAL:path + +Connects to a UNIX domain socket. +Option groups: FD, SOCKET, SOCK_UNIX +NOTE: you need rw permissions to connect to a local socket. My Linux answers +with "connection refused" to insufficient permissions, not existing +socket, not a socket, or just a socket entry without a listening process. +NOTE: this address does not implement option group NAMED because its connect +call succeeds only if there is already someone listening, but at this point the +NAMED group actions no longer affect this socket, only the fs entry. + + +UNIX-listen:path +UNIX-l:path + +Create a listening UNIX domain socket. With the fork option, for each accepted +connection a new process is forked off, and more connections are accepted on +the parent socket. Without fork, only the first connection is accepted. +Option groups: FD, NAMED, SOCKET, SOCK_UNIX, LISTEN, CHILD + + +IP:host:protocol +IP4:host:protocol + +Open a raw socket with IP4 protocol. This mode sends packets to and accepts +them only from host. protocol is a number from 0 to 255, with 1 meaning ICMP, +6..TCP, 17..UDP, 255..raw IP; 0 might be unsupported by the local IP stack, +resulting in an error. +Requires root privilege. +Note: my Linux 2.4.10 kernel seems to drop payloads smaller than 8 +bytes on their way from the network to the application. +Option groups: FD, SOCKET, SOCK_IP + + +TCP:host:port +TCP4:host:port +INET:host:port + +Create a TCP/IP4 client socket and connect to the given host/port combination. +Option groups: FD, SOCKET, SOCK_IP, IPAPP, IP_TCP +Useful options: crlf, bind, tos, mtudiscover, mss, nodelay, + + +TCP-l:port +TCP-listen:port +TCP4-l:port +TCP4-listen:port +INET-l:port +INET-listen:port + +Create a TCP/IP4 server socket and wait for an incoming connection. With the +fork option, for each accepted connection a new process is forked off, and more +connections are accepted on the parent socket. Without fork, only the first +connection is accepted. +Option groups: FD, SOCKET, SOCK_IP, IPAPP, IP_TCP, LISTEN, RANGE, CHILD +Useful options: fork, crlf, bind, backlog, mtu, tcpwrap + + +UDP:host:port +UDP-CONNECT:host:port + + Connects to port on host using UDP/IP version 4 or 6 + depending on address specification, name resolution, or option pf. + Please note that, + due to UDP protocol properties, no real connection is established; data has + to be sent for `connecting' to the server, and no end-of-file condition can + be transported. +Option groups: FD, SOCKET, SOCK_IP4, SOCK_IP6, IP_UDP +Useful options: ttl + +UDP4:host:port +UDP4-CONNECT:host:port + +Like UDP-CONNECT, but only supports IPv4 protocol. +Option groups: FD, SOCKET, SOCK_IP, IPAPP, IP_UDP + + +UDP-listen:port +UDP-l:port + +Emulates a UDP server in the same way as netcat: Create a UDP/IP4 socket and +bind to the given port. Then wait for the first packet, get its sender address +(without consuming its data), connect() to this address, and leave xioopen(). +Afterwards, our socket only communicates with this peer. +Option groups: FD, SOCKET, SOCK_IP, IPAPP, IP_UDP, RANGE +Note: with fork option, child processes might hang forever because UDP cannot +transport EOF conditions. + + +#UDP-dgram:port +#UDP-d:port +# +#Create and use a pure datagram oriented UDP socket. +#The following restrictions apply: +#* range option does not work +#* de facto this is a read-only endpoint: sending data to 0.0.0.0 might fail. + + +TCP6:host:port +INET6:host:port + +Create a TCP/IP6 client socket and connect to the given host/port combination. +Option groups: FD, SOCKET, SOCK_IP, IPAPP, IP_TCP +Note: Address syntax parsing is awkward, since the IPv6 address word separator +is ':' which is used as port separator too. +An FTP listen entry looks in netstat ":::21"! + + +TCP6-l:port +TCP6-listen:port +INET6-l:port +INET6-listen:port + +Create a TCP server socket and wait for an incoming connection. With the fork +option, for each accepted connection a new process is forked off, and more +connections are accepted on the parent socket. Without fork, only the first +connection is accepted. +Option groups: FD, SOCKET, SOCK_IP, IPAPP, IP_TCP, LISTEN, RANGE, CHILD + + +SOCKS4:sockd:host:port +SOCKS:sockd:host:port + +Use a socks server, socks protocol version 4, to build a TCP (IPv4) connection. +Sockd is the name or address of the socks server, host and port specify the +destination address. Use option socksport if the socks server does not listen +on port 1080. +Option groups: FD, SOCKET, SOCK_IP, IPAPP, IP_TCP, IP_SOCKS +Useful options: sp, socksport, socksuser +Note: If you do not specify option socksuser, xioopen tries to derive it from +environment: LOGNAME or USER, and might therefore undisclose your identity. + + +SOCKS4a:sockd:host:port + +Like SOCKS4, but use the socks version 4a extension for destination name +resolution on the socks server. +Option groups: FD, SOCKET, SOCK_IP, IPAPP, IP_TCP, IP_SOCKS + + +PTY + +Creates a pseudo terminal (pty) and uses its master side. Another process may +open the pty´s slave side using it like a serial line or terminal. +Option groups: FD,NAMED,PTY,TERMIOS +Useful options: link, openpty, mode, user, group + + +OPENSSL-CONNECT:host:port +OPENSSL:host:port + +Tries to establish a SSL connection to port on host using TCP/IPv4. +Note: this is currently only an experimental integration of openssl! +(it does not provide any trust between the peers because is does not check +certificates!) +Option groups: FD,SOCKET,SOCK_IP4,IP_TCP,OPENSSL,RETRY +Useful options: cipher, method, verify, cafile, capath, certificate, bind, sourceport, retry + + +OPENSSL-LISTEN:port + +Listens on tcp4 port. When a connection is accepted, this address behaves as +SSL server. +Option groups: FD,SOCKET,SOCK_IP4,TCP,LISTEN,CHILD,RANGE,OPENSSL,RETRY +Usefule options: cipher, method, verify, cafile, capath, certificate, retry + + +PROXY:proxy:host:port +PROXY-CONNECT:proxy:host:port + +Connects to an HTTP proxy server on port 8080 using TCP/IPv4, and sends a +CONNECT request for host:port. If the proxy grants access and succeeds to +connect to the target, data transfer between socat and the target can +start. Note that the traffic need not be HTTP but can be an arbitrary +protocol. +Option groups: FD,SOCKET,IP4,TCP,HTTP +Useful options: proxyport, ignorecr, proxyauth, crnl, bind, mss, sourceport + +=============================================================================== + +Option Groups: + +Each option is member of one option group. Address definitions specify which +option groups they support. This allows to reject unapplyable options in an +early stage of address processing. + +Address groups are identified by single bit positions. Option definitions +specify to which group the option belongs (some options are member or more than +one group). Addresses use a bit pattern to specify which option groups they +support. + +Currently the following option groups are defined: + +GROUP_FD: All addresses that result in one or more file descriptors. These +options are typically applied with fcntl() or some special calls like fchown() +or fchmod(). There is no documented restriction to apply these functions to any +file descriptor; but they are not always meaningful, and sometimes lead to OS +exceptions. + +GROUP_APPL: All addresses. The options do not need file descriptors, because +they manipulate the data streams at application level (ignoreeof, line +terminator conversion). + +GROUP_PROCESS: For options that change process related attributes, like user id +(setuid). + +GROUP_FIFO: Options for pipes. Currently not used. + +GROUP_CHR: Options for character devices. Currently not used. + +GROUP_BLK: Options for block devices. Currently not used. + +GROUP_REG, GROUP_FILE: Options for regular files. Currently not used. + +GROUP_SOCKET: Options for arbitrary type sockets, e.g. so-sndbuf, so-linger. + +GROUP_NAMED: Options for file system entries, e.g. user-early, unlink. + +GROUP_OPEN: Options that are applied with the open() system call. + +GROUP_EXEC: Options for program or script execution, e.g. path. + +GROUP_FORK: Options for communication with children processes, e.g. fdin, pty. + +GROUP_LISTEN: Options for listening sockets. Only backlog. + +GROUP_DEVICE: not used + +GROUP_CHILD: Options for addresses that may fork off independent child +processes. Currently only option fork. + +GROUP_RETRY: Options for failure handling. Currently not used. + +GROUP_TERMIOS: Options for terminal settings, e.g. echo, b38400, raw. + +GROUP_READLINE: Options for readline (GNU line editing and history). + +GROUP_RANGE: Options for checking peer address. Currently only range. + +GROUP_SOCK_UNIX: Options for UNIX domain sockets. Currently not used. + +GROUP_SOCK_IP4: Options for IP4 sockets. Currently not used. + +GROUP_SOCK_IP6: Options for IP6 sockets. Currently not used. + +GROUP_SOCK_IP: Options for IP sockets, e.g. mtu, ip-options, ttl. + +GROUP_IP_UDP: Options for UDP sockets. Currently not used. + +GROUP_IP_TCP: Options for TCP sockets, e.g. maxseg, nodelay. + +GROUP_IPAPP: Options for UDP and TCP sockets. Currently only sourceport. + +GROUP_IP_SOCKS4: Options for SOCKS client connections, e.g. socksuser. + +GROUP_PROCESS: Options for process wide attributes, e.g. su, chroot. + +GROUP_APPL: Options handled by application. Currently not used. + +GROUP_PTY: Options for pseudo terminals. Used with addresses PTY, EXEC, and +SYSTEM. + +GROUP_OPENSSL: Options for the OPENSSL address. + +There are "combined" group definitions too: +#define GROUP_ANY (GROUP_PROCESS|GROUP_APPL) +#define GROUP_ALL 0xffffffff + +=============================================================================== + +Address Options + +Address options are identified by a case insensitive keyword. If the options +needs a parameter value, the option syntax is always: +OPTION=VALUE +Currently there do not exist options that take more than one argument; +sometimes, two values are combined to form one argument value, e.g. IP4 address +and port: +192.168.0.1:80 + +Note: +"Type" describes the type of data that may or must be given to the option and +that is passed to the system. There are some options with boolean semantics +(on/off or yes/no), but their values are passed to the system with an int +parameter. This situation is indicated as "Logical type: bool" and "Physical +type: int". In this case xioopen passes the physical value to the system, +giving the user one more hacking playground. + + +Option: append + +Type: BOOL +Option group: FD +Phase: LATE +Platforms: all (UNIX98) + +Sets the O_APPEND flag via a fcntl() call and F_SETFL; with OPEN type +addresses, this flag is applied with the open() call. All data written is +appended to the actual file end, even if other processes have written to or +truncated the file in the meantime. + + +Option: async + +Type: BOOL +Option group: FD +Phase: LATE +Platforms: FreeBSD, Linux, SunOS + +Sets the O_ASYNC (or FASYNC) flag via a fcntl() call and F_SETFL; with FILE +addresses, this flag is applied with the open() call. Consult your kernel +documentation for effects of this flag. +NOTE: socat does not handle the SIGIO signal. + + +Option: cloexec + +Type: BOOL +Option group: FD +Phase: LATE +Platforms: all + +Sets the FD_CLOEXEC (close-on-exec) flag on the file descriptor via a +fcntl()call with F_SETFD. Use with caution, because xioopen() makes use of this +flag to archieve what we consider the most reasonable behaviour; using this +option overrides xioopen's setting! + + +Option: flock-ex +Aliases: flock, lock + +Type: BOOL +Option group: FD +Phase: FD +Platforms: FreeBSD, Linux + +Applies the flock(fd, LOCK_EX) call to the file descriptor(s). This locks a file +exclusively (but only for processes also using flock() on this file - otherwise, they seem to have unrestricted access). +If the file is already locked with flock, our flock call blocks until the other +processes lock is released. +Note: the "lock" option name alias applies to this option only + if the fcntl locking mechanism is not available on a platform. + + +Option: flock-ex-nb +Aliases: flock-nb + +Type: BOOL +Option group: FD +Phase: FD +Platforms: FreeBSD, Linux + +Applies the flock(fd, LOCK_EX|LOCK_NB) call to the file descriptor(s). This locks a file +exclusively (but only for processes also using flock() on this file - +otherwise, they seem to have unrestricted access). +If the file is already locked with flock, our flock call returns the error +"Resource temporarily unavailable". + + +Option: flock-sh + +Type: BOOL +Option group: FD +Phase: FD +Platforms: FreeBSD, Linux + +Applies a shared advisory lock to the file using the flock(fd, LOCK_SH) call. +This prevents processes from locking the file exclusively. +If the file has already an exclusive lock, our flock call blocks until the +other processes lock is released. + + +Option: flock-sh-nb + +Type: BOOL +Option group: FD +Phase: FD +Platforms: FreeBSD, Linux + +Applies a shared advisory lock to the file using the flock(fd, LOCK_SH|LOCK_NB) call. +This prevents processes from locking the file exclusively. +If the file has already an exclusive lock, our flock call returns with error +"Resource temporarily unavailable". + + +Option: f-setlk-rd +Aliases: setlk-rd + +Type: BOOL +Option group: FD +Phase: FD +Platforms: all + +Locks the complete file with fcntl(fd, F_SETLK, {F_RDLCK}) (complete means from its +start to its maximal length). This locks the file exclusively (but only if the +other processes accessing this file also use f-setlk or f-setlkw - otherwise, +they seem to have unrestricted access). If the file is already locked with +f-setlk or f-setlkw, the fcntl call blocks until release by the other process. + + +Option: f-setlk-wr +Aliases: f-setlk, setlk-wr, setlk + +Type: BOOL +Option group: FD +Phase: FD +Platforms: all + +Locks the complete file with fcntl(fd, F_SETLK, {F_WRLCK}) (complete means from its +start to its maximal length). This locks the file exclusively (but only if the +other processes accessing this file also use f-setlk or f-setlkw - otherwise, +they seem to have unrestricted access). If the file is already locked with +f-setlk or f-setlkw, the fcntl call blocks until release by the other process. + + +Option: f-setlkw-rd +Aliases: setlkw-rd + +Type: BOOL +Option group: FD +Phase: FD +Platforms: all + +Locks the complete file with fcntl(fd, F_SETLKW, {F_RDLCK}) (complete means from its +start to its maximal length). This locks the file exclusively (but only if the +other processes accessing this file also use f-setlk or f-setlkw - otherwise, +they seem to have unrestricted access). If the file is already locked with +f-setlk or f-setlkw, fcntl returns with EAGAIN. + + +Option: f-setlkw-wr +Aliases: setlkw-wr, f-setlkw, setlkw, lockw, lock + +Type: BOOL +Option group: FD +Phase: FD +Platforms: all + +Locks the complete file with fcntl(fd, F_SETLKW, {F_WRLCK}) (complete means from its +start to its maximal length). This locks the file exclusively (but only if the +other processes accessing this file also use f-setlk or f-setlkw - otherwise, +they seem to have unrestricted access). If the file is already locked with +f-setlk or f-setlkw, fcntl returns with EAGAIN. + + +Option: fork + +Type: BOOL +Option group: CHILD +Phase: PASTACCEPT +Platforms: all + +Without fork (or fork=0), the listening process accepts exactly one +connections, and terminates afterwards. With fork set, it forks off a new socat +child process for each incoming connection. +It is very important to understand what socat does with this fork option: +The parent process remains in a loop of accept() and fork() calls until +terminated from outside. The child process leaves this loop and goes on with +the socat processing. If the fork occurs in the first address argument, the +child process continues with parsing and activating the second address +argument. This will in most cases be what you want or expect. +If the fork call occurs in socats second address argument, all children will +inherit and share the already activated first address. + + +Option: group=value +Aliases: gid=value + +Type: GIDT or unsigned int +Option group: NAMED +Type: GIDT +Platforms: all + +Takes one argument, a UNIX group name or a numeric group id. The first +character of value is a digit for group ids. +With NAMED addresses this option is applied via a chown() call, with a +fchown() call otherwise. +If groupname is a name it must be a valid groupname from /etc/group and is +converted to a group id with a getgrnam(3) call. +On most modern operating systems, the owner of the process must be member of +the group being set; only root may set any group, even numbers without group +name. +A Linux 2.2.10 kernel SIGSEGVs the process in the fchown() call when this +option is used with a socket or pipe. Is fixed with Linux 2.4. +LINUXBUG TESTCASE: +SH1: socat -D - unix-l:/tmp/socket,unlink-early +SH2: socat -d -d -d -d -D gopen:/tmp/socket,group=floppy - + + +Option: group-late=value + +Type: GIDT or string +Option group: FD +Type: GIDT +Platforms: all + +Takes one argument, a UNIX group name or a numeric group id. The first +character of value is a digit for group ids. +This option is applied via a fchown(2) call. +If groupname is a name it must be a valid groupname from /etc/group and is +converted to a group id with a getgrnam(3) call. +On most modern operating systems, the owner of the process must be member of +the group being set; only root may set any group, even numberic group ids +without group name. + + +Option: o-nonblock +Aliases: nonblock + +Type: BOOL +Option group: FD +Phase: FD +Platforms: all (UNIX98) + +Sets the O_NONBLOCK flag of a file descriptor via a fcntl(2) call and F_SETFL; +with OPEN type addresses, this flag is applied with the open() call. +It does not change the behaviour of socat's data transfer loop because socat +uses select() which blocks nevertheless. +Currently is has only two documented uses: +1) With address TCP, the connect() call +does not block; instead, it continues through the open step. The channel is +passed to the select() call. If something is written to the channel before it +is connected, this is an error. If connection fails, a read condition occurs +and read() returns the error. +2) Opening a named pipe does not block with this option. + + +Option: o-ndelay +Aliases: ndelay + +Type: BOOL +Option group: FD +Phase: LATE +Platforms: HP-UX, SunOS (UNIX98) + +Under Solaris it sets the O_NDELAY of the file descriptor via a fcntl(2) call +and F_SETFL; with OPEN type addresses, this flag is applied with the open() +call. +With all other operating systems, this is just another name for the nonblock option. + + +Option: o-noatime +Aliases: noatime + +Type: BOOL +Option group: FD +Phase: FD +Platforms: Linux + +Sets the O_NOATIME flag of a file descriptor via a fcntl(2) call and F_SETFL; +with OPEN type addresses, this flag is applied with the open() call. +It prevents the access time from being updated during read operations. + + +Option: perm=value +Aliases: mode=value + +Type: MODET (mode_t) +Option group: NAMED +Phase: FD +Platforms: all + +This option changes the mode (permissions) of an addresses inode. xioopen +tries to apply this option already during open phase. If the address does not +have a open phase or if the option cannot be applied there, the value is +applied directly on the file descriptor afterwards. +It is up to you to (1) have the permission to change the permissions, and (2) +not to set permissions that prevent you from performing your transactions :-) +NOTE: At least with some Linux 2.2, setting permissions on an existing file or +device with fchmod() does not change the permissions of its inode on disk. See +perm-early which uses chmod() instead. +NOTE: At least with some Linux 2.2, restricting mode on file descriptors does +not restrict this file descriptors data transfer capabilities. + + +Option: perm-late=value + +Type: MODET (mode_t) +Option group: FD +Phase: LATE +Platforms: all + +This option changes the mode (permissions) of a file descriptor with fchown() +in the last phase of address processing. + + +Option: seek-set=offset +Aliases: lseek=offset, seek=offset + +Type: OFF32 or OFF64 +Option group: BLK +Phase: LATE +Platforms: HP-UX, Linux, SunOS + +Positions the file at the given absolute offset, using lseek() (or lseek64() if +available) with SEEK_SET. + + +Option: seek-cur=offset + +Type: OFF32 or OFF64 +Option group: BLK +Phase: LATE +Platforms: HP-UX, Linux, SunOS + +Positions the file at the given offset from the current position, +using lseek() (or lseek64() if available) with SEEK_SET. + + +Option: seek-end=offset + +Type: OFF32 or OFF64 +Option group: BLK +Phase: LATE +Platforms: HP-UX, Linux, SunOS + +Positions the file at the given offset from the file end, +using lseek() (or lseek64() if available) with SEEK_END. + + +Option: lseek32-set=offset +Aliases: lseek32=offset + +Type: OFF32 +Option group: BLK +Phase: LATE +Platforms: HP-UX, Linux, SunOS + +Positions the file at the given absolute offset using lseek() with SEEK_SET. +This call might fail for non +random access data objects like character devices or sockets. +NOTE: this option seems to be useless on files with O_APPEND set. + + +Option: lseek32-cur=offset + +Type: OFF32 (instead of off_t) +Option group: BLK +Phase: LATE +Platforms: HP-UX, Linux, SunOS + +Positions the file at the given offset from the current position using lseek() +with SEEK_CUR. This call +might fail for non random access data objects like character devices. +On Linux, the seek() call fails on pipes, sockets and ttys but works on files +and /dev/null +NOTE: this option seems to be useless on files with O_APPEND set. + + +Option: lseek32-end=offset + +Type: OFF32 +Option group: BLK +Phase: LATE +Platforms: HP-UX, Linux, SunOS + +Positions the file at the given offset from the file end using lseek() with +SEEK_END. This call might fail +for non random access data objects like character devices. +NOTE: this option seems to be useless on files with O_APPEND set. + + +Option: lseek64-set=offset +Aliases: lseek64=offset + +Type: OFF64 +Option group: BLK +Phase: LATE +Platforms: all + +Positions the file at the given absolute offset using lseek64() with SEEK_SET. +This call might fail for non +random access data objects like character devices or sockets. +NOTE: this option seems to be useless on files with O_APPEND set. + + +Option: lseek64-cur=offset + +Type: OFF64 +Option group: BLK +Phase: LATE +Platforms: all + +Positions the file at the given offset from the current position using +lseek64() with SEEK_CUR. This call +might fail for non random access data objects like character devices. +NOTE: this option seems to be useless on files with O_APPEND set. + + +Option: lseek64-end=offset + +Type: OFF64 +Option group: BLK +Phase: LATE +Platforms: all + +Positions the file at the given offset from the file end using lseek64() with +SEEK_END. This call might fail +for non random access data objects like character devices. +NOTE: this option seems to be useless on files with O_APPEND set. + + +Option: chroot=path + +Type: STRING +Option group: PROCESS +Phase: LATE +Platforms: all + +Invokes the chroot() system call with the given path after the address +resolution, so the path names of the address must be specified with absolute +pathes. +Note: when you combine chroot with substuser, with substuser applied within the +chroot environment, usually the etc/passwd and etc/group files in the chroot +environment are used for group set etc. +See appendix "generating a sandbox" + + +Option: chroot-early=path + +Type: STRING +Option group: PROCESS +Phase: EARLY +Platforms: all + +Invokes the chroot() system call with the given path before the address is +resolved, this means before file opening in OPEN, GOPEN and before program +execution in EXEC and SYSTEM, so their pathes must be specified related to +their chroot directory. +See appendix "generating a sandbox" + + +Option: setgid=group + +Type: GIDT (gid_t or string) +Option group: PROCESS +Phase: LATE2 +Platforms: all + +Invokes setgid() with the group id. For EXEC and SYSTEM this call is performed +for the child process after the fork and therefore does not affect the socat +process directly. For LISTEN group addresses with fork option, this call is +performed only on the child processes. For all other addresses, it is performed +in the late phase of address processing, so it does not affect the address +where it is used, but for the next address (if any), and for the data loop. +Note: setgid() does not remove any groups from the current process group set. + + +Option: setuid=user + +Type: UIDT (uid_t or string) +Option group: PROCESS +Phase: LATE2 +Platforms: all + +Invokes setuid() with the user id. For EXEC and SYSTEM this call is performed +for the child process after the fork and therefore does not affect the socat +process directly. For LISTEN group addresses with fork option, this call is +performed only on the child processes. For all other addresses, it is performed +in the late phase of address processing, so it does not affect the address +where it is used, but the next address (if any), and the data loop. +Note: setuid() is invoked AFTER setgid(), if both are applied. +Note: setuid() does not influence the processes group set; in most cases, you +want to prefer substuser option. + + +Option: substuser=user +Aliases: su=user + +Type: UIDT (uid_t or string) +Option group: PROCESS +Phase: LATE2 +Platforms: all + +Tries to switch the process to the given user and its group set. +To make sure that the groups are set correctly for the new process owner, the +system calls initgroups(), setgid(), and setuid() are invoked with the +appropriate arguments. +On sane operating system, this option requires root privileges. +Note: this option sets the user and group ids of the process, but does not +change the environment; therefore, all variables including $USER, $HOME, +$LOGNAME, $SHELL etc. are inherited from the old users environment. +Note: starting a SETUID program after applying substuser or setuid gives the +process the SETUID owner, which might give root privileges again. + + +Option: substuser-delayed=user +Aliases: su-d=user + +Type: UIDT (unsigned int or string) +Option group: PROCESS +Phase: INIT +Platforms: all + +Like substuser, but reads the user and group information in an early phase of +address processing, but applies the appropriate system calls in a late +phase. This allows to use user information from the host in a chroot +environment, without exposing this data within the sandbox. + + +Option: o-trunc +Aliases: trunc + +Type: BOOL +Option group: OPEN +Phase: LATE +Platforms: all + +Sets the O_TRUNC flag of the open() call, thus truncating the file to zero +length. +#! block devices? + + +Option: ftruncate=value +Aliases: truncate=value + +Type: OFF32 or OFF64 +Option group: REG +Phase: LATE +Platforms: HP-UX, Linux, SunOS + +Invokes the ftruncate() (or ftruncate64() if available) call for the file descriptor with the given value, +thus reducing the length of the file to the given length. +On Linux, ftruncate() fails on sockets and devices but works on regular files +and pipes. +#! block devices? +Note: AIX docu says: for regular files only + + +Option: ftruncate32=value + +Type: OFF32 +Option group: REG +Phase: LATE +Platforms: HP-UX, Linux, SunOS + +Invokes the ftruncate() call (even if ftruncate64() is available) call for the file descriptor with the given value, +thus reducing the length of the file to the given length. + + +Option: ftruncate64=value + +Type: OFF64 +Option group: REG +Phase: LATE +Platforms: all + +Invokes the ftruncate64() call if available, for the file descriptor with the given value, +thus reducing the length of the file to the given length. + + +Option: o-binary +Aliases: binary, bin + +Type: BOOL +Option group: FD +Phase: OPEN +Platforms: none; Cygwin + +Sets the O_BINARY flag with open() or fcntl() to avoid implicit line terminator conversions. + + +Option: o-text +Aliases: text + +Type: BOOL +Option group: FD +Phase: OPEN +Platforms: none; Cygwin + +Sets the O_TEXT flag with open() or fcntl() to force implicit line terminator conversions. + + +Option: o-noinherit +Aliases: noinherit + +Type: BOOL +Option group: FD +Phase: OPEN +Platforms: none; Cygwin + +Sets the O_NOINHERIT flag with open() or fcntl() to not keep this file open in a spawned process. + + +Option: cool-write +Aliases: coolwrite + +Type: BOOL +Option group: FD +Phase: INIT +Platforms: all + + Takes it easy when write fails with EPIPE or ECONNRESET and logs the message + with notice level instead of error. + This prevents the log file from being filled with useless error messages + when socat is used as a high volume server or proxy where clients often + abort the connection. + This option is experimental. + + +Option: end-close +Aliases: close + +Type: CONST +Option group: FD +Phase: INIT +Platforms: all + + Changes the (address dependent) method to close a connection to just close + the file descriptors. This is useful when the connection is to be reused by + or shared with other processes. + Normally, socket connections will be ended with shutdown(2) which + terminates the socket even if it is shared by multiple processes. + close(2) "unlinks" the socket from the process but keeps it active as + long as there are still links from other processes. + Similarly, when an address of type EXEC or SYSTEM is ended, socat usually + will explicitely kill the sub process. With this option, it will just close + the file descriptors. + + +Option: user=value +Aliases: owner=value, uid=value + +Type: UIDT (unsigned int or string) +Option group: NAMED +Phase: FD +Platforms: all + +Takes one argument, a UNIX user name or a numeric user id. The first +character of value is a digit for user ids. +For NAMED addresses, if the file already exists, this option is applied via a +chown() call, with fchown() for all other cases. +If username is a name it must be a valid username from /etc/passwd and is +converted to a user id with a getpwnam() call. +On sane operating systems, the owner of the process must be root to change +the owner of a file descriptor; root may even apply undefined (unnamed) user +ids. +My Linux 2.2 kernel SIGSEGVs the process in the fchown() call when this +option is used with a (UNIX, unconnected or connected) socket or pipe. Linux +2.4.0 handles this call correctly. +TESTCASE: ./socat -d -d -d -d - tcp:loopback:21,user=root + + +Option: user-late=value +Aliases: uid-l=value + +Type: UIDT (unsigned int or string) +Option group: FD +Phase: LATE +Platforms: all + +Takes one argument, a UNIX user name or a numeric user id. The first +character of value is a digit for user ids. +This option is applied via a fchown() call just before xioopen_single() +terminates. +If username is a name it must be a valid username from /etc/passwd and is +converted to a user id with a getpwnam() call. +On sane operating systems, the owner of the process must be root to change +the owner of a file descriptor; root may even apply undefined (unnamed) user +ids. +My Linux 2.2 kernel SIGSEGVs the process in the fchown() call when this +option is used with a socket or pipe. + + +=============================================================================== +OPEN group options +Options of this group may be used with all addresses that support OPEN group +options. + + +Option: o-rdonly +Aliases: rdonly + +Type: BOOL (inherent - no value) +Option group: OPEN +Phase: OPEN +Platforms: all + +Use O_RDONLY with the open() call instead of the position dependend default. +Take care not to block later write operations. + + +Option: o-wronly +Aliases: wronly + +Type: BOOL (inherent - no value) +Option group: OPEN +Phase: OPEN +Platforms: all + +Use O_WRONLY with the open() call instead of the position dependend default. +Take care not to block later write operations. + + +Option: o-rdwr +Aliases: rdwr + +Type: BOOL (inherent - no value) +Option group: OPEN +Phase: OPEN +Platforms: all + +Use O_RDWR with the open() call instead of the position dependend default. + + +Option: o-create +Aliases: create, creat + +Type: BOOL +Option group: OPEN +Phase: OPEN +Platforms: all + +Sets the O_CREAT flag of the open() call. This means that it is not an error if +the file does not exist. + + +Option: o-defer +Aliases: defer + +Type: BOOL +Option group: OPEN +Phase: OPEN +Platforms: none + +Sets the O_DEFER flag of the open() call. This means that write data is stored +in paging space until an fsync() call. + + +Option: o-delay +Aliases: delay + +Type: BOOL +Option group: OPEN +Phase: OPEN +Platforms: none + +Sets the O_DELAY flag of the open() call. This lets open block until the share +conditions are fulfilled (see nshare, rshare) + + +Option: o-direct +Aliases: direct + +Type: BOOL +Option group: OPEN +Phase: OPEN +Platforms: FreeBSD, HP-UX, Linux + +Sets the O_DIRECT flag of the open() call. + + +Option: o-directory +Aliases: directory + +Type: BOOL +Option group: OPEN +Phase: OPEN +Platforms: Linux + +Sets the O_DIRECTORY flag of the open() call. This lets open fail if the given +path is not a directory. This does not seem to be useful with socat. + + +Option: o-dsync +Aliases: dsync + +Type: BOOL +Option group: OPEN +Phase: OPEN +Platforms: HP-UX, Linux, SunOS (UNIX98) + +Sets the O_DSYNC flag with the open() call. This lets write() calls wait until +modification metainfo is physically written to media. + + +Option: o-excl +Aliases: excl + +Type: BOOL +Option group: OPEN +Phase: OPEN +Platforms: all + +Sets the O_EXCL flag of the open() call. + + +Option: o-largefile +Aliases: largefile + +Type: BOOL +Option group: OPEN +Phase: OPEN +Platforms: HP-UX, Linux, SunOS + +Sets the O_LARGEFILE flag of the open() flag. + + +Option: o-noctty +Aliases: noctty + +Type: BOOL +Option group: OPEN +Phase: OPEN +Platforms: all + +Sets the O_NOCTTY flag of the open() call, so the opened device does not become +the controlling tty of the process. + + +Option: o-nofollow +Aliases: nofollow + +Type: BOOL +Option group: OPEN +Phase: OPEN +Platforms: FreeBSD, Linux + +Sets the O_NOFOLLOW flag of the open() call. This means that the last component +of the open path must no be a symlink. + + +Option: o-sync +Aliases: sync + +Type: BOOL +Option group: OPEN +Phase: OPEN +Platforms: all (UNIX98) + +Sets the O_SYNC flag with the open() call. This lets write() calls wait until +data is physically written to media. + + +Option: o-rshare +Aliases: rshare + +Type: BOOL +Option group: OPEN +Phase: OPEN +Platforms: none + +Sets the O_RSHARE flag of the open() call. This means that the file must not be +opened for writing by other processes ("read sharing"). + + +Option: o-nshare +Aliases: nshare + +Type: BOOL +Option group: OPEN +Phase: OPEN +Platforms: none + +Sets the O_NSHARE flag of the open() call. This means that the file must not be +shared with other processes ("no sharing"). + + +Option: o-rsync +Aliases: rsync + +Type: BOOL +Option group: OPEN +Phase: OPEN +Platforms: HP-UX, Linux, SunOS (UNIX98) + +Sets the O_RSYNC flag with the open() call. This lets write() calls wait until +read metainfo is physically written to media. + + +Option: o-priv +Aliases: priv + +Type: BOOL +Option group: OPEN +Phase: OPEN +Platforms: none (Solaris) + +Sets the O_PRIV flag with the open() call. + +=============================================================================== +NAMED group options +This group is valid for all addresses that refer to a file system entry like +file, device, named pipe, or named UNIX domain socket. + + +Option: unlink-early +Aliases: new + +Type: BOOL +Option group: NAMED +Phase: EARLY +Platforms: all + +This options tries to remove the filesystem entry given in the address before +starting any other processing (even before user-early, perm-early, or +group-early). unlink() is called; note that this call, in contrast to rm(1), +removes entries regardless of their permissions. Instead, ownership or root +privileges and write permissions in the directory are required and sufficient. + + +Option: unlink + +Type: BOOL +Option group: NAMED +Phase: PREOPEN +Platforms: all + +This options tries to remove the filesystem entry given in the address before +it is tried to open, but past user-early, perm-early, or group-early). +unlink() is called; note that this call, in contrast to rm(1), removes entries +regardless of their permissions. Instead, ownership or root privileges and +write permissions in the directory are required and sufficient. + + +Option: unlink-late + +Type: BOOL +Option group: NAMED +Phase: PASTOPEN +Platforms: all + +This option tries to remove the filesystem entry after it has been opened. +Options can still be applied to the file descriptor, and +the node or files data can be used, but it can no longer be accessed by other +processes (except by tricks?), and after closing the stream the data or node is +completely removed. +unlink() is called; note that this call, in contrast to rm(1), removes entries +regardless of their permissions. Instead, ownership or root privileges and +write permissions in the directory are required and sufficient. + + +Option: perm-early=value + +Type: MODET (mode_t) +Option group: NAMED +Phase: PREOPEN +Platforms: all + +This option changes the mode (permissions) of an already existing filesystem +entry with chown() before the file is opened or after the UNIX domain socket is +bound, but before it listens/connects. + + +Option: user-early=value +Aliases: uid-e=value + +Type: UIDT (unsigned int or string) +Option group: NAMED +Phase: PREOPEN +Platforms: all + +Takes one argument, a UNIX user name or a numeric user id. The first +character of value is a digit for user ids. +This option is applied via a chown() call before the file system entry is +opened or after the UNIX domain socket is bound, but before it starts to +listen/connect. +If username is a name it must be a valid username from /etc/passwd and is +converted to a user id with a getpwnam() call. +On sane operating systems, the owner of the process must be root to change +the owner of a file descriptor; root may even apply undefined (unnamed) user +ids. + + +Option: group-early=value +Aliases: gid-e=value + +Type: GIDT (unsigned int or string) +Option group: NAMED +Phase: PREOPEN +Platforms: all + +Takes one argument, a UNIX group name or a numeric group id. The first +character of value is a digit for group ids. +This option is applied via a chown() call before the file system entry is +opened or after the UNIX domain socket is bound, but before it +listens/connects. +If groupname is a name it must be a valid groupname from /etc/group and is +converted to a group id with a getgrnam() call. +On most modern operating systems, the owner of the process must be member of +the group being set; only root may set any group, even numbers without group +name. + + +Option: umask=value + +Type: MODET +Option group: NAMED +Phase: EARLY +Platforms: all + +Sets the umask before opening a file or creating a UNIX domain socket. This is +especially useful for these sockets, because there interface does not provide a +mode argument. + + +Option: unlink-close + +Type: BOOL +Option group: NAMED +Phase: LATE +Platforms: all + +Remove the addresses file system entry when closing the address. +For named pipes, listening unix domain sockets, and the symbolic links of pty +addresses, the default is 1; for created files, opened files, generic opened +files, and client unix domain sockets the default is 0. + + +=============================================================================== +FORK and EXEC options + +Option: path=string + +Type: STRING +Option group: EXEC +Phase: PREEXEC +Platforms: all + +Changes the PATH environment variable in the child process before the exec() or +system() call. + + +Option: nofork + +Type: BOOL +Option group: FORK +Phase: BIGEN +Platforms: all + +Does not fork a subprocess for executing the program, instead calls execvp() +directly from the actual socat instance. This avoids the overhead of another process +between the program and the communication peer, but introduces lots of +restrictions: + * this option can only be applied to the second socat() address. + * the first socat address cannot be OPENSSL or READLINE + * socat options -b, -t, -D, -l, -v, -x, -t become useless + * for both addresses, options ignoreeof, cr and crnl become useless + * for the second address (the one with option nofork), options + append, async, cloexec, flock, user, group, mode, nonblock, + perm-late, setlk, and setpgid cannot be applied, and should be used on the + first address instead. + + +Option: pipes + +Type: BOOL +Option group: FORK +Phase: BIGEN +Platforms: all + +For communication between the exec() or system() subprocess with socat, use two +unnamed pipes instead of creating a socket pair. + + +Option: pty + +Type: BOOL +Option group: FORK +Phase: BIGEN +Platforms: all + +For communication between the exec() or system() subprocess with socat, use a +pseudo terminal instead of a socket pair. The executed program gets the slave +side, and socat the controlling side of the pseudo terminal. +This is especially useful if you want to use, e.g., chat with socat (see +EXAMPLES). Plus, ptys do not buffer I/O. +Note: implementation of pseudo terminals are differing between platforms, so +extra porting struggles might be required for porting this feature. + + +Option: fdin=num + +Type: USHORT +Option group: FORK +Phase: PASTBIGEN +Platforms: all + +After forking the child process, assign the stream where the child +receives data from socat, to file descriptor num instead of stdin. + + +Option: fdout=num + +Type: USHORT +Option group: FORK +Phase: PASTBIGEN +Platforms: all + +After forking the child process, assign the stream where the child +writes data to socat, to file descriptor num instead of stdout. + + +Option: stderr + +Type: BOOL +Option group: FORK +Phase: PASTFORK +Platforms: all + +Normally, the stderr filedescriptor of the forked program is a clone of socat's +stderr fd. If this option is used, the programs stderr filedescriptor is a copy +of the "normal" data output of the program, i.e. of its stdout or fdout. + + +Option: setsid +Aliases: sid + +Type: BOOL +Option group: PROCESS +Phase: LATE +Platforms: all + +Invokes setsid() to make the forked off subprocess the leader of a new +session. This also generates a new process group with this process as leader. +This is useful, e.g., when exec'ing ssh to get the password prompt into the I/O +channel (see EXAMPLES) + + +Option: setpgid +Aliases: pgid + +Type: INT +Option group: FORK +Phase: LATE +Platforms: all + +Invokes setpgid(0, val) from the child process. + + +Option: tiocsctty +Aliases: ctty + +Type: BOOL +Option group: TERMIOS +Phase: LATE2 +Platforms: all + +Applies only in combination with the pty option or its variants. Tries to make +the pty the controlling terminal. May require option setsid to work correctly. + + +Option: dash +Aliases: login + +Type: BOOL +Option group: EXEC +Phase: PREEXEC +Platforms: all + +Prefixes argv[0] for the execvp() call with '-', thus making a shell behave as +login shell. + + +Option: sighup + +Type: CONST +Option group: PARENT +Phase: LATE +Platforms: all + + Has socat pass an eventual SIGHUP signal to the sub process. + If no address has this option, socat terminates on SIGHUP. + + +Option: sigint + +Type: CONST +Option group: PARENT +Phase: LATE +Platforms: all + + Has socat pass an eventual SIGINT signal to the sub process. + If no address has this option, socat terminates on SIGINT. + + +Option: sigquit + +Type: CONST +Option group: PARENT +Phase: LATE +Platforms: all + + Has socat pass an eventual SIGQUIT signal to the sub process. + If no address has this option, socat dumps core and terminates on SIGQUIT. + + +=============================================================================== +PTY options +These options may be used with addresses that create a pseudo terminal (pty). +In particular, these are addresses EXEC, SYSTEM, and PTY. + + +Option: openpty + +Type: BOOL +Option group: PTY +Phase: BIGEN +Platforms: FreeBSD, Linux + +Like pty, but only use the openpty mechanism, not any other way for pty +generation. + + +Option: ptmx + +Type: BOOL +Option group: PTY +Phase: BIGEN +Platforms: HP-UX, Linux, SunOS + +Like pty, but only use the /dev/ptmx (/dev/ptc on AIX) mechanism, not any other +way for pty generation. + + +Option: symbolic-link=filename + +Type: FILENAME +Option group: PTY +Phase: LATE +Platforms: all + +Generates a symbolic link that points to the actual pseudo terminal (pty). This +might help to solve the problem that ptys are generated with more or less +unpredictable names, making it difficult to directly access the socat generated +pty automatically. With this option, the user can specify a "fix" point in the +file hierarchy that helps him to access the actual pty. + + +Option: pty-wait-slave +Aliases: wait-slave, waitslave + +Type: BOOL +Option group: PTY +Phase: EARLY +Platforms: all + + Blocks the open phase until a process opens the slave side of the pty. + Usually, socat continues after generating the pty with opening the next + address or with entering the transfer engine. With the wait-slave option, + socat waits until some process opens the slave side of the pty before + continuing. + This option only works if the operating system provides the tt(poll()) + system call. And it depends on an undocumented behaviour of pty's, so it + does not work on all operating systems. It has successfully been tested on + Linux, FreeBSD, NetBSD, and on Tru64 with openpty. + + +Option: pty-intervall + +Type: TIMESPEC +Option group: PTY +Phase: EARLY +Platforms: all + + When the wait-slave option is set, socat periodically checks the HUP + condition using poll() to find if the pty's slave side has been + opened. The default + polling intervall is 1s. Use the pty-intervall option to change this value. + + +=============================================================================== +SOCKET options +These are options that may be applied to all socket type addresses: UNIX +(LOCAL) domain sockets (even with EXEC type addresses if not pipes), IP, and +IPv6. + + +Option: so-debug +Aliases: debug + +Logical type: bool +Physical type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: all (UNIX98) + +Sets the SO_DEBUG socket option. Requires root. + + +Option: so-acceptconn +Aliases: acceptconn + +Logical type: bool +Physical type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: all (UNIX98) + +Tries to set the SO_ACCEPTCONN socket option. Read-only! + + +Option: so-broadcast +Aliases: broadcast + +Logical type: bool +Physical type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: all (UNIX98) + +Sets the SO_BROADCAST socket option. + + +Option: so-reuseaddr +Aliases: reuseaddr + +Logical type: bool +Physical type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: all (UNIX98) + +Sets the SO_REUSEADDR socket option. Allows to bind to a port even if this +port is already used for a connection. + + +Option: so-keepalive +Aliases: keepalive + +Logical type: bool +Physical type: INT +Option group: SOCKET +Phase: FD +Platforms: all (UNIX98) + +Sets the SO_KEEPALIVE socket option. + + +Option: so-linger=value +Aliases: linger=value + +Type: LINGER +Option group: SOCKET +Phase: PASTSOCKET +Platforms: all (UNIX98) + +Activates the SO_LINGER option and sets a value (seconds) for it. +This lets shutdown() or close() block until data transfers have finished or the +given value timed out. +Note: on some systems, the type for setsockopt() is struct { int; int; } +In this case, xioopen() sets {1,value}. + + +Option: so-oobinline +Aliases: oobinline + +Logical type: bool +Physical type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: all (UNIX98) + +Sets the SO_OOBINLINE socket option. + + +Option: so-sndbuf=value +Aliases: sndbuf=value + +Type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: all (UNIX98) + +Sets the SO_SNDBUF option of the socket to the given value. This option is +applied after the socket() (or socketpair()) call. +NOTE: The kernel might change the effective value: +My Linux 2.2 with TCP doubles the value, but uses at least 2048. + + +Option: so-sndbuf-late=value +Aliases: sndbuf-late=value + +Type: INT +Option group: SOCKET +Phase: LATE +Platforms: all (UNIX98) + +Sets the SO_SNDBUF option of the socket to the given value. This option is +applied after the connect() or accept() (or socketpair) call. +NOTE: The kernel might change the effective value: +My Linux 2.2 with TCP doubles the value, but uses at least 2048, and a +maximum of 131070 (system limit?). + + +Option: so-rcvbuf=value +Aliases: rcvbuf=value + +Type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: all (UNIX98) + +Sets the SO_RCVBUF option of the socket to the given value. This option is +applied after the socket() call. +NOTE: The kernel might change the effective value: +My Linux 2.2 with TCP connect doubles the value, but uses at least 256 and +at most 131070. +My Linux 2.2 with TCP listen doubles the value but uses at least 11772. +NOTE: For applying the SO_RCVBUF options after the connect() or accept() calls +see rcvbuf-late. + + +Option: so-rcvbuf-late=value +Aliases: rcvbuf-late=value + +Type: INT +Option group: SOCKET +Phase: LATE +Platforms: all (UNIX98) + +Sets the SO_RCVBUF option of the socket to the given value. This option is +applied after the connect() or listen() call. +NOTE: The kernel might change the effective value: +My Linux 2.2 with TCP doubles the value, but uses at least 256 and maximal +131070. +NOTE: sequence of this call may be relevant for the effecting value (AIX +4.3.3). For applying the SO_RCVBUF option immediately after the socket() call +see rcvbuf. + + +Option: so-error +Aliases: error + +Logical type: bool +Physical type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: all (UNIX98) + +Tries to set the SO_ERROR socket option which is a read-only option. +On my Linux 2.2 it gives "protocol not available". + + +Option: so-type=value +Aliases: type=value + +Type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: all + +Set the sockettype argument of the socket() or socketpair() call. This +overrides the per +protocol default (e.g., TCP: SOCK_STREAM). Most values might +not be supported by a given protocol. +The following combinations are known to work at least under one OS: +TCP SOCK_STREAM (system default) +UDP SOCK_DGRAM (system default) +IP SOCK_RAW (socat default) +UNIX SOCK_STREAM (system default) +UNIX SOCK_DGRAM + + +Option: so-dontroute +Aliases: dontroute + +Logical type: bool +Physical type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: all (UNIX98) + +Sets the SO_DONTROUTE socket option. + + +Option: so-rcvlowat=value +Aliases: rcvlowat=value + +Type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: all (UNIX98) + +Sets the SO_RCVLOWAT socket option. Cannot be changed in Linux (always +gives "protocol not available"). + + +Option: so-rcvtimeo=value +Aliases: rcvtimeo=value + +Provided type: double +Physical type: TIMEVAL (long[2]) +Option group: SOCKET +Phase: PASTSOCKET +Platforms: all (UNIX98) + +Sets the SO_RCVTIMOE socket option. Cannot be changed in Linux (always +gives "protocol not available"). + + +Option: so-sndlowat=value +Aliases: sndlowat=value + +Type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: all (UNIX98) + +Sets the SO_SNDLOWAT socket option. Cannot be changed in Linux (always +gives "protocol not available"). + + +Option: so-sndtimeo=value +Aliases: sndtimeo=value + +Provided type: double +Physical type: TIMEVAL (long[2]) +Option group: SOCKET +Phase: PASTSOCKET +Platforms: all (UNIX98) + +Sets the SO_SNDTIMEO socket option. Cannot be changed in Linux (always +gives "protocol not available"). + + +Option: so-audit +Aliases: audit + +Type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: none + +Sets the SO_AUDIT socket option. + + +Option: so-attach-filter +Aliases: attach-filter, attachfilter + +Type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: Linux + +Linux docu recommends to use libpcap for this feature. +"protocol not available", need kernel CONFIG_FILTER! + + +Option: so-detach-filter +Aliases: detach-filter, detachfilter + +Type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: Linux + +See Linux "man 7 socket". +"protocol not available", need kernel CONFIG_FILTER! + + +Option: so-bindtodevice=string +Aliases: bindtodevice, interface, if + +Type: NAME +Option group: SOCKET +Phase: PASTSOCKET +Platforms: Linux + +Binds the socket to a net interface, e.g. lo0 or eth0 (interface names depend +on operating system). Might require root privilege. + + +Option: so-bsdcompat +Aliases: bsdcompat + +Logical type: bool +Physical type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: none + +Sets the SO_BSDCOMPAT socket option. See Linux "man 7 socket". + + +Option: so-cksumrecv +Aliases: cksumrecv + +Logical type: bool +Physical type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: none + +Sets the SO_CKSUMRECV socket option. + + +Option: so-kernaccept +Aliases: kernaccept + +Logical type: bool +Physical type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: none + +Sets the SO_KERNACCEPT socket option. + + +Option: so-no-check +Aliases: no-check, nocheck + +Logical type: bool +Physical type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: Linux + +Sets the SO_NO_CHECK socket option." Intentionally undocumented" under +Linux (see "man 7 socket"), don't know what it does.... + + +Option: so-noreuseaddr +Aliases: noreuseaddr + +Type: INT? +Option group: SOCKET +Phase: PASTSOCKET +Platforms: none + +Sets the SO_NOREUSEADDR socket option. + + +Option: passcred +Aliases: so-passcred + +Type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: Linux + +Sets the SO_PASSCRED option of a socket. + + +Option: so-peercred +Aliases: peercred + +Type: INT3 or int[3]? +Option group: SOCKET +Phase: PASTSOCKET +Platforms: Linux + +Enables receiving of credentials. Read only. +Not really implemented yet. +Nevertheless, Gives "Protocol not available". + + +Option: so-priority=value +Aliases: priority=value + +Type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: Linux + +Sets the protocol defined priority for all packets to be sent on this socket. +Docu says it requires root privileges. Normal user may set 0..6 for UNIX domain +and TCP client sockets on Linux 2.2. root may send any int value. + + +Option: so-reuseport +Aliases: reuseport + +Type: INT? +Option group: SOCKET +Phase: PASTSOCKET +Platforms: FreeBSD, HP-UX + +Sets the SO_REUSEPORT socket option. + + +Option: so-security-authentication +Aliases: security-authentication, securityauthentication + +Type: INT? +Option group: SOCKET +Phase: PASTSOCKET +Platforms: Linux + +Sets the SO_SECURITY_AUTHENTICATION socket option. Gives "protocol not +available" error. +In Linux 2.2.16 source, only exists in asm-*/socket.h + + +Option: so-security-encryption-network +Aliases: security-encryption-network, securityencryptionnetwork + +Type: INT? +Option group: SOCKET +Phase: PASTSOCKET +Platforms: Linux + +Sets the SO_SECURITY_ENCRYPTION_NETWORK option of the socket. Gives "protocol +not available" error. +In Linux 2.2.16 source, only exists in asm-*/socket.h + + +Option: so-security-encryption-transport +Aliases: security-encryption-transport, securityencryptiontransport + +Type: INT? +Option group: SOCKET +Phase: PASTSOCKET +Platforms: Linux + +Sets the SO_SECURITY_ENCRYPTION_TRANSPORT option of the socket. Gives "protocol +not available" error. +In Linux 2.2.16 source, only exists in asm-*/socket.h + + +Option: so-use-ifbufs +Aliases: use-ifbufs, useifbufs + +Type: INT? +Option group: SOCKET +Phase: PASTSOCKET +Platforms: none + +Sets the SO_USE_IFBUFS socket option. + + +Option: so-useloopback +Aliases: useloopback + +Type: INT? +Option group: SOCKET +Phase: PASTSOCKET +Platforms: FreeBSD, HP-UX, SunOS + +Sets the SO_USELOOPBACK socket option. + + +Option: so-dgram-errind +Aliases: dgram-errind, dgramerrind + +Logical type: bool? +Physical type: INT? +Option group: SOCKET +Phase: PASTSOCKET +Platforms: SunOS + +Sets the SO_DGRAM_ERRIND flag. + + +Option: so-dontlinger +Aliases: dontlinger + +Type: INT? +Option group: SOCKET +Phase: PASTSOCKET +Platforms: SunOS + +Sets the SO_DONTLINGER socket option. + + +Option: so-prototype +Aliases: prototype + +Type: INT? +Option group: SOCKET +Phase: PASTSOCKET +Platforms: HP-UX, SunOS + +Sets the SO_PROTOTYPE socket option. + + +Option: type + +Type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: all + +Sets the type of the socket, usually as argument to the socket() or +socketpair() call, to . Under Linux, 1 means stream oriented socket, 2 +means datagram socket, and 3 means raw socket. + + +Option: protocol-family +Aliases: pf + +Type: STRING +Option group: SOCKET +Phase: PRESOCKET +Platforms: all + +Forces the use of the specified IP version. can be something like +"ip4" or "ip6". + + +Option: fiosetown + +Logical type: bool +Physical type: INT +Option group: SOCKET +Phase: PASTSOCKET +Platforms: FreeBSD, Linux + +Sets the FIOSETOWN ioctl (in "man 7 socket" called FIOCSETOWN). + + +#Option: ciocspgrp +# +#Allowed in addresses: SOCKET +#Logical type: bool +#Physical type: int +# +#Sets the CIOCSPGRP ioctl. + + +#Option: addr=value +# +#Allowed in addresses: SOCKET +#Type: socket-address +# +#For client socket, sets the local (bind) address. Not yet implemented. + + +Option: bind=socketaddress + +Type: STRING +Option group: SOCKET +Phase: BIND +Platforms: all + +Gives the address to be used in the bind(2) system call. The format of the +socketaddress depends on the socket type (see below). For "client" sockets this +option inserts a bind(2) call between socket(2) and connect(2) calls. For +"server" sockets this option is ignored! For datagram sockets behaviour of this +option is currently unspecified. +Note: for client sockets in the UNIX domain this option is not useful: with the +same address as connect it will conflict with the bind call of the server +socket; another address for bind is ignored (with Linux 2.2). +For TCP sockets these formats are currently implemented: +HOSTNAME +HOSTNAME:PORT +IPADDR +IPADDR:PORT +:PORT +.PORT + + +Option: connect-timeout=seconds + +Type: TIMEVAL +Option group: SOCKET +Phase: PASTSOCKET +Platforms: all + +Abort the connection attempt after the given time with error status. + +# +Option: backlog=value + +Type: INT +Option group: LISTEN +Phase: LISTEN +Platforms: all + +Sets the value to be used with the listen(2) system call. The default is 5. +It does not seem to work for Linux 2.2; Linux seems to allow much more +established connections, but then they stay even after server process +shutdown... + + +Option: range=address:mask, range=address/bits + +Type: STRING +Option group: RANGE +Phase: ACCEPT +Platforms: all +Implementation status: only for INET (IP4) addresses + +Defines a subnet where clients may connect from. If other clients connect the +accepted connection is shut down immediately after examination of the client +address. If this option is not used, the default is 0.0.0.0:0.0.0.0, allowing +arbitrary client addresses. bits is the number of high order bits that must +match between the range value and the clients address. + + +Option: tcpwrap, tcpwrap=name + +Type: STRING_NULL +Option group: RANGE +Phase: ACCEPT +Platforms: (depends on libwrap installation) + +Uses the rules introduced by Wietse Venema's libwrap (tcpd) library to check +if the client is allowed to connect. The configuration files are +/etc/hosts.allow and /etc/hosts.deny. See "man 5 hosts_access" for +more information. is passed to the wrapper functions as daemon +process name. If omitted, the basename of socats invokation (argv[0]) is +passed. +If both tcpwrap and and range options are applied to an address, both +conditions must be fulfilled to allow the connection. + + +Option: hosts-allow, tcpwrap-hosts-allow-table + +Type: FILENAME +Option group: RANGE +Phase: ACCEPT +Platforms: (depends on libwrap installation) + +Takes the specified file instead of /etc/hosts.allow. + + +Option: hosts-deny, tcpwrap-hosts-deny-table + +Type: FILENAME +Option group: RANGE +Phase: ACCEPT +Platforms: (depends on libwrap installation) + +Takes the specified file instead of /etc/hosts.deny. + + +Option: tcpwrap-etc, tcpwrap-dir + +Type: FILENAME +Option group: RANGE +Phase: ACCEPT +Platforms: (depends on libwrap installation) + + Looks for hosts.allow and hosts.deny in the specified directory. Is + overriden by options hosts-allow and hosts-deny. + + +------------------------------------------------------------------------------- +IP options + + +Option: ip-options=values +Aliases: ipoptions + +Type: BIN +Option group: SOCK_IP +Phase: PASTSOCKET +Platforms: all + +Sets the IP_OPTIONS values of the IP socket. For example, to send packets to +destination D.D.D.D via a router G.G.G.G you have to specify G.G.G.G as the +"normal" destination, and D.D.D.D in the source route: +TCP:G.G.G.G:25,ip-options=x890704dddddddd +Note that the destination will see G.G.G.G as sender of the packets, and +therefore might not return the answers correctly. +See RFC791 for detailed specification of IP option fields. +Examples: +x01 ... nop +x8307040a000001 ... loose source route +x890b040a000001c0c1c2c3 ... strict source route +Note: with source routes, you should not specifiy destination address and +hops as defined in RFC791 (first hop as IP header destination address, +further hops and final destination in source route) because the (Linux?) kernel changes +them to a more intuitive form (final destination as destination in IP header, +gateways in source route). So, in destination address give the final +destination, and in the source route the gateways! +Note: this option may be mulitply applied per socket but the (Linux?) kernel +pads each setting with 0' to align the options end to 4 octets. So you should +better pad the options data with nops (01) yourself. + + +Option: ip-pktinfo +Aliases: ippktinfo, pktinfo + +Type: INT (should be struct in_pktinfo) +Option group: SOCK_IP +Phase: PASTSOCKET +Platforms: Linux +Status: Not completely implemented (ancillary messages are not supported by +socat/xio) + +Pass an IP_PKTINFO ancillary message. + + +Option: ip-recvtos +Aliases: iprecvtos, recvtos + +Logical type: bool +Physical type: INT +Option group: SOCK_IP +Phase: PASTSOCKET +Platforms: Linux +Status: Not completely implemented (ancillary messages are not supported by +socat/xio) + +Set the IP_RECVTOS socket option which enables IP_TOS ancillary message +passing. + + +Option: ip-recvttl +Aliases: iprecvttl, recvttl + +Logical type: bool +Physical type: INT +Option group: SOCK_IP +Phase: PASTSOCKET +Platforms: all +Implementation status: No results. + +Set the IP_RECVTTL socket option. + + +Option: ip-recvopts +Aliases: iprecvopts, recvopts + +Logical type: bool +Physical type: INT +Option group: SOCK_IP +Phase: PASTSOCKET +Platforms: all +Implementation status: No results. + +Set the IP_RECVOPTS socket option. + + +Option: ip-retopts +Aliases: ipretopts, retopts + +Logical type: bool +Physical type: INT +Option group: SOCK_IP +Phase: PASTSOCKET +Platforms: all +Implementation status: No results. + +Set the IP_RETOPTS socket option. + + +Option: ip-tos=value +Aliases: iptos=value, tos=value + +Logical type: byte +Physical type: INT +Option group: SOCK_IP +Phase: PASTSOCKET +Platforms: all + +Sets the TOS (type of service) flags for the outgoing IP headers of the +socket. My Linux 2.2 does not allow to set values other than 0 (probably +needs some optional kernel features). + + +Option: ip-ttl=value +Aliases: ipttl=value, ttl=value + +Logical type: byte +Physical type: INT +Option group: SOCK_IP +Phase: PASTSOCKET +Platforms: all + +Sets the TTL (time to live) field for the outgoing IP headers of the socket. +0 does not seem to be useful and gives "invalid argument" error in Linux. +This option can be used to implement a "poor mans traceroute" in conjunction +with tcpdump. + + +Option: ip-hdrincl +Aliases: iphdrincl, hdrincl + +Logical type: bool +Physical type: INT +Option group: SOCK_IP +Phase: PASTSOCKET +Platforms: all + +Set the IP_HDRINCL socket option. User will supply IP header before user +data. For raw IP sockets only. Not tested. + + +Option: ip-recverr +Aliases: iprecverr, recverr + +Type: INT +Option group: SOCK_IP +Phase: PASTSOCKET +Platforms: Linux + +Set the IP_RECVERR socket option. +Implementation status: No results. + + +Option: ip-mtu-discover=value +Aliases: ipmtudiscover=value, mtudiscover=value + +Type: INT (0..2) +Option group: SOCK_IP +Phase: PASTSOCKET +Platforms: Linux + +Sets the IP_MTU_DISCOVER flag of the IP socket. In Linux there are three values +defined: 0..dont(never), 1..want(per route), 2..do(always) + + +Option: ip-mtu +Aliases: ipmtu, mtu + +Type: INT +Option group: SOCK_IP +Phase: PASTSOCKET +Platforms: none + +Sets the MTU (maximal transfer unit) of the socket. In Linux this is a +read-only parameter and results in a "protocol not available" error. + + +Option: ip-freebind +Aliases: ipfreebind, freebind + +Logical type: bool +Physical type: INT +Option group: SOCK_IP +Phase: PASTSOCKET +Platforms: none + +Allows the socket to locally bind to any address, even those that are +not covered by an interface address, alias address or a local subnet. Even +broadcast and multicast addresses are possible. +Note: this option has been found on Linux 2.4 in . This file might +not be included per default, because it creates errors. +To make this option available, "make" socat with the CCOPT environment +variable set to "-DIP_FREEBIND=15" + + +Option: ip-router-alert=value +Aliases: iprouteralert, routeralert + +Type: INT +Option group: SOCK_IP +Phase: PASTSOCKET +Platforms: Linux + +Sets the IP_ROUTER_ALERT socket option. Only works with raw sockets. +"Invalid argument" + + +Option: ip-add-membership=multicast-address:interface-address + ip-add-membership=multicast-address:interface-name + ip-add-membership=multicast-address:interface-index + ip-add-membership=multicast-address:interface-address:interface-name + ip-add-membership=multicast-address:interface-address:interface-index +Aliases: add-membership + ip-membership + +Type: IP_MREQN +Option group: SOCK_IP +Phase: PASTSOCKET +Platforms: all + + Makes the socket member of the specified multicast group. This is currently + only implemented for IPv4. The option takes the IP address of the multicast + group and info about the desired network interface. The most common syntax + is the first one, while the others are only available on systems that + provide tt(struct mreqn) (Linux).nl() + The indices of active network interfaces can be shown using the utility + procan(). + + +Option: ip-drop-membership + +Not implemented. + + +#! Option: ipv6-join-group + + +Option: ip-multicast-ttl=byte +Aliases: ipmulticastttl, multicastttl + +Type: BYTE +Option group: SOCK_IP +Phase: PASTSOCKET +Platforms: all + + Sets the TTL used for outgoing multicast traffic. Default is 1. + + +Option: ip-multicast-loop +Aliases: ipmulticastloop, multicastloop + +Logical type: bool +Physical type: INT +Option group: SOCK_IP +Phase: PASTSOCKET +Platforms: all + + Specifies if outgoing multicast traffic should loop back to the interface. + + +Option: ip-multicast-if=hostname +Aliases: multicast-if + +Type: IP4NAME +Option group: SOCK_IP +Phase: PASTSOCKET +Platforms: all + + Specifies hostname or address of the network interface to be used for + multicast traffic. + + +Option: ip-pktoptions +Aliases: ippktoptions, pktoptions, pktopts + +Type: INT? +Option group: SOCK_IP +Phase: PASTSOCKET +Platforms: Linux + +Set the IP_PKTOPTIONS socket option. No docu found. +Implementation status: "Protocol not available". + + +Option: res-debug + +Type: BOOL +Option group: SOCK_IP +Phase: INIT +Platforms: all + +Apply the debug resolver option to all queries of this XIO address. + + +Option: res-aaonly +Aliases: aaonly + +Type: BOOL +Option group: SOCK_IP +Phase: INIT +Platforms: all + +Apply the aaonly resolver option to all queries of this XIO address. + + +Option: res-usevc +Aliases: usevc + +Type: BOOL +Option group: SOCK_IP +Phase: INIT +Platforms: all + +Apply the usevc resolver option to all queries of this XIO address. + + +Option: res-primary +Aliases: primary + +Type: BOOL +Option group: SOCK_IP +Phase: INIT +Platforms: all + +Apply the primary resolver option to all queries of this XIO address. + + +Option: res-igntc +Aliases: igntc + +Type: BOOL +Option group: SOCK_IP +Phase: INIT +Platforms: all + +Apply the igntc resolver option to all queries of this XIO address. + + +Option: res-recurse +Aliases: recurse + +Type: BOOL +Option group: SOCK_IP +Phase: INIT +Platforms: all + +Apply the recurse resolver option to all queries of this XIO address. + + +Option: res-defnames +Aliases: defnames + +Type: BOOL +Option group: SOCK_IP +Phase: INIT +Platforms: all + +Apply the defnames resolver option to all queries of this XIO address. + + +Option: res-stayopen +Aliases: stayopen + +Type: BOOL +Option group: SOCK_IP +Phase: INIT +Platforms: all + +Apply the stayopen resolver option to all queries of this XIO address. + + +Option: res-dnsrch +Aliases: dnsrch + +Type: BOOL +Option group: SOCK_IP +Phase: INIT +Platforms: all + +Apply the dnsrch resolver option to all queries of this XIO address. + + +------------------------------------------------------------------------------- +IP6 options + + +Option: ipv6-v6only=value +Alias: ipv6only, v6only + +Type: BOOL +Option group: SOCK_IP6 +Phase: PASTSOCKET +Platforms: FreeBSD, Linux + +Apply the IPV6_V6ONLY socket option to the file descriptor. This controls if +the socket listens only on the IPv6 protocol or also on IPv4. + + +------------------------------------------------------------------------------- +IPAPP (TCP and UDP) options + + +Option: sourceport=value +Alias: sp=value + +Type: 2BYTE +Option group: IPAPP (IP_TCP and IP_UDP) +Phase: LATE +Platforms: all + +For outgoing (client) TCP and UDP connections, it sets the source port (local port, client side port) of +the socket connection. For server type addresses, requires the client to use +this sourceport, otherwise socat immediately shuts down the connection. +On UNIX class operating systems root privilege are required to set a source +port between 1 and 1023 incl. 0 gives a "random" port number >= 1024, which is +the default. + + +Option: lowport + +Type: BOOL +Option group: IPAPP (IP_TCP and IP_UDP) +Phase: LATE +Platforms: all + +For outgoing (client) TCP and UDP connections, it sets the source +to an unused random port between 640 and 1023 incl. On UN*X type operating +systems, this requires root privilege, and thus guaranties the peer to be +root authorized. +With TCP or UDP listen addresses, socat immediately shuts down the +connection if the client does not use a sourceport <= 1023. +This mechanism can provide limited authorization under some circumstances. + +------------------------------------------------------------------------------- +TCP options + + +Option: tcp-nodelay +Aliases: nodelay + +Logical type: bool +Physical type: INT +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: all + +Sets the TCP_NODELAY flag of the TCP socket. This turns off Nagles algorithm. + + +Option: tcp-maxseg +Aliases: maxseg, mss + +Type: INT +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: all + +Limits the MAXSEG (MSS) value of the TCP socket. This option is applied before +the connect or listen call, so it is transferred in the SYN packet to the peer +socket. +Linux client: 0 gives "invalid argument", higher values are used in SYN +negotiation, but effective MSS is n-12, at least 8. +On AIX, this is a read-only option. + + +Option: tcp-maxseg-late +Aliases: maxseg-late, mss-late + +Type: INT +Option group: IP_TCP +Phase: CONNECTED +Platforms: all + +Limits the MAXSEG (MSS) value of the TCP socket. This option is applied past +the connect or accept call, so it is not transferred as MSS to the peer socket. +Observation with Linux 2.2: does not influence the size of packets generated +by the local socket. + + +Option: tcp-cork +Aliases: cork + +Logical type: bool +Physical type: INT +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: Linux + +Sets the TCP_CORK option. + + +Option: tcp-stdurg +Aliases: stdurg + +Logical type: bool +Physical type: INT +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: none + +Applies the TCP_STDURG option with setsockopt. This enables RFC 1122 compliant +urgent point handling. + + +Option: tcp-rfc1323 +Aliases: rfc1323 + +Logical type: bool +Physical type: INT +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: none + +Applies the TCP_RFC1323 option with setsockopt. This enables RFC1323 TCP +enhancements (window scale, timestamp). + + +Option: tcp-keepidle +Aliases: keepidle + +Type: INT +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: Linux + +Sets the TCP_KEEPIDLE value of the socket with setsockopt(). Starts keepalive +after this period (in seconds?) + + +Option: tcp-keepintvl +Aliases: keepintvl + +Type: INT +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: Linux + +Sets the TCP_KEEPINTVL value of the socket with setsockopt(). Intervall between +keepalives (in seconds?) + + +Option: tcp-keepcnt +Aliases: keepcnt + +Type: INT +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: Linux + +Sets the TCP_KEEPCNT value of the socket with setsockopt(). Number of +keepalives before death. + + +Option: tcp-syncnt +Aliases: syncnt + +Type: INT +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: Linux + +Sets the TCP_SYNCNT value of the socket with setsockopt(). Number of SYN +retransmits. + + +Option: tcp-linger2 +Aliases: linger2 + +Type: INT +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: Linux + +Sets the TCP_LINGER2 value of the socket with setsockopt(). Life time of +orphaned FIN-WAIT-2 state. + + +Option: tcp-defer-accept +Aliases: defer-accept + +Type: INT +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: Linux + +Sets the TCP_DEFER_ACCEPT value of the socket with setsockopt(). accept() of +the listener will only return when data arrived at the new connection. The +value is converted to seconds by some algorithm. + + +Option: tcp-window-clamp +Aliases: window-clamp + +Type: INT +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: Linux + +Sets the TCP_WINDOW_CLAMP value of the socket with setsockopt(). "Bound advertised +window". + + +Option: tcp-info +Aliases: info + +Type: INT +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: FreeBSD, Linux + +Sets the TCP_INFO value of the socket with setsockopt(). Is a read only option, +so it always generates an error. + + +Option: tcp-quickack +Aliases: quickack + +Type: INT +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: Linux + +Sets the TCP_QUICKACK option with setsockopt(). + + +Option: tcp-md5sig +Aliases: md5sig + +Type: INT +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: none + +Enables generation of MD5 digests on the packets. + + +Option: tcp-noopt +Aliases: noopt + +Type: INT +Option: group: IP_TCP +Phase: PASTSOCKET +Platforms: FreeBSD + +Disables use of TCP options. + + +Option: tcp-nopush +Aliases: nopush + +Type: INT +Option: group: IP_TCP +Phase: PASTSOCKET +Platforms: FreeBSD + +Sets the TCP_NOPUSH option. + + +Option: tcp-sack-disable +Aliases: sack-disable + +Type: INT +Option: group: IP_TCP +Phase: PASTSOCKET +Platforms: none + +Disables use the selective acknowledge feature. + + +Option: tcp-signature-enable +Aliases: signature-enable + +Type: INT +Option: group: IP_TCP +Phase: PASTSOCKET +Platforms: none + +Enables generation of MD5 digests on the packets. + + +Option: tcp-abort-threshold +Aliases: abort-threshold + +Type: INT +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: HP-UX, SunOS + +Sets the time to wait for an answer of the peer on an established connection. + + +Option: tcp-conn-abort-threshold +Aliases: conn-abort-threshold + +Type: INT +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: HP-UX, SunOS + +Sets the time to wait for an answer of the server during the initial connect. + + +Option: tcp-keepinit +Aliases: keepinit + +Type: INT +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: none + +Sets the time to wait for an answer of the server during connect() before +giving up. Value in half seconds, default is 150 (75s). + + +Option: tcp-paws +Aliases: paws + +Type: BOOL +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: none + +Enables the "protect against wrapped sequence numbers" feature. + + +Option: tcp-sackena +Aliases: sackena + +Type: BOOL +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: none + +Enables selective acknowledge. + + +Option: tcp-tsoptena +Aliases: tsoptena + +Type: BOOL +Option group: IP_TCP +Phase: PASTSOCKET +Platforms: none + +Enables the time stamp option that allows RTT recalculation on existing +connections. + + +=============================================================================== +SOCKS options + + +Option: socksport + +Type: STRING +Option group: IP_SOCKS4 +Phase: LATE +Platforms: all + +Overrides the default socks server port 1080 + + +Option: socksuser + +Type: NAME +Option group: IP_SOCKS4 +Phase: LATE +Platforms: all + +Overrides the system derived socks user name ($USER or $LOGNAME or "anonymous") + + +=============================================================================== +HTTP options + + +Option: proxyport + +Type: STRING +Option group: HTTP +Phase: LATE +Platforms: all + +Overrides the default HTTP proxy port 8080. + + +Option: ignorecr + +Type: BOOL +Option group: HTTP +Phase: LATE +Platforms: all + +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 +to ignore CR in the answer. Nevertheless, socat sends CR+NL to the proxy. + + +Option: proxyauth + +Type: STRING +Option group: HTTP +Phase: LATE +Platforms: all + +Provide "basic" authentication to the proxy server. The argument to the option +must be the username followed by ':' followed by the password. This string is +used with a "Proxy-Authorize: Base" header in base64 encoded form. + + +Option: resolve + +Type: BOOL +Option group: HTTP +Phase: LATE +Platforms: all + +Per default, socat sends to the proxy a CONNECT request containing the target +hostname. With this option, socat resolves the hostname locally and sends the +IP address. + + +=============================================================================== +TERMIOS options + +These options are applied with tcsetattr calls with a struct termios. +Attention: Applying these options to stdin/stdout when they refer to your +terminal might directly effect your terminal! +See Linux:"man 3 termios" and Linux:"man 2 stty" + +------------------------------------------------------------------------------- +TERMIOS combined modes + + +Option: raw + +Type: CONST +Option group: TERMIOS +Phase: FD +Platforms: all + +Is equivalent to +ignbrk=0,brkint=0,ignpar=0,parmrk=0,inpck=0,istrip=0,inlcr=0,igncr=0,icrnl=0,ixon=0,ixoff=0,iuclc=0,ixany=0,imaxbel=0,opost=0,isig=0,icanon=0,xcase=0,vmin=1,vtime=0 + + +Option: sane + +Type: CONST +Option group: TERMIOS +Phase: FD +Platforms: all + +Is equivalent to +cread,ignbrk=0,brkint,inlcr=0,igncr=0,icrnl,ixoff=0,iuclc=0,-ixany=0,imaxbel,opost,olcuc=0,ocrnl=0,onlcr,onocr=0,onlret=0,ofill=0,ofdel=0,nl0,cr0,tab0,bs0,vt0,ff0,isig,icanon,iexten,echo,echoe,echok,echonl=0,noflsh=0,xcase=0,tostop=0,echoprt=0,echoctl,echoke + +------------------------------------------------------------------------------- +TERMIOS input mode flags + + +Option: ignbrk + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the IGNBRK flag of the terminal driver. + + +Option: brkint + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the BRKINT flag of the terminal driver. + + +Option: ignpar + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the IGNPAR flag of the terminal driver. + + +Option: parmrk + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the PARMRK flag of the terminal driver. + + +Option: inpck + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the INPCK flag of the terminal driver. Enables input parity checking. + + +Option: istrip + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the ISTRIP flag of the terminal driver. Strips off the eighth bit. + + +Option: inlcr + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the INLCR flag of the terminal driver. Translates NL to CR on input. + + +Option: igncr + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the IGNCR flag of the terminal driver. Ignores CR character on input. + + +Option: icrnl + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the ICRNL flag of the terminal driver. Translates CR to NL on input. This +option is ignored when IGNCR is set. + + +Option: iuclc + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the IUCLC flag of the terminal driver. Changes characters in input from +uppercase to lowercase. + + +Option: ixon + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the IXON flag of the terminal driver. Enables XON/XOFF flow control on +output (?). + + +Option: ixany + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the IXANY flag of the terminal driver. Enables any character to restart +output. + + +Option: ixoff +Aliases: tandem + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the IXOFF flag of the terminal driver. Enables XON/XOFF flow control on +input. + + +Option: imaxbel + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the IMAXBEL flag of the terminal driver. Rings the bell when the input +queue is full. + +------------------------------------------------------------------------------- +TERMIOS output mode flags + + +Option: opost + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the OPOST flag of the terminal driver. + + +Option: olcuc + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the OLCUC flag of the terminal driver. + + +Option: onlcr + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the ONLCR flag of the terminal driver. + + +Option: ocrnl + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the OCRNL flag of the terminal driver. + + +Option: onocr + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the ONOCR flag of the terminal driver. + + +Option: onlret + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the ONLRET flag of the terminal driver. + + +Option: ofill + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the OFILL flag of the terminal driver. + + +Option: ofdel + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the OFDEL flag of the terminal driver. + + +Option: nldly + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the NLDLY flag of the terminal driver. 0 sets the value to NL0, and 1 to +NL1. See nl0, nl1. + + +Option: nl0 + +Type: CONST (const bool, always sets 0) +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the field NLDLY to the value NL0. + + +Option: nl1 + +Type: CONST (const bool, always sets 1) +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the field NLDLY to the value NL1. + + +Option: crdly=value + +Type: UINT (0..3) +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the field CRDLY to the given value. +See cr0, cr1, cr2, cr3. + + +Option: cr0 + +Type: CONST +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the CRDLY field to the value CR0. +See crdly. + + +Option: cr1 + +Type: CONST +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the CRDLY field to the value CR1. +See crdly. + + +Option: cr2 + +Type: CONST +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the CRDLY field to the value CR2. +See crdly. + + +Option: cr3 + +Type: CONST +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the CRDLY field to the value CR3. +See crdly. + + +Option: tab0 + +Type: CONST +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the horizontal tab delay mask to TAB0. +See tabdly. + + +Option: tab1 + +Type: CONST +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the horizontal tab delay mask to TAB1. +See tabdly. + + +Option: tab2 + +Type: CONST +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the horizontal tab delay mask to TAB2. +See tabdly. + + +Option: tab3 + +Type: CONST +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the horizontal tab delay mask to TAB3. +See tabdly. + + +Option: tabdly=value + +Type: UINT (0..3) +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the field TABDLY to the given value. +See tab0, tab1, tab2, and tab3. + + +Option: xtabs + +Type: CONST +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the horizontal tab delay mask to XTABS. + + +Option: bs0 + +Type: CONST (0) +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the field BSDLY to the value BS0 + + +Option: bs1 + +Type: CONST (1) +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the field BSDLY to the value BS1 + + +Option: bsdly + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the BSDLY flag of the terminal driver. 0 sets the value to BS0, and 1 to +BS1. See bs0, bs1. + + +Option: vt0 + +Type: CONST (0) +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the field VTDLY to the value VT0 + + +Option: vt1 + +Type: CONST (1) +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the field VTDLY to the value VT1 + + +Option: vtdly + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the VTDLY flag of the terminal driver. 0 sets the value to VT0, and 1 to +VT1. See vt0, vt1. + + +Option: ff0 + +Type: CONST (0) +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the field FFDLY to the value FF0 +See ffdly. + + +Option: ff1 + +Type: CONST (1) +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the field FFDLY to the value FF1 +See ffdly. + + +Option: ffdly + +Type: BOOL (0..1) +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the FFDLY flag of the terminal driver. 0 sets the value to FF0, and 1 to +FF1. See ff0, ff1. + + + +------------------------------------------------------------------------------- +TERMIOS control mode flags + + +Option: cs5 + +Type: CONST +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the field CSIZE to the value CS5 + + +Option: cs6 + +Type: CONST +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the field CSIZE to the value CS6 + + +Option: cs7 + +Type: CONST +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the field CSIZE to the value CS7 + + +Option: cs8 + +Type: CONST +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the field CSIZE to the value CS8 + + +Option: csize + +Type: UINT (0..3) +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the field CSIZE. 0..CS5, 1..CS6, 2..CS7, 3..CS8 + + +Option: cstopb + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the flag CSTOPB. + + +Option: cread + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the value of the CREAD flag. + + +Option: parenb + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the PARENB flag of the terminal driver. + + +Option: parodd + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the PARODD flag of the terminal driver. + + +Option: hupcl +Aliases: hup + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the HUPCL flag of the terminal driver. + + +Option: clocal + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the CLOCAL flag of the terminal driver. + + +Option: crtscts + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: FreeBSD, Linux, SunOS + +Sets the CRTSCTS flag of the terminal driver. + + +Option: b0 (HP-UX, Linux, SunOS) +Option: b50 (HP-UX, Linux, SunOS) +Option: b75 (HP-UX, Linux, SunOS) +Option: b110 (HP-UX, Linux, SunOS) +Option: b134 (HP-UX, Linux, SunOS) +Option: b150 (HP-UX, Linux, SunOS) +Option: b200 (HP-UX, Linux, SunOS) +Option: b300 (HP-UX, Linux, SunOS) +Option: b600 (HP-UX, Linux, SunOS) +Option: b900 (HP-UX) +Option: b1200 (HP-UX, Linux, SunOS) +Option: b1800 (HP-UX, Linux, SunOS) +Option: b2400 (HP-UX, Linux, SunOS) +Option: b3600 (HP-UX) +Option: b4800 (HP-UX, Linux, SunOS) +Option: b7200 (HP-UX) +Option: b9600 (HP-UX, Linux, SunOS) +Option: b19200 (HP-UX, Linux, SunOS) +Option: b38400 (HP-UX, Linux, SunOS) +Option: b57600 (HP-UX, Linux, SunOS) +Option: b115200 (HP-UX, Linux, SunOS) +Option: b230400 (HP-UX, Linux, SunOS) +Option: b460800 (HP-UX, Linux, SunOS) +Option: b500000 (Linux) +Option: b576000 (Linux) +Option: b921600 (Linux) +Option: b1000000 (Linux) +Option: b1152000 (Linux) +Option: b1500000 (Linux) +Option: b2000000 (Linux) +Option: b2500000 (Linux) +Option: b3000000 (Linux) +Option: b3500000 (Linux) +Option: b4000000 (Linux) + +Type: CONST +Option group: TERMIOS +Phase: FD + +Sets the baud rate to the implied value. b0 "hangs up" the connection. + + +Option: ispeed + +Type: UINT +Option group: TERMIOS +Phase: FD +Platforms: FreeBSD, Linux + +Sets the input baud rate to the specified value. This works on systems where +struct termios has a special c_ispeed field. + + +Option: ospeed + +Type: UINT +Option group: TERMIOS +Phase: FD +Platforms: FreeBSD, Linux + +Sets the input baud rate to the specified value. This works on systems where +struct termios has a special c_ospeed field. + + + + +------------------------------------------------------------------------------- +TERMIOS local mode flags + + +Option: isig + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the ISIG flag of the terminal driver. + + +Option: icanon + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the ICANON flag of the terminal driver. + + +Option: xcase + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: HP-UX, Linux, SunOS + +Sets the XCASE flag of the terminal driver. + + +Option: echo + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the ECHO flag of the terminal driver. + + +Option: echoe +Aliases: crterase + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the ECHOE flag of the terminal driver. + + +Option: echok + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the ECHOK flag of the terminal driver. + + +Option: echonl + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the ECHONL flag of the terminal driver. + + +Option: echoctl +Aliases: ctlecho + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the ECHOCTL flag of the terminal driver. + + +Option: echoprt +Aliases: prterase + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the ECHOPRT flag of the terminal driver. + + +Option: echoke +Aliases: crtkill + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the ECHOKE flag of the terminal driver. + + +Option: flusho + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the FLUSHO flag of the terminal driver. + + +Option: noflsh + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the NOFLSH flag of the terminal driver. + + +Option: tostop + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the TOSTOP flag of the terminal driver. + + +Option: pendin + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the PENDIN flag of the terminal driver. + + +Option: iexten + +Type: BOOL +Option group: TERMIOS +Phase: FD +Platforms: all + +Sets the IEXTEN flag of the terminal driver. + + +------------------------------------------------------------------------------- +TERMIOS options for functional characters + +Option: vintr=value +Aliases: intr=value + +Type: BYTE +Option group: TERMIOS +Phase: FD +Platforms: all +Status: tested + +Sets the value for the VINTR character that interrupts the current process. +On UNIX systems the preset value usually is 3 (^C). + + +Option: vquit=value +Aliases: quit=value + +Type: BYTE +Option group: TERMIOS +Phase: FD +Platforms: all +Status: tested + +Sets the value for the VQUIT character that quits the current process. +On my Linux 2.2 system the preset value is 0x1c (^\). + + +Option: verase=value +Aliases: erase=value + +Type: BYTE +Option group: TERMIOS +Phase: FD +Platforms: all +Status: tested + +Sets the value for the VERASE character that erases the last character. +On many UNIX systems the preset value is 0x7f. + + +Option: vkill=value +Aliases: kill=value + +Type: BYTE +Option group: TERMIOS +Phase: FD +Platforms: all +Status: tested + +Sets the value for the VKILL character that kills (erases) the current line. +On my Linux 2.2 system systems the preset value is 0x15 (^U). + + +Option: veof=value +Aliases: eof=value + +Type: BYTE +Option group: TERMIOS +Phase: FD +Platforms: all +Status: tested + +Sets the value for the VEOF character that kills indicate end of file. +On most UNIX systems the preset value is 0x04 (^D). + + +Option: vtime=value +Aliases: time=value + +Type: BYTE +Option group: TERMIOS +Phase: FD +Platforms: all +Status: not tested + +Sets the value of VTIME. See "man 1 stty" / time. +On my Linux 2.2 system the preset value is 0. + + +Option: vmin=value +Aliases: min=value + +Type: BYTE +Option group: TERMIOS +Phase: FD +Platforms: all +Status: not tested + +Sets the value of VMIN. See "man 1 stty" / time. +On my Linux 2.2 system the preset value is 1. + + +Option: vswtc=value +Aliases: swtc=value, swtch=value + +Type: BYTE +Option group: TERMIOS +Phase: FD +Platforms: Linux +Status: not tested + +Sets the value of VSWTC. "Switches to a different shell layer". +On my Linux 2.2 system the preset value is 0. + + +Option: vstart=value +Aliases: start=value + +Type: BYTE +Option group: TERMIOS +Phase: FD +Platforms: all +Status: tested + +Sets the value for the VSTART character that resumes data flow after a stop. +Usually the preset value is 0x11 (^Q). + + +Option: vstop=value +Aliases: stop=value + +Type: BYTE +Option group: TERMIOS +Phase: FD +Platforms: all +Status: tested + +Sets the value for the VSTOP character that stops output. +Usually the preset value is 0x13 (^S) + + +Option: vsusp=value +Aliases: susp=value + +Type: BYTE +Option group: TERMIOS +Phase: FD +Platforms: all +Status: tested + +Sets the value for the VSUSP character that suspends the current foreground +process and reactivates the shell. +Usually the preset value is 0x1a (^Z) + + +Option: vdsusp=value +Aliases: dsusp=value + +Type: BYTE +Option group: TERMIOS +Phase: FD +Platforms: FreeBSD, HP-UX, SunOS +Status: tested + +Sets the value for the VDSUSP character that suspends the current foreground +process and reactivates the shell. + + +Option: veol=value +Aliases: eol=value + +Type: BYTE +Option group: TERMIOS +Phase: FD +Platforms: all +Status: tested with awkward results + +Sets the value for the VEOL character that should indicate end of line. +Not clear what differentiates it from the return key; xterm window put "xterm" +into the input buffer. +On my Linux 2.2 system the preset value is 0 (disabled) + + +Option: vreprint=value +Aliases: reprint=value, rprnt=value + +Type: BYTE +Option group: TERMIOS +Phase: FD +Platforms: FreeBSD, Linux, SunOS +Status: not tested + +Sets the value for the VREPRINT character that should reprint the current line. +On my Linux 2.2 system the preset value is 0x12 (^R). Nevertheless, bash +enters backward search mode. + + +Option: vdiscard=value +Aliases: discard=value + +Type: BYTE +Option group: TERMIOS +Phase: FD +Platforms: FreeBSD, Linux, SunOS +Status: not tested + +Sets the value for the VDISCARD character. +On my Linux 2.2 system the preset value is 0x0f (^O) + + +Option: vwerase=value +Aliases: werase=value + +Type: BYTE +Option group: TERMIOS +Phase: FD +Platforms: all +Status: tested + +Sets the value for the VWERASE character that erases the last word. +On my Linux 2.2 system the preset value is 0x17 (^W) + + +Option: vlnext=value +Aliases: lnext=value + +Type: BYTE +Option group: TERMIOS +Phase: FD +Platforms: all +Status: tested + +Sets the value for the VLNEXT character that lets the next input character raw +(not interpreted). +On my Linux 2.2 system the preset value is 0x16 (^V) + + +Option: veol2=value +Aliases: eol2=value + +Type: BYTE +Option group: TERMIOS +Phase: FD +Platforms: all +Status: not tested + +Sets the value for the VEOL2 character. +On my Linux 2.2 system the preset value is 0 (disabled). + + +=============================================================================== +READLINE options + +Option: history-file=filename +Aliases: history=filename + +Type: STRING +Option group: READLINE +Phase: LATE +Platforms: (depends on libreadline installation) + +Without this option, the readline address uses only a per process history +list. With this option, socat tries to read history lines during initialization +from the given file, and on termination writes the old and new lines to the +file. +NOTE: currently, no mechanism is implemented for limiting the length of the +history file. +NOTE: filename must be a valid relativ or absolute path; "~" is not supported! + + +Option: noprompt + +Type: BOOL +Option group: READLINE +Phase: LATE +Platforms: all + +Since version 1.3.3, socat per default tries to determine a prompt - +that is then passed to the readline call - by remembering the last +incomplete line of the output. With this option, socat does not pass a +prompt to the readline call, so it might set the cursor to the first column +of the terminal. + + +Option: noecho + +Type: STRING +Option group: READLINE +Phase: LATE +Platforms: all + +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 +typed. The pattern is a regular expression, e.g. +"^[Pp]assword:.*$" or "([Uu]ser:|[Pp]assword:)". See regex(7) for details. + + +Option: prompt + +Type: STRING +Option group: READLINE +Phase: LATE +Platforms: all + +Passes the string as prompt to the readline function. readline prints this +prompt when stepping through the history. If this string matches a constant +prompt issued by an interactive program on the other socat address, +consistent look and feel can be archieved. + +=============================================================================== +OPENSSL options + +Option: openssl-cipherlist=string +Aliases: cipherlist=string, ciphers=string, cipher=string + +Type: STRING +Option group: OPENSSL +Phase: SPEC +Platforms: (depends on openssl installation) + +Selects the list of ciphers that may be used for the connection. +See the man page ciphers(1), section CIPHER LIST FORMAT, for +detailed information about syntax, values, and default of the cipherlist +string. +Several cipher strings may be given, separated by ':'. +Some simple cipher strings: + 3DES Uses a cipher suite with triple DES. + MD5 Uses a cipher suite with MD5. + aNULL Uses a cipher suite without authentication. + NULL Does not use encryption. + HIGH Uses a cipher suite with "high" encryption. +Note that the peer must support the selected property, or the negotiation +will fail. + + +Option: openssl-method=string +Aliases: method=string + +Type: STRING +Option group: OPENSSL +Phase: SPEC +Platforms: (depends on openssl installation) + +Sets the protocol version to be used. Valid strings (not case sensitive) are: + SSLv2 Select SSL protocol version 2. + SSLv3 Select SSL protocol version 3. + SSLv23 Select SSL protocol version 2 or 3. This is the default when + this option is not provided. + TLSv1 Select TLS protocol version 1. + + +Option: openssl-verify=bool +Aliases: verify=bool + +Type: BOOL +Option group: OPENSSL +Phase: SPEC +Platforms: (depends on openssl installation) + + Controls check of the peer's certificate. Default is 1 (true). Disabling + verify might open your socket for everyone! + + +Option: openssl-certificate=file +Aliases: cert=file + +Type: FILENAME +Option group: OPENSSL +Phase: SPEC +Platforms: (depends on openssl installation) + +Specifies the file with the certificate. The certificate must be +in OpenSSL format (*.pem). With openssl-listen, this option is strongly +recommended: except with cipher aNULL, "no shared ciphers" error might +occur when no certificate is given. + + +Option: openssl-key=file +Aliases: key + +Type: FILENAME +Option group: OPENSSL +Phase: SPEC +Platforms: (depends on openssl installation) + +Specifies the file with the private key. The private key may be in this +file or in the file given with the ref(cert) option. The party that has +to proof that it is the owner of a certificate needs the private key. + + +Option: openssl-cafile=file +Aliases: cafile + +Type: FILENAME +Option group: OPENSSL +Phase: SPEC +Platforms: (depends on openssl installation) + +Specifies the file with the trusted (root) authority certificates. The file +must be in PEM format and should contain one or more certificates. + + +Option: openssl-capath=directory +Aliases: capath + +Type: FILENAME +Option group: OPENSSL +Phase: SPEC +Platforms: (depends on openssl installation) + +Specify the directory with the trusted (root) certificates. The directory +must contain certificates in PEM format and their hashes (see OpenSSL +documentation) + + +Option: openssl-egd=file +Aliases: egd + +Type: FILENAME +Option group: OPENSSL +Phase: SPEC +Platforms: (depends on openssl installation) + +On some systems, openssl requires an explicit source of random data. Specify +the socket name where an entropy gathering daemon like egd provides random +data, e.g. /dev/egd-pool. + + +Option: openssl-pseudo +Aliases: pseudo + +Type: BOOL +Option group: OPENSSL +Phase: SPEC +Platforms: (depends on openssl installation) + +On systems where openssl cannot find an entropy source and where no entropy +gathering daemon can be utilized, this option activates a mechanism for +providing pseudo entropy. This is archieved 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 random calls. +NOTE:This mechanism is not sufficient for generation of secure keys! + + +Option: openssl-fips +Aliases: fips + +Type: BOOL +Option group: BOOL +Phase: SPEC +Platforms: (depends on OpenSSL installation and FIPS implementation) + +Enables FIPS mode if compiled in. For info about the FIPS encryption +implementation standard see http://oss-institute.org/fips-faq.html. +This mode might require that the involved certificates are generated with a +FIPS enabled version of openssl. Setting or clearing this option on one +socat address affects all OpenSSL addresses of this process. + + +=============================================================================== +Application specific address options + + +Option: ignoreeof +Aliases: ignoreof + +Type: BOOL +Option group: APPL +Phase: LATE +Platforms: all + +This option has to be supported by the application. For socat it means that an +EOF condition on this data source does not trigger termination procedures, but +instead the read/write loop waits for one second and then tries to read more +input data. This behaviour emulates "tail -f" and might not be useful for all +kinds of input devices, but regular files and /dev/null are good candidates. +Termination of socat then can only occur by EOF condition of the other input +device, an error, or by external events. + + +Option: cr + +Type: CONST +Option group: APPL +Phase: LATE +Platforms: all + +The appropriate data endpoint uses CR ('\r', 0x0d) as line terminator +character. Convert data to and from this stream appropriately. +This is useful for, e.g., modems. + + +Option: crnl +Aliases: crlf + +Type: CONST +Option group: APPL +Phase: LATE +Platforms: all + +The appropriate data endpoint uses CR+LF ("\r\n", 0x0d0a ) as line terminator +string. Convert data to and from this stream appropriately. +This is useful for, e.g., TCP protocols like SMTP and FTP. + + +Option: readbytes=num +Aliases: bytes + +Type: SIZE_T +Option group: APPL +Phase: LATE +Platforms: all + +socat reads only so many bytes from this address (the address provides +only so many bytes for transfer and pretends to be at EOF afterwards). + + +Option: lockfile=filename + +Type: FILENAME +Option group: APPL +Phase: INIT +Platforms: all + +If lockfile exists, exits with error. If lockfile does not exist, creates it +and continues; removes lockfile on exit. + + +Option: waitlock=filename + +Type: FILENAME +Option group: APPL +Phase: INIT +Platforms: all + +If lockfile exists, waits until it disappears. When lockfile does not exist, +creates it and continues; removes lockfile on exit. + +=============================================================================== +RETRY options + +Option: retry= + +Type: UINT +Option group: RETRY +Phase: INIT +Platforms: all + +Number of retries before the connection or listen attempt is aborted. +Default is 0, which means just one attempt. + + +Option: intervall= + +Type: TIMESPEC +Option group: RETRY +Phase: INIT +Platforms: all + +Time between consecutive attempts (seconds). Default is 1 second. + + +Option: forever + +Type: BOOL +Option group: RETRY +Phase: INIT +Platforms: all + +Performs an unlimited number of retry attempts. + +=============================================================================== +EXT2 options + +Option: ext2-secrm= +Aliases: secrm= + +Type: BOOL +Option group: REG +Phase: FD +Platforms: Linux + +Sets the secrm file attribute on the file. + + +Option: ext2-unrm= +Aliases: unrm= + +Type: BOOL +Option group: REG +Phase: FD +Platforms: Linux + +Sets the unrm file attribute on the file. + + +Option: ext2-compr= +Aliases: compr= + +Type: BOOL +Option group: REG +Phase: FD +Platforms: Linux + +Sets the compr file attribute on the file. + + +Option: ext2-sync= + +Type: BOOL +Option group: REG +Phase: FD +Platforms: all + +Sets the sync file attribute on the file. + + +Option: ext2-immutable= +Aliases: immutable= + +Type: BOOL +Option group: REG +Phase: FD +Platforms: Linux + +Sets the immutable file attribute on the file. + + +Option: ext2-append= + +Type: BOOL +Option group: REG +Phase: FD +Platforms: all + +Sets the append file attribute on the file. + + +Option: ext2-nodump= +Aliases: nodump= + +Type: BOOL +Option group: REG +Phase: FD +Platforms: Linux + +Sets the nodump file attribute on the file. + + +Option: ext2-noatime= + +Type: BOOL +Option group: REG +Phase: FD +Platforms: Linux + +Sets the noatime file attribute on the file. + + +Option: ext2-journal-data= +Aliases: journal-data= + +Type: BOOL +Option group: REG +Phase: FD +Platforms: Linux + +Sets the journal-data file attribute on the file. + + +Option: ext2-notail= +Aliases: notail= + +Type: BOOL +Option group: REG +Phase: FD +Platforms: none + +Sets the notail file attribute on the file. + + +Option: ext2-dirsync= +Aliases: dirsync= + +Type: BOOL +Option group: REG +Phase: FD +Platforms: Linux + +Sets the dirsync file attribute on the file. + + +Option: ext2-topdir= +Aliases: topdir= + +Type: BOOL +Option group: REG +Phase: FD +Platforms: Linux + +Sets the topdir file attribute on the file. + + +=============================================================================== + +Appendix: generating a sandbox (chroot environment) + +While it is possible to generate a sandbox almost anywhere in the file system, +I recommend to use a file system that has been mounted with restrictions, +especially nosuid and maybe nodev, or even ro. + +You may mount a dedicated file system for the sandbox, so it gets a little +harder for the guests to determine for sure if they are within a sandbox when +using "ls -id /" + +The following desribes typical steps for generating a sandbox. Depending on +your operating system, application, and security requirements, your mileage may +vary. With the below steps, you will be able to run some check programs to play +around with the sandbox. + +I Installation +1) Create a sandbox group - but give it and all following "sandbox" ids a more +cryptic name! +2) Create a sandbox user, only in sandbox group. If this user must never login, +give it a useless shell like /bin/false +3) Check the sandbox home directory (e.g. /home/sandbox) and save and remove +all .profile, public_html/ etc. +4) Optionally mount a new file system over the new home directory +5) Generate subdirectories bin, lib, etc, usr, usr/bin, usr/lib. +Set their permissions and ownership equal to the original directories (or use +only root.root) +6) Generate subdirectory home/sandbox (or similarly; like sandbox home) +7) Generate etc/passwd with users sandbox and root, but do not store original +password hashes there! +8) Generate etc/group with only groups sandbox and root (or system on AIX) +9) Copy test programs and utilities to bin, e.g. su, id, ls, mount, strace (but +without SUID/SGID) +10) Copy the required shared libraries and the shared library loader to their +directories. +On Linux, e.g. /lib/ld-linux.so.2, /lib/libnss_compat.so.2 +Note: it is often difficult to find out what shared libraries are (still) not +installed in the sandbox. The programs invoked in the sandbox typically do not +give useful error messages. If chroot's exec call gives an error like "no such +file or directory", and you do not know if it even found the program itself, +then remove the test programs execute permission; the error message should +change to "execute permission denied" or so. Redo the execute permissions and +look for the shared libraries... +List required libraries of a program: +Linux: ldd +AIX: xdb + map + +11) For testing purposes, install id, ls, su, mount, strace, and maybe sh in +the sandbox. Test it. + +II Customization +12) Copy your applications, configuration files, and data to the appropriate +directories within the sandbox. +Test function of the application in the sandbox, and add missing files and +libraries. If an application program gets killed immediately after start, it +might miss a shared library. + +III Cleanup, check +13) Implement your own tricks how to improve security of the sandbox +14) Remove test programs like bin/sh, id, ls, mount, strace + + +=============================================================================== +socket types, modes and their security features: +IP.v4.TCP.connect +IP.v4.TCP.listen range tcpwrap srcport lowport +IP.v4.UDP.connect +IP.v4.UDP.listen range tcpwrap srcport lowport +IP.v4.UDP.sendto +IP.v4.UDP.recvfrom range tcpwrap srcport lowport +IP.v4.UDP.recv range tcpwrap srcport lowport +IP.v4.raw.sendto +IP.v4.raw.recvfrom range tcpwrap +IP.v4.raw.recv range tcpwrap +IP.v6.TCP.connect +IP.v6.TCP.listen range tcpwrap srcport lowport +IP.v6.UDP.connect +IP.v6.UDP.listen range tcpwrap srcport lowport +IP.v6.UDP.sendto +IP.v6.UDP.recvfrom range tcpwrap srcport lowport +IP.v6.UDP.recv range tcpwrap srcport lowport +IP.v6.raw.sendto +IP.v6.raw.recvfrom range tcpwrap +IP.v6.raw.recv srcport lowport +UNIX.stream.connect +UNIX.stream.listen +UNIX.dgram.sendto +UNIX.dgram.recvfrom +UNIX.dgram.recv +OPENSSL.connect +OPENSSL.TCP4.listen range tcpwrap srcport lowport +OPENSSL.TCP6.listen range tcpwrap srcport lowport + +=============================================================================== +Missing features and Caveats: + +. no support for SIGIO mechanism +. no support for socket ancillary messages +. Probably many ioctls not implemented due to missing documentation +. only limited implementation of raw sockets and interfaces, +. no support for high level sockets beyond UNIX, INET, and INET6 domains diff --git a/error.c b/error.c new file mode 100644 index 0000000..3345979 --- /dev/null +++ b/error.c @@ -0,0 +1,249 @@ +/* $Id: error.c,v 1.29 2007/02/08 18:22:23 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* the logging subsystem */ + +#include "config.h" + +#include +#include +#include +#if HAVE_SYSLOG_H +#include +#endif +#include +#include /* time_t, strftime() */ +#include /* gettimeofday() */ +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include "mytypes.h" +#include "compat.h" +#include "utils.h" + +#include "error.h" + +/* translate MSG level to SYSLOG level */ +int syslevel[] = { + LOG_DEBUG, + LOG_INFO, + LOG_NOTICE, + LOG_WARNING, + LOG_ERR, + LOG_CRIT }; + +struct diag_opts { + const char *progname; + int msglevel; + int exitlevel; + int logstderr; + int syslog; + FILE *logfile; + int logfacility; + bool micros; + int exitstatus; /* pass signal number to error exit */ + bool withhostname; /* in custom logs add hostname */ + char *hostname; +} ; + + +struct diag_opts diagopts = + { NULL, E_ERROR, E_ERROR, 1, 0, NULL, LOG_DAEMON, false, 0 } ; + +static void _msg(int level, const char *buff, const char *syslp); + +static struct wordent facilitynames[] = { + {"auth", (void *)LOG_AUTH}, +#ifdef LOG_AUTHPRIV + {"authpriv", (void *)LOG_AUTHPRIV}, +#endif +#ifdef LOG_CONSOLE + {"console", (void *)LOG_CONSOLE}, +#endif + {"cron", (void *)LOG_CRON}, + {"daemon", (void *)LOG_DAEMON}, +#ifdef LOG_FTP + {"ftp", (void *)LOG_FTP}, +#endif + {"kern", (void *)LOG_KERN}, + {"local0", (void *)LOG_LOCAL0}, + {"local1", (void *)LOG_LOCAL1}, + {"local2", (void *)LOG_LOCAL2}, + {"local3", (void *)LOG_LOCAL3}, + {"local4", (void *)LOG_LOCAL4}, + {"local5", (void *)LOG_LOCAL5}, + {"local6", (void *)LOG_LOCAL6}, + {"local7", (void *)LOG_LOCAL7}, + {"lpr", (void *)LOG_LPR}, + {"mail", (void *)LOG_MAIL}, + {"news", (void *)LOG_NEWS}, +#ifdef LOG_SECURITY + {"security", (void *)LOG_SECURITY}, +#endif + {"syslog", (void *)LOG_SYSLOG}, + {"user", (void *)LOG_USER}, + {"uucp", (void *)LOG_UUCP} +} ; + + +void diag_set(char what, const char *arg) { + switch (what) { + const struct wordent *keywd; + + case 'y': diagopts.syslog = true; + if (arg && arg[0]) { + if ((keywd = + keyw(facilitynames, arg, + sizeof(facilitynames)/sizeof(struct wordent))) == NULL) { + Error1("unknown syslog facility \"%s\"", arg); + } else { + diagopts.logfacility = (int)keywd->desc; + } + } + openlog(diagopts.progname, LOG_PID, diagopts.logfacility); + diagopts.logstderr = false; break; + case 'f': if ((diagopts.logfile = fopen(arg, "a")) == NULL) { + Error2("cannot open log file \"%s\": %s", arg, strerror(errno)); + break; + } else { + diagopts.logstderr = false; break; + } + case 's': diagopts.logstderr = true; break; /* logging to stderr is default */ + case 'p': diagopts.progname = arg; + openlog(diagopts.progname, LOG_PID, diagopts.logfacility); + break; + case 'd': --diagopts.msglevel; break; + case 'u': diagopts.micros = true; break; + default: msg(E_ERROR, "unknown diagnostic option %c", what); + } +} + +void diag_set_int(char what, int arg) { + switch (what) { + case 'D': diagopts.msglevel = arg; break; + case 'e': diagopts.exitlevel = arg; break; + case 'x': diagopts.exitstatus = arg; break; + case 'h': diagopts.withhostname = arg; + if ((diagopts.hostname = getenv("HOSTNAME")) == NULL) { + struct utsname ubuf; + uname(&ubuf); + diagopts.hostname = strdup(ubuf.nodename); + } + break; + default: msg(E_ERROR, "unknown diagnostic option %c", what); + } +} + +int diag_get_int(char what) { + switch (what) { + case 'y': return diagopts.syslog; + case 's': return diagopts.logstderr; + case 'd': case 'D': return diagopts.msglevel; + case 'e': return diagopts.exitlevel; + } + return -1; +} + +const char *diag_get_string(char what) { + switch (what) { + case 'p': return diagopts.progname; + } + return NULL; +} + +/* Linux and AIX syslog format: +Oct 4 17:10:37 hostname socat[52798]: D signal(13, 1) +*/ +void msg(int level, const char *format, ...) { +#if HAVE_GETTIMEOFDAY || 1 + struct timeval now; + int result; + time_t nowt; +#else /* !HAVE_GETTIMEOFDAY */ + time_t now; +#endif /* !HAVE_GETTIMEOFDAY */ +#define BUFLEN 512 + char buff[BUFLEN], *bufp, *syslp; + size_t bytes; + va_list ap; + + if (level < diagopts.msglevel) return; + va_start(ap, format); +#if HAVE_GETTIMEOFDAY || 1 + result = gettimeofday(&now, NULL); + if (result < 0) { + /* invoking msg() might create endless recursion; by hand instead */ + sprintf(buff, "cannot read time: %s["F_pid"] E %s", + diagopts.progname, getpid(), strerror(errno)); + _msg(LOG_ERR, buff, strstr(buff, " E "+1)); + strcpy(buff, "unknown time "); bytes = 20; + } else { + nowt = now.tv_sec; +#if HAVE_STRFTIME + if (diagopts.micros) { + bytes = strftime(buff, 20, "%Y/%m/%d %H:%M:%S", localtime(&nowt)); + bytes += sprintf(buff+19, "."F_tv_usec" ", now.tv_usec); + } else { + bytes = + strftime(buff, 21, "%Y/%m/%d %H:%M:%S ", localtime(&nowt)); + } +#else + strcpy(buff, ctime(&nowt)); + bytes = strlen(buff); +#endif + } +#else /* !HAVE_GETTIMEOFDAY */ + now = time(NULL); if (now == (time_t)-1) { + /* invoking msg() might create endless recursion; by hand instead */ + sprintf(buff, "cannot read time: %s["F_pid"] E %s", + diagopts.progname, getpid(), strerror(errno)); + _msg(LOG_ERR, buff, strstr(buff, " E "+1)); + strcpy(buff, "unknown time "); bytes = 20; + } else { +#if HAVE_STRFTIME + bytes = strftime(buff, 21, "%Y/%m/%d %H:%M:%S ", localtime(&now)); +#else + strcpy(buff, ctime(&now)); + bytes = strlen(buff); +#endif + } +#endif /* !HAVE_GETTIMEOFDAY */ + bufp = buff + bytes; + if (diagopts.withhostname) { + bytes = sprintf(bufp, "%s ", diagopts.hostname), bufp+=bytes; + } + bytes = sprintf(bufp, "%s["F_pid"] ", diagopts.progname, getpid()); + bufp += bytes; + syslp = bufp; + *bufp++ = "DINWEF"[level]; + *bufp++ = ' '; + vsnprintf(bufp, BUFLEN-(bufp-buff)-1, format, ap); + strcat(bufp, "\n"); + _msg(level, buff, syslp); + if (level >= diagopts.exitlevel) { + va_end(ap); + if (E_NOTICE >= diagopts.msglevel) { + sprintf(syslp, "N exit(1)\n"); + _msg(E_NOTICE, buff, syslp); + } + exit(diagopts.exitstatus ? diagopts.exitstatus : 1); + } + va_end(ap); +} + + +static void _msg(int level, const char *buff, const char *syslp) { + if (diagopts.logstderr) { + fputs(buff, stderr); fflush(stderr); + } + if (diagopts.syslog) { + /* prevent format string attacks (thanks to CoKi) */ + syslog(syslevel[level], "%s", syslp); + } + if (diagopts.logfile) { + fputs(buff, diagopts.logfile); fflush(diagopts.logfile); + } +} diff --git a/error.h b/error.h new file mode 100644 index 0000000..72eb85b --- /dev/null +++ b/error.h @@ -0,0 +1,208 @@ +/* $Id: error.h,v 1.14 2007/03/06 21:19:18 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __error_h_included +#define __error_h_included 1 + +/* these must be defines because they are used by cpp! */ +#define E_DEBUG 0 /* all, including trace */ +#define E_INFO 1 /* all status changes etc. */ +#define E_NOTICE 2 /* all interesting, e.g. for firewall relay */ +#define E_WARN 3 /* all unusual */ +#define E_ERROR 4 /* errors */ +#define E_FATAL 5 /* emergency abort */ + + +/* here are the macros for diag invocation; use WITH_MSGLEVEL to specify the + lowest priority that is compiled into your program */ +#ifndef WITH_MSGLEVEL +# define WITH_MSGLEVEL E_NOTICE +#endif + +#if WITH_MSGLEVEL <= E_FATAL +#define Fatal(m) msg(E_FATAL,"%s",m) +#define Fatal1(m,a1) msg(E_FATAL,m,a1) +#define Fatal2(m,a1,a2) msg(E_FATAL,m,a1,a2) +#define Fatal3(m,a1,a2,a3) msg(E_FATAL,m,a1,a2,a3) +#define Fatal4(m,a1,a2,a3,a4) msg(E_FATAL,m,a1,a2,a3,a4) +#define Fatal5(m,a1,a2,a3,a4,a5) msg(E_FATAL,m,a1,a2,a3,a4,a5) +#define Fatal6(m,a1,a2,a3,a4,a5,a6) msg(E_FATAL,m,a1,a2,a3,a4,a5,a6) +#define Fatal7(m,a1,a2,a3,a4,a5,a6,a7) msg(E_FATAL,m,a1,a2,a3,a4,a5,a6,a7) +#else /* !(WITH_MSGLEVEL <= E_FATAL) */ +#define Fatal(m) +#define Fatal1(m,a1) +#define Fatal2(m,a1,a2) +#define Fatal3(m,a1,a2,a3) +#define Fatal4(m,a1,a2,a3,a4) +#define Fatal5(m,a1,a2,a3,a4,a5) +#define Fatal6(m,a1,a2,a3,a4,a5,a6) +#define Fatal7(m,a1,a2,a3,a4,a5,a6,a7) +#endif /* !(WITH_MSGLEVEL <= E_FATAL) */ + +#if WITH_MSGLEVEL <= E_ERROR +#define Error(m) msg(E_ERROR,"%s",m) +#define Error1(m,a1) msg(E_ERROR,m,a1) +#define Error2(m,a1,a2) msg(E_ERROR,m,a1,a2) +#define Error3(m,a1,a2,a3) msg(E_ERROR,m,a1,a2,a3) +#define Error4(m,a1,a2,a3,a4) msg(E_ERROR,m,a1,a2,a3,a4) +#define Error5(m,a1,a2,a3,a4,a5) msg(E_ERROR,m,a1,a2,a3,a4,a5) +#define Error6(m,a1,a2,a3,a4,a5,a6) msg(E_ERROR,m,a1,a2,a3,a4,a5,a6) +#define Error7(m,a1,a2,a3,a4,a5,a6,a7) msg(E_ERROR,m,a1,a2,a3,a4,a5,a6,a7) +#define Error8(m,a1,a2,a3,a4,a5,a6,a7,a8) msg(E_ERROR,m,a1,a2,a3,a4,a5,a6,a7,a8) +#else /* !(WITH_MSGLEVEL >= E_ERROR) */ +#define Error(m) +#define Error1(m,a1) +#define Error2(m,a1,a2) +#define Error3(m,a1,a2,a3) +#define Error4(m,a1,a2,a3,a4) +#define Error5(m,a1,a2,a3,a4,a5) +#define Error6(m,a1,a2,a3,a4,a5,a6) +#define Error7(m,a1,a2,a3,a4,a5,a6,a7) +#define Error8(m,a1,a2,a3,a4,a5,a6,a7,a8) +#endif /* !(WITH_MSGLEVEL <= E_ERROR) */ + +#if WITH_MSGLEVEL <= E_WARN +#define Warn(m) msg(E_WARN,"%s",m) +#define Warn1(m,a1) msg(E_WARN,m,a1) +#define Warn2(m,a1,a2) msg(E_WARN,m,a1,a2) +#define Warn3(m,a1,a2,a3) msg(E_WARN,m,a1,a2,a3) +#define Warn4(m,a1,a2,a3,a4) msg(E_WARN,m,a1,a2,a3,a4) +#define Warn5(m,a1,a2,a3,a4,a5) msg(E_WARN,m,a1,a2,a3,a4,a5) +#define Warn6(m,a1,a2,a3,a4,a5,a6) msg(E_WARN,m,a1,a2,a3,a4,a5,a6) +#define Warn7(m,a1,a2,a3,a4,a5,a6,a7) msg(E_WARN,m,a1,a2,a3,a4,a5,a6,a7) +#else /* !(WITH_MSGLEVEL <= E_WARN) */ +#define Warn(m) +#define Warn1(m,a1) +#define Warn2(m,a1,a2) +#define Warn3(m,a1,a2,a3) +#define Warn4(m,a1,a2,a3,a4) +#define Warn5(m,a1,a2,a3,a4,a5) +#define Warn6(m,a1,a2,a3,a4,a5,a6) +#define Warn7(m,a1,a2,a3,a4,a5,a6,a7) +#endif /* !(WITH_MSGLEVEL <= E_WARN) */ + +#if WITH_MSGLEVEL <= E_NOTICE +#define Notice(m) msg(E_NOTICE,"%s",m) +#define Notice1(m,a1) msg(E_NOTICE,m,a1) +#define Notice2(m,a1,a2) msg(E_NOTICE,m,a1,a2) +#define Notice3(m,a1,a2,a3) msg(E_NOTICE,m,a1,a2,a3) +#define Notice4(m,a1,a2,a3,a4) msg(E_NOTICE,m,a1,a2,a3,a4) +#define Notice5(m,a1,a2,a3,a4,a5) msg(E_NOTICE,m,a1,a2,a3,a4,a5) +#define Notice6(m,a1,a2,a3,a4,a5,a6) msg(E_NOTICE,m,a1,a2,a3,a4,a5,a6) +#define Notice7(m,a1,a2,a3,a4,a5,a6,a7) msg(E_NOTICE,m,a1,a2,a3,a4,a5,a6,a7) +#define Notice8(m,a1,a2,a3,a4,a5,a6,a7,a8) msg(E_NOTICE,m,a1,a2,a3,a4,a5,a6,a7,a8) +#define Notice9(m,a1,a2,a3,a4,a5,a6,a7,a8,a9) msg(E_NOTICE,m,a1,a2,a3,a4,a5,a6,a7,a8,a9) +#else /* !(WITH_MSGLEVEL <= E_NOTICE) */ +#define Notice(m) +#define Notice1(m,a1) +#define Notice2(m,a1,a2) +#define Notice3(m,a1,a2,a3) +#define Notice4(m,a1,a2,a3,a4) +#define Notice5(m,a1,a2,a3,a4,a5) +#define Notice6(m,a1,a2,a3,a4,a5,a6) +#define Notice7(m,a1,a2,a3,a4,a5,a6,a7) +#define Notice8(m,a1,a2,a3,a4,a5,a6,a7,a8) +#define Notice9(m,a1,a2,a3,a4,a5,a6,a7,a8,a9) +#endif /* !(WITH_MSGLEVEL <= E_NOTICE) */ + +#if WITH_MSGLEVEL <= E_INFO +#define Info(m) msg(E_INFO,"%s",m) +#define Info1(m,a1) msg(E_INFO,m,a1) +#define Info2(m,a1,a2) msg(E_INFO,m,a1,a2) +#define Info3(m,a1,a2,a3) msg(E_INFO,m,a1,a2,a3) +#define Info4(m,a1,a2,a3,a4) msg(E_INFO,m,a1,a2,a3,a4) +#define Info5(m,a1,a2,a3,a4,a5) msg(E_INFO,m,a1,a2,a3,a4,a5) +#define Info6(m,a1,a2,a3,a4,a5,a6) msg(E_INFO,m,a1,a2,a3,a4,a5,a6) +#define Info7(m,a1,a2,a3,a4,a5,a6,a7) msg(E_INFO,m,a1,a2,a3,a4,a5,a6,a7) +#define Info8(m,a1,a2,a3,a4,a5,a6,a7,a8) msg(E_INFO,m,a1,a2,a3,a4,a5,a6,a7,a8) +#define Info9(m,a1,a2,a3,a4,a5,a6,a7,a8,a9) msg(E_INFO,m,a1,a2,a3,a4,a5,a6,a7,a8,a9) +#define Info10(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) msg(E_INFO,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) +#define Info11(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) msg(E_INFO,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) +#else /* !(WITH_MSGLEVEL <= E_INFO) */ +#define Info(m) +#define Info1(m,a1) +#define Info2(m,a1,a2) +#define Info3(m,a1,a2,a3) +#define Info4(m,a1,a2,a3,a4) +#define Info5(m,a1,a2,a3,a4,a5) +#define Info6(m,a1,a2,a3,a4,a5,a6) +#define Info7(m,a1,a2,a3,a4,a5,a6,a7) +#define Info8(m,a1,a2,a3,a4,a5,a6,a7,a8) +#define Info9(m,a1,a2,a3,a4,a5,a6,a7,a8,a9) +#define Info10(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) +#define Info11(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) +#endif /* !(WITH_MSGLEVEL <= E_INFO) */ + +#if WITH_MSGLEVEL <= E_DEBUG +#define Debug(m) msg(E_DEBUG,"%s",m) +#define Debug1(m,a1) msg(E_DEBUG,m,a1) +#define Debug2(m,a1,a2) msg(E_DEBUG,m,a1,a2) +#define Debug3(m,a1,a2,a3) msg(E_DEBUG,m,a1,a2,a3) +#define Debug4(m,a1,a2,a3,a4) msg(E_DEBUG,m,a1,a2,a3,a4) +#define Debug5(m,a1,a2,a3,a4,a5) msg(E_DEBUG,m,a1,a2,a3,a4,a5) +#define Debug6(m,a1,a2,a3,a4,a5,a6) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6) +#define Debug7(m,a1,a2,a3,a4,a5,a6,a7) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7) +#define Debug8(m,a1,a2,a3,a4,a5,a6,a7,a8) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8) +#define Debug9(m,a1,a2,a3,a4,a5,a6,a7,a8,a9) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8,a9) +#define Debug10(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) +#define Debug11(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) +#define Debug12(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) +#define Debug13(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13) +#define Debug14(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14) +#define Debug15(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) +#define Debug16(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16) +#define Debug17(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17) +#define Debug18(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18) +#else /* !(WITH_MSGLEVEL <= E_DEBUG) */ +#define Debug(m) +#define Debug1(m,a1) +#define Debug2(m,a1,a2) +#define Debug3(m,a1,a2,a3) +#define Debug4(m,a1,a2,a3,a4) +#define Debug5(m,a1,a2,a3,a4,a5) +#define Debug6(m,a1,a2,a3,a4,a5,a6) +#define Debug7(m,a1,a2,a3,a4,a5,a6,a7) +#define Debug8(m,a1,a2,a3,a4,a5,a6,a7,a8) +#define Debug9(m,a1,a2,a3,a4,a5,a6,a7,a8,a9) +#define Debug10(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) +#define Debug11(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) +#define Debug12(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) +#define Debug13(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13) +#define Debug14(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14) +#define Debug15(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) +#define Debug16(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16) +#define Debug17(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17) +#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 */ +#if WITH_MSGLEVEL <= E_FATAL +#define Msg(l,m) msg(l,"%s",m) +#define Msg1(l,m,a1) msg(l,m,a1) +#define Msg2(l,m,a1,a2) msg(l,m,a1,a2) +#define Msg3(l,m,a1,a2,a3) msg(l,m,a1,a2,a3) +#define Msg4(l,m,a1,a2,a3,a4) msg(l,m,a1,a2,a3,a4) +#define Msg5(l,m,a1,a2,a3,a4,a5) msg(l,m,a1,a2,a3,a4,a5) +#define Msg6(l,m,a1,a2,a3,a4,a5,a6) msg(l,m,a1,a2,a3,a4,a5,a6) +#define Msg7(l,m,a1,a2,a3,a4,a5,a6,a7) msg(l,m,a1,a2,a3,a4,a5,a6,a7) +#else /* !(WITH_MSGLEVEL >= E_FATAL) */ +#define Msg(l,m) +#define Msg1(l,m,a1) +#define Msg2(l,m,a1,a2) +#define Msg3(l,m,a1,a2,a3) +#define Msg4(l,m,a1,a2,a3,a4) +#define Msg5(l,m,a1,a2,a3,a4,a5) +#define Msg6(l,m,a1,a2,a3,a4,a5,a6) +#define Msg7(l,m,a1,a2,a3,a4,a5,a6,a7) +#endif /* !(WITH_MSGLEVEL <= E_FATAL) */ + + +extern void diag_set(char what, const char *arg); +extern void diag_set_int(char what, int arg); +extern int diag_get_int(char what); +extern const char *diag_get_string(char what); + +extern void msg(int level, const char *format, ...); + +#endif /* !defined(__error_h_included) */ diff --git a/fdname.c b/fdname.c new file mode 100644 index 0000000..f48e736 --- /dev/null +++ b/fdname.c @@ -0,0 +1,327 @@ +/* $Id: fdname.c,v 1.9 2007/02/08 18:27:00 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2003-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* the subroutine sockname prints the basic info about the address of a socket + NOTE: it works on UNIX (kernel) file descriptors, not on libc files! */ + +#include "config.h" +#include "xioconfig.h" /* what features are enabled */ + +#include "sysincludes.h" + +#include "mytypes.h" +#include "compat.h" +#include "error.h" +#include "sycls.h" +#include "sysutils.h" + +#include "filan.h" + + +struct sockopt { + int so; + char *name; +}; + + +int statname(const char *file, int fd, int filetype, FILE *outfile); +int cdevname(int fd, FILE *outfile); +int sockname(int fd, FILE *outfile); +int unixame(int fd, FILE *outfile); +int tcpname(int fd, FILE *outfile); + + +int fdname(const char *file, int fd, FILE *outfile) { + struct stat buf = {0}; + int filetype; + Debug1("checking file descriptor %u", fd); + if (fd >= 0) { + if (Fstat(fd, &buf) < 0) { + if (errno == EBADF) { + Debug2("fstat(%d): %s", fd, strerror(errno)); + return -1; + } else { + Error2("fstat(%d): %s", fd, strerror(errno)); + } + } + filetype = (buf.st_mode&S_IFMT)>>12; + return statname(file, fd, filetype, outfile); + } else { + if (Stat(file, &buf) < 0) { + Error2("stat(\"%s\"): %s", file, strerror(errno)); + } + filetype = (buf.st_mode&S_IFMT)>>12; + return statname(file, -1, filetype, outfile); + } +} + +#if HAVE_PROC_DIR_FD +static int procgetfdname(int fd, char *filepath, size_t pathsize) { + static pid_t pid = -1; + char procpath[PATH_MAX]; + int len; + + /* even if configure has shown that we have /proc, we must check if it + exists at runtime, because we might be in a chroot environment */ +#if HAVE_STAT64 + { + struct stat64 buf; + if (Stat64("/proc", &buf) < 0) { + return -1; + } + if (!S_ISDIR(buf.st_mode)) { + return -1; + } + } +#else /* !HAVE_STAT64 */ + { + struct stat buf; + if (Stat("/proc", &buf) < 0) { + return -1; + } + if (!S_ISDIR(buf.st_mode)) { + return -1; + } + } +#endif /* !HAVE_STAT64 */ + + if (pid < 0) pid = Getpid(); + snprintf(procpath, sizeof(procpath), "/proc/"F_pid"/fd/%d", pid, fd); + if ((len = Readlink(procpath, filepath, pathsize-1)) < 0) { + Error4("readlink(\"%s\", %p, "F_Zu"): %s", + procpath, filepath, pathsize, strerror(errno)); + return -1; + } + filepath[len] = '\0'; + return 0; +} +#endif /* HAVE_PROC_DIR_FD */ + +int statname(const char *file, int fd, int filetype, FILE *outfile) { + char filepath[PATH_MAX]; + int result; + + filepath[0] = '\0'; +#if HAVE_PROC_DIR_FD + if (fd >= 0) { + procgetfdname(fd, filepath, sizeof(filepath)); + if (filepath[0] == '/') { + file = filepath; + } + } +#endif /* HAVE_PROC_DIR_FD */ + /* now see for type specific infos */ + switch (filetype) { + case (S_IFIFO>>12): /* 1, FIFO */ + fputs("pipe", outfile); + if (file) fprintf(outfile, " %s", file); + break; + case (S_IFCHR>>12): /* 2, character device */ + if (cdevname(fd, outfile) == 0) { + if (file) fprintf(outfile, " %s", file); + } + break; + case (S_IFDIR>>12): /* 4, directory */ + fputs("dir", outfile); + if (file) fprintf(outfile, " %s", file); + break; + case (S_IFBLK>>12): /* 6, block device */ + fputs("blkdev", outfile); + if (file) fprintf(outfile, " %s", file); + break; + case (S_IFREG>>12): /* 8, regular file */ + fputs("file", outfile); + if (file) fprintf(outfile, " %s", file); + break; + case (S_IFLNK>>12): /* 10, symbolic link */ + fputs("link", outfile); + if (file) fprintf(outfile, " %s", file); + break; + case (S_IFSOCK>>12): /* 12, socket */ +#if WITH_SOCKET + if (fd >= 0) { + result = sockname(fd, outfile); + } else if (file) { + fprintf(outfile, "socket %s", file); + } else { + fputs("socket", outfile); + } +#else + Error("SOCKET support not compiled in"); + return -1; +#endif /* !WITH_SOCKET */ + break; + } + /* ioctl() */ + fputc('\n', outfile); + + return 0; +} + + +/* character device analysis */ +/* return -1 on error, 0 if no name was found, or 1 if it printed ttyname */ +int cdevname(int fd, FILE *outfile) { + int ret; + + if ((ret = Isatty(fd)) < 0) { + Error2("isatty(%d): %s", fd, strerror(errno)); + return -1; + } + if (ret > 0) { + char *name; + + fputs("tty", outfile); + if ((name = Ttyname(fd)) != NULL) { + fputc(' ', outfile); + fputs(name, outfile); + return 1; + } + } else { + fputs("chrdev", outfile); + } + return 0; +} + + +#if WITH_SOCKET +int sockname(int fd, FILE *outfile) { +#define FDNAME_OPTLEN 256 +#define FDNAME_NAMELEN 256 + socklen_t optlen; + int opttype; +#ifdef SO_ACCEPTCONN + int optacceptconn; +#endif + int result /*0, i*/; + char namebuff[FDNAME_NAMELEN]; + char peerbuff[FDNAME_NAMELEN]; + /* in Linux these optcodes are 'enum', but on AIX they are bits! */ + union sockaddr_union sockname, peername; /* the longest I know of */ + socklen_t namelen; +#if 0 && defined(SIOCGIFNAME) + /*Linux struct ifreq ifc = {{{ 0 }}};*/ + struct ifreq ifc = {{ 0 }}; +#endif + + optlen = FDNAME_OPTLEN; + + Getsockopt(fd, SOL_SOCKET, SO_TYPE, &opttype, &optlen); +#ifdef SO_ACCEPTCONN + Getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &optacceptconn, &optlen); +#endif + + namelen = sizeof(sockname); + result = Getsockname(fd, &sockname.soa, &namelen); + if (result < 0) { + Error2("getsockname(%d): %s", fd, strerror(errno)); + return -1; + } + + namelen = sizeof(peername); + result = Getpeername(fd, (struct sockaddr *)&peername, &namelen); + if (result < 0) { + Error2("getpeername(%d): %s", fd, strerror(errno)); + } + + switch (sockname.soa.sa_family) { +#if WITH_UNIX + case AF_UNIX: + fprintf(outfile, "unix%s%s %s", + opttype==SOCK_DGRAM?"datagram":"", +#ifdef SO_ACCEPTCONN + optacceptconn?"(listening)": +#endif + "", + sockaddr_unix_info(&sockname.un, namelen, + namebuff, sizeof(namebuff))); + break; +#endif +#if WITH_IP4 + case AF_INET: + switch (opttype) { +#if WITH_TCP + case SOCK_STREAM: + fprintf(outfile, "tcp%s %s %s", +#ifdef SO_ACCEPTCONN + optacceptconn?"(listening)": +#endif + "", + sockaddr_inet4_info(&sockname.ip4, + namebuff, sizeof(namebuff)), + sockaddr_inet4_info(&peername.ip4, + peerbuff, sizeof(peerbuff))); + break; +#endif +#if WITH_UDP + case SOCK_DGRAM: + fprintf(outfile, "udp%s %s %s", +#ifdef SO_ACCEPTCONN + optacceptconn?"(listening)": +#endif + "", + sockaddr_inet4_info(&sockname.ip4, + namebuff, sizeof(namebuff)), + sockaddr_inet4_info(&peername.ip4, + peerbuff, sizeof(peerbuff))); + break; +#endif + default: + fprintf(outfile, "ip %s", + sockaddr_inet4_info(&sockname.ip4, + namebuff, sizeof(namebuff))); + break; + } + break; +#endif /* WITH_IP4 */ + +#if WITH_IP6 + case AF_INET6: + switch (opttype) { +#if WITH_TCP + case SOCK_STREAM: + fprintf(outfile, "tcp6%s %s %s", +#ifdef SO_ACCEPTCONN + optacceptconn?"(listening)": +#endif + "", + sockaddr_inet6_info(&sockname.ip6, + namebuff, sizeof(namebuff)), + sockaddr_inet6_info(&peername.ip6, + peerbuff, sizeof(peerbuff))); + break; +#endif +#if WITH_UDP + case SOCK_DGRAM: + fprintf(outfile, "udp6%s %s %s", +#ifdef SO_ACCEPTCONN + optacceptconn?"(listening)": +#endif + "", + sockaddr_inet6_info(&sockname.ip6, + namebuff, sizeof(namebuff)), + sockaddr_inet6_info(&peername.ip6, + peerbuff, sizeof(peerbuff))); + break; +#endif + default: + fprintf(outfile, "ip6 %s", + sockaddr_inet6_info(&sockname.ip6, + namebuff, sizeof(namebuff))); + break; + } +#endif /* WITH_IP6 */ + default: + fputs("socket", outfile); + } + + return result; +#undef FDNAME_OPTLEN +#undef FDNAME_NAMELEN +} +#endif /* WITH_SOCKET */ + + + + diff --git a/filan.c b/filan.c new file mode 100644 index 0000000..b486389 --- /dev/null +++ b/filan.c @@ -0,0 +1,918 @@ +/* $Id: filan.c,v 1.45 2007/02/08 19:42:34 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* the subroutine filan makes a "FILe descriptor ANalysis". It checks the + type of file descriptor and tries to retrieve as much info about it as + possible without modifying its state. + NOTE: it works on UNIX (kernel) file descriptors, not on libc files! */ + +#include "config.h" +#include "xioconfig.h" /* what features are enabled */ + +#include "sysincludes.h" + +#include "mytypes.h" +#include "compat.h" +#include "error.h" +#include "sycls.h" +#include "sysutils.h" + +#include "filan.h" + + +struct sockopt { + int so; + char *name; +}; + +/* dirty workaround so we dont get an error on AIX when getting linked with + libwrap */ +int allow_severity, deny_severity; + +/* global variables for configuring filan */ +bool filan_followsymlinks; +bool filan_rawoutput; + + +int sockoptan(int fd, const struct sockopt *optname, int socklay, FILE *outfile); +int tcpan(int fd, FILE *outfile); +const char *getfiletypestring(int st_mode); + +static int printtime(FILE *outfile, time_t time); + +static int headprinted; + +/* analyse a file system entry, referred by file name */ +int filan_file(const char *filename, FILE *outfile) { + int fd = -1; + int result; +#if HAVE_STAT64 + struct stat64 buf = {0}; +#else + struct stat buf = {0}; +#endif /* !HAVE_STAT64 */ + + if (filan_followsymlinks) { +#if HAVE_STAT64 + result = Stat64(filename, &buf); +#else + result = Stat(filename, &buf); +#endif /* !HAVE_STAT64 */ + if (result < 0) { + Warn3("stat(\"%s\", %p): %s", filename, &buf, strerror(errno)); + } + } else { +#if HAVE_STAT64 + result = Lstat64(filename, &buf); +#else + result = Lstat(filename, &buf); +#endif /* !HAVE_STAT64 */ + if (result < 0) { + Warn3("lstat(\"%s\", %p): %s", filename, &buf, strerror(errno)); + } + } + switch (buf.st_mode&S_IFMT) { +#ifdef S_IFSOCK + case S_IFSOCK: /* probably, it's useless to make a socket and describe it */ + break; +#endif /* S_IFSOCK */ + default: + if ((fd = + Open(filename, O_RDONLY|O_NOCTTY|O_NONBLOCK +#ifdef O_LARGEFILE + |O_LARGEFILE +#endif + , 0700)) + < 0) { + Warn2("open(\"%s\", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE, 0700): %s", + filename, strerror(errno)); + } + } + + result = filan_stat(&buf, fd, -1, outfile); + fputc('\n', outfile); + return result; +} + +/* analyze a file descriptor */ +int filan_fd(int fd, FILE *outfile) { +#if HAVE_STAT64 + struct stat64 buf = {0}; +#else + struct stat buf = {0}; +#endif /* !HAVE_STAT64 */ + int result; + + Debug1("checking file descriptor %u", fd); +#if HAVE_STAT64 + result = Fstat64(fd, &buf); +#else + result = Fstat(fd, &buf); +#endif /* !HAVE_STAT64 */ + if (result < 0) { + if (errno == EBADF) { + Debug2("fstat(%d): %s", fd, strerror(errno)); + } else { + Warn2("fstat(%d): %s", fd, strerror(errno)); + } + return -1; + } + Debug2("fd %d is a %s", fd, getfiletypestring(buf.st_mode)); + + result = filan_stat(&buf, fd, fd, outfile); + + if (result >= 0) { + /* even more dynamic info */ + { /* see if data is available */ + struct pollfd ufds; + ufds.fd = fd; + ufds.events = POLLIN|POLLPRI|POLLOUT|POLLRDNORM|POLLRDBAND|POLLWRNORM|POLLWRBAND +#ifdef POLLMSG + |POLLMSG +#endif + ; + if (Poll(&ufds, 1, 0) < 0) { + Warn4("poll({%d, %hd, %hd}, 1, 0): %s", + ufds.fd, ufds.events, ufds.revents, strerror(errno)); + } else { + fputs("poll: ", outfile); + if (ufds.revents & POLLIN) fputs("IN,", outfile); + if (ufds.revents & POLLPRI) fputs("PRI,", outfile); + if (ufds.revents & POLLOUT) fputs("OUT,", outfile); + if (ufds.revents & POLLERR) fputs("ERR,", outfile); + if (ufds.revents & POLLNVAL) fputs("NVAL,", outfile); +#ifdef FIONREAD + if (ufds.revents & POLLIN) { + size_t sizet; + if ((result = Ioctl(fd, FIONREAD, &sizet) >= 0)) { + fprintf (outfile, "; FIONREAD="F_Zu, sizet); + } + } +#endif /* defined(FIONREAD) */ +#if WITH_SOCKET && defined(MSG_DONTWAIT) + if ((ufds.revents & POLLIN) && isasocket(fd)) { + char _peername[SOCKADDR_MAX]; + struct sockaddr *pa = (struct sockaddr *)_peername; + struct msghdr msgh = {0}; + char peekbuff[1]; /* [0] fails with some compilers */ +#if HAVE_STRUCT_IOVEC + struct iovec iovec; +#endif + char ctrlbuff[5120]; + ssize_t bytes; + + fputs("; ", outfile); + msgh.msg_name = pa; + msgh.msg_namelen = sizeof(*pa); +#if HAVE_STRUCT_IOVEC + iovec.iov_base = peekbuff; + iovec.iov_len = sizeof(peekbuff); + msgh.msg_iov = &iovec; + msgh.msg_iovlen = 1; +#endif +#if HAVE_STRUCT_MSGHDR_MSGCONTROL + msgh.msg_control = ctrlbuff; +#endif +#if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN + msgh.msg_controllen = sizeof(ctrlbuff); +#endif +#if HAVE_STRUCT_MSGHDR_MSGFLAGS + msgh.msg_flags = 0; +#endif + if ((bytes = Recvmsg(fd, &msgh, MSG_PEEK|MSG_DONTWAIT)) < 0) { + Warn1("recvmsg(): %s", strerror(errno)); + } else { + fprintf(outfile, "recvmsg="F_Zd", ", bytes); + } + } +#endif /* WITH_SOCKET && defined(MSG_DONTWAIT) */ + } + } + } + fputc('\n', outfile); + return 0; +} + + +int filan_stat( +#if HAVE_STAT64 + struct stat64 *buf +#else + struct stat *buf +#endif /* !HAVE_STAT64 */ + , int statfd, int dynfd, FILE *outfile) { + char stdevstr[8]; + int result; + + /* print header */ + if (!headprinted) { + if (filan_rawoutput) { + fputs(" FD type\tdevice\tinode\tmode\tlinks\tuid\tgid" +#if HAVE_ST_RDEV + "\trdev" +#endif + "\tsize" +#if HAVE_ST_BLKSIZE + "\tblksize" +#endif +#if HAVE_ST_BLOCKS + "\tblocks" +#endif + "\tatime\t\tmtime\t\tctime\t\tcloexec\tflags" +#if defined(F_GETOWN) + "\tsigown" +#endif + , outfile); + } else /* !rawoutput */ { + fputs(" FD type\tdevice\tinode\tmode\tlinks\tuid\tgid" +#if HAVE_ST_RDEV + "\trdev" +#endif + "\tsize" +#if HAVE_ST_BLKSIZE + "\tblksize" +#endif +#if HAVE_ST_BLOCKS + "\tblocks" +#endif + "\tatime\t\t\t\tmtime\t\t\t\tctime\t\t\t\tcloexec\tflags" +#if defined(F_GETOWN) + "\tsigown" +#endif + , outfile); + + } /* endif !rawoutput */ + +#if defined(F_GETSIG) + fputs("\tsigio", outfile); +#endif /* defined(F_GETSIG) */ + fputc('\n', outfile); + headprinted = 1; + } + if (filan_rawoutput) { + snprintf(stdevstr, 8, F_st_dev, buf->st_dev); + } else { + snprintf(stdevstr, 8, "%hu,%hu", (unsigned short)buf->st_dev>>8, (unsigned short)buf->st_dev&0xff); + } + fprintf(outfile, "%4d: %s\t%s\t" +#if HAVE_STAT64 + F_st64_ino +#else + F_st_ino +#endif /* HAVE_STAT64 */ + "\t"F_mode"\t"F_st_nlink"\t"F_uid"\t"F_gid +#if HAVE_ST_RDEV + "\t%hu,%hu" +#endif + "\t" +#if HAVE_STAT64 + F_st64_size +#else + F_st_size +#endif /* HAVE_STAT64 */ +#if HAVE_ST_BLKSIZE + "\t"F_st_blksize +#endif +#if HAVE_ST_BLOCKS +#if HAVE_STAT64 + "\t"F_st64_blocks +#else + "\t"F_st_blocks +#endif /* HAVE_STAT64 */ +#endif + , + (dynfd>=0?dynfd:statfd), getfiletypestring(buf->st_mode), + stdevstr, + buf->st_ino, + buf->st_mode, buf->st_nlink, buf->st_uid, + buf->st_gid, +#if HAVE_ST_RDEV + (unsigned short)buf->st_rdev>>8, (unsigned short)buf->st_rdev&0xff, +#endif + buf->st_size +#if HAVE_ST_BLKSIZE + , buf->st_blksize +#endif +#if HAVE_ST_BLOCKS + , buf->st_blocks /* on Linux, this applies to stat and stat64 */ +#endif + ); + + printtime(outfile, buf->st_atime); + printtime(outfile, buf->st_mtime); + printtime(outfile, buf->st_ctime); + +#if 0 + { + fputc('\t', outfile); + time = asctime(localtime(&buf->st_mtime)); + if (strchr(time, '\n')) *strchr(time, '\n') = '\0'; + fputs(time, outfile); + + fputc('\t', outfile); + time = asctime(localtime(&buf->st_ctime)); + if (strchr(time, '\n')) *strchr(time, '\n') = '\0'; + fputs(time, outfile); + } +#endif + + /* here comes dynamic info - it is only meaningful with preexisting FDs */ + if (dynfd >= 0) { /*!indent */ + int cloexec, flags; +#if defined(F_GETOWN) + int sigown; +#endif +#if defined(F_GETSIG) + int sigio; +#endif /* defined(F_GETSIG) */ + + cloexec = Fcntl(dynfd, F_GETFD); + flags = Fcntl(dynfd, F_GETFL); +#if defined(F_GETOWN) + sigown = Fcntl(dynfd, F_GETOWN); +#endif +#if defined(F_GETSIG) + sigio = Fcntl(dynfd, F_GETSIG); +#endif /* defined(F_GETSIG) */ + fprintf(outfile, "\t%d\tx%06x", cloexec, flags); +#if defined(F_GETOWN) + fprintf(outfile, "\t%d", sigown); +#endif +#if defined(F_GETSIG) + fprintf(outfile, "\t%d", sigio); +#endif /* defined(F_GETSIG) */ + } else { + fputs("\t\t" +#if defined(F_GETOWN) + "\t" +#endif +#if defined(F_GETSIG) + "\t" +#endif /* defined(F_GETSIG) */ + , outfile); + } + + /* now see for type specific infos */ + if (statfd >= 0) { /*!indent */ + switch (buf->st_mode&S_IFMT) { + case (S_IFIFO): /* 1, FIFO */ + break; + case (S_IFCHR): /* 2, character device */ + result = cdevan(statfd, outfile); + break; + case (S_IFDIR): /* 4, directory */ + break; + case (S_IFBLK): /* 6, block device */ + break; + case (S_IFREG): /* 8, regular file */ + break; + case (S_IFLNK): /* 10, symbolic link */ + break; +#ifdef S_IFSOCK + case (S_IFSOCK): /* 12, socket */ +#if WITH_SOCKET + result = sockan(statfd, outfile); +#else + Warn("SOCKET support not compiled in"); + return -1; +#endif /* !WITH_SOCKET */ + break; +#endif /* S_IFSOCK */ + } + } + /* ioctl() */ + return 0; +} + + +#if LATER +int fdinfo(int fd) { + int result; + + result = Fcntl(fd, F_GETFD); + fcntl(fd, F_GETFL, ); + fcntl(fd, F_GETLK, ); +#ifdef F_GETOWN + fcntl(fd, F_GETOWN, ); +#endif +#ifdef F_GETSIG + fcntl(fd, F_GETSIG, ); +#endif +} + + +int devinfo(int fd) { + ioctl(); +} +#endif + + +/* character device analysis */ +int cdevan(int fd, FILE *outfile) { + int ret; + + if ((ret = Isatty(fd)) < 0) { + Warn2("isatty(%d): %s", fd, strerror(errno)); + return -1; + } + if (ret > 0) { + struct termios termarg; + char *name; + int i; + + if ((name = Ttyname(fd)) == NULL) { + /*Warn2("ttyname(%d): %s", fd, strerror(errno));*/ + fputs("\tNULL", outfile); + } else { + fprintf(outfile, "\t%s", name); + } + if (Tcgetattr(fd, &termarg) < 0) { + Warn3("tcgetattr(%d, %p): %s", fd, &termarg, strerror(errno)); + return -1; + } + fprintf(outfile, " \tIFLAGS=%08x OFLAGS=%08x CFLAGS=%08x LFLAGS=%08x", + termarg.c_iflag, termarg.c_oflag, termarg.c_cflag, termarg.c_lflag); + + /* and the control characters */ + if (filan_rawoutput) { + for (i=0; i>4)>=10?(ch>>4)-10+'A':(ch>>4)+'0'; + s[2] = (ch&0x0f)>=10?(ch&0x0f)-10+'A':(ch&0x0f)+'0'; + s[3] = '\0'; + } + fprintf(outfile, " cc[%d]=%s", i, s); + } + } + } + return 0; +} + + +#if WITH_SOCKET +int sockan(int fd, FILE *outfile) { +#define FILAN_OPTLEN 256 +#define FILAN_NAMELEN 256 + socklen_t optlen; + int result /*0, i*/; + static const char *socktypes[] = { + "undef", "STREAM", "DGRAM", "RAW", "RDM", + "SEQPACKET", "undef", "undef", "undef", "undef", + "PACKET", "undef" } ; + char nambuff[FILAN_NAMELEN]; + /* in Linux these optcodes are 'enum', but on AIX they are bits! */ + static const struct sockopt sockopts[] = { + {SO_DEBUG, "DEBUG"}, + {SO_REUSEADDR, "REUSEADDR"}, + {SO_TYPE, "TYPE"}, + {SO_ERROR, "ERROR"}, + {SO_DONTROUTE, "DONTROUTE"}, + {SO_BROADCAST, "BROADCAST"}, + {SO_SNDBUF, "SNDBUF"}, + {SO_RCVBUF, "RCVBUF"}, + {SO_KEEPALIVE, "KEEPALIVE"}, + {SO_OOBINLINE, "OOBINLINE"}, +#ifdef SO_NO_CHECK + {SO_NO_CHECK, "NO_CHECK"}, +#endif +#ifdef SO_PRIORITY + {SO_PRIORITY, "PRIORITY"}, +#endif + {SO_LINGER, "LINGER"}, +#ifdef SO_BSDCOMPAT + {SO_BSDCOMPAT, "BSDCOMPAT"}, +#endif +#ifdef SO_REUSEPORT + {SO_REUSEPORT, "REUSEPORT"}, +#endif /* defined(SO_REUSEPORT) */ +#ifdef SO_PASSCRED + {SO_PASSCRED, "PASSCRED"}, +#endif +#ifdef SO_PEERCRED + {SO_PEERCRED, "PEERCRED"}, +#endif +#ifdef SO_RCVLOWAT + {SO_RCVLOWAT, "RCVLOWAT"}, +#endif +#ifdef SO_SNDLOWAT + {SO_SNDLOWAT, "SNDLOWAT"}, +#endif +#ifdef SO_RCVTIMEO + {SO_RCVTIMEO, "RCVTIMEO"}, +#endif +#ifdef SO_SNDTIMEO + {SO_SNDTIMEO, "SNDTIMEO"}, +#endif +#ifdef SO_SECURITY_AUTHENTICATION + {SO_SECURITY_AUTHENTICATION, "SECURITY_AUTHENTICATION"}, +#endif +#ifdef SO_SECURITY_ENCRYPTION_TRANSPORT + {SO_SECURITY_ENCRYPTION_TRANSPORT, "SECURITY_ENCRYPTION_TRANSPORT"}, +#endif +#ifdef SO_SECURITY_ENCRYPTION_NETWORK + {SO_SECURITY_ENCRYPTION_NETWORK, "SECURITY_ENCRYPTION_NETWORK"}, +#endif +#ifdef SO_BINDTODEVICE + {SO_BINDTODEVICE, "BINDTODEVICE"}, +#endif +#ifdef SO_ATTACH_FILTER + {SO_ATTACH_FILTER, "ATTACH_FILTER"}, +#endif +#ifdef SO_DETACH_FILTER + {SO_DETACH_FILTER, "DETACH_FILTER"}, +#endif + {0, NULL} } ; + char optval[FILAN_OPTLEN]; + const struct sockopt *optname; + union sockaddr_union sockname, peername; /* the longest I know of */ + socklen_t namelen; +#if 0 && defined(SIOCGIFNAME) + /*Linux struct ifreq ifc = {{{ 0 }}};*/ + struct ifreq ifc = {{ 0 }}; +#endif + + optlen = FILAN_OPTLEN; + result = Getsockopt(fd, SOL_SOCKET, SO_TYPE, optval, &optlen); + if (result < 0) { + Debug4("getsockopt(%d, SOL_SOCKET, SO_TYPE, %p, {"F_socklen"}): %s", + fd, optval, optlen, strerror(errno)); + } else { + Debug3("fd %d: socket of type %d (\"%s\")", fd, *(int *)optval, + socktypes[*(int *)optval]); + } + + optname = sockopts; while (optname->so) { + optlen = FILAN_OPTLEN; + result = + Getsockopt(fd, SOL_SOCKET, optname->so, (void *)optval, &optlen); + if (result < 0) { + Debug5("getsockopt(%d, SOL_SOCKET, %d, %p, {"F_socklen"}): %s", + fd, optname->so, optval, optlen, strerror(errno)); + fputc('\t', outfile); + } else if (optlen == sizeof(int)) { + Debug2("getsockopt(,,, {%d}, %d)", + *(int *)optval, optlen); + /*Info2("%s: %d", optname->name, *(int *)optval);*/ + fprintf(outfile, "%s=%d\t", optname->name, *(int *)optval); + } else { + Debug3("getsockopt(,,, {%d,%d}, %d)", + ((int *)optval)[0], ((int *)optval)[1], optlen); + fprintf(outfile, "%s={%d,%d}\t", optname->name, + ((int *)optval)[0], ((int *)optval)[1]); + } + ++optname; + } + + namelen = sizeof(sockname); + result = Getsockname(fd, (struct sockaddr *)&sockname, &namelen); + if (result < 0) { + putc('\n', outfile); + Warn2("getsockname(%d): %s", fd, strerror(errno)); + return -1; + } + fputc('\t', outfile); + fputs(sockaddr_info((struct sockaddr *)&sockname, namelen, nambuff, sizeof(nambuff)), + outfile); + + namelen = sizeof(peername); + result = Getpeername(fd, (struct sockaddr *)&peername, &namelen); + if (result < 0) { + putc('\n', outfile); + Warn2("getpeername(%d): %s", fd, strerror(errno)); + } else { + /* only valid if getpeername() succeeded */ + fputs(" <-> ", outfile); + fprintf(outfile, "%s\t", + sockaddr_info((struct sockaddr *)&peername, namelen, + nambuff, sizeof(nambuff))); + } + +#if 0 && defined(SIOCGIFNAME) + if ((result = Ioctl(fd, SIOCGIFNAME, &ifc)) < 0) { + Warn3("ioctl(%d, SIOCGIFNAME, %p): %s", fd, &ifc, strerror(errno)); + } else { + fprintf(outfile, "IFNAME=\"%s\"\t", ifc.ifr_name); + } +#endif /* SIOCGIFNAME */ + + switch (((struct sockaddr *)&sockname)->sa_family) { +#if WITH_UNIX + case AF_UNIX: + /* no options for unix domain sockets known yet -> no unixan() */ + result = 0; + break; +#endif +#if WITH_IP4 + case AF_INET: + result = ipan(fd, outfile); + break; +#endif +#if WITH_IP6 + case AF_INET6: + result = ipan(fd, outfile); + result |= ip6an(fd, outfile); + break; +#endif + default: + fputs("**** NO FURTHER ANALYSIS FOR THIS SOCKET TYPE IMPLEMENTED", outfile); + result = 0; + } + return result; +#undef FILAN_OPTLEN +#undef FILAN_NAMELEN +} +#endif /* WITH_SOCKET */ + + +#if WITH_IP4 || WITH_IP6 +/* prints the option values for the IP protocol and the IP based protocols */ +/* no distinction between IP4 and IP6 yet */ +int ipan(int fd, FILE *outfile) { + /* in Linux these optcodes are 'enum', but on AIX they are bits! */ + static const struct sockopt ipopts[] = { + {IP_TOS, "IP_TOS"}, + {IP_TTL, "IP_TTL"}, +#ifdef IP_HDRINCL + {IP_HDRINCL, "IP_HDRINCL"}, +#endif +#ifdef IP_OPTIONS + {IP_OPTIONS, "IP_OPTIONS"}, +#endif +#ifdef IP_ROUTER_ALERT + {IP_ROUTER_ALERT, "IP_ROUTER_ALERT"}, +#endif +#ifdef IP_RECVOPTS + {IP_RECVOPTS, "IP_RECVOPTS"}, +#endif +#ifdef IP_RETOPTS + {IP_RETOPTS, "IP_RETOPTS"}, +#endif +#ifdef IP_PKTINFO + {IP_PKTINFO, "IP_PKTINFO"}, +#endif +#ifdef IP_PKTOPTIONS + {IP_PKTOPTIONS, "IP_PKTOPTIONS"}, +#endif +#ifdef IP_MTU_DISCOVER + {IP_MTU_DISCOVER, "IP_MTU_DISCOVER"}, +#endif +#ifdef IP_RECVERR + {IP_RECVERR, "IP_RECVERR"}, +#endif +#ifdef IP_RECVTTL + {IP_RECVTTL, "IP_RECVTTL"}, +#endif +#ifdef IP_RECVTOS + {IP_RECVTOS, "IP_RECVTOS"}, +#endif +#ifdef IP_MTU + {IP_MTU, "IP_MTU"}, +#endif +#ifdef IP_FREEBIND + {IP_FREEBIND, "IP_FREEBIND"}, +#endif +#ifdef IP_MULTICAST_TTL + {IP_MULTICAST_TTL, "IP_MULTICAST_TTL"}, +#endif +#ifdef IP_MULTICAST_LOOP + {IP_MULTICAST_LOOP, "IP_MULTICAST_LOOP"}, +#endif + {0, NULL} } ; + const struct sockopt *optname; + int opttype; + socklen_t optlen = sizeof(opttype); + + optname = ipopts; while (optname->so) { + sockoptan(fd, optname, SOL_IP, outfile); + ++optname; + } + /* want to pass the fd to the next layer protocol. dont know how to get the + protocol number from the fd? use TYPE to identify TCP. */ + if (Getsockopt(fd, SOL_SOCKET, SO_TYPE, &opttype, &optlen) >= 0) { + switch (opttype) { +#if WITH_TCP + case SOCK_STREAM: tcpan(fd, outfile); break; +#endif + } + } + return 0; +} +#endif /* WITH_IP */ + + +#if WITH_IP6 +/* prints the option values for the IPv6 protocol */ +int ip6an(int fd, FILE *outfile) { + static const struct sockopt ip6opts[] = { +#ifdef IPV6_V6ONLY + {IPV6_V6ONLY, "IPV6_V6ONLY"}, +#endif + {0, NULL} } ; + const struct sockopt *optname; + + optname = ip6opts; while (optname->so) { + sockoptan(fd, optname, SOL_IPV6, outfile); + ++optname; + } + return 0; +} +#endif /* WITH_IP6 */ + + +#if WITH_TCP +int tcpan(int fd, FILE *outfile) { + static const struct sockopt tcpopts[] = { +#ifdef TCP_NODELAY + { TCP_NODELAY, "TCP_NODELAY" }, +#endif +#ifdef TCP_MAXSEG + { TCP_MAXSEG, "TCP_MAXSEG" }, +#endif +#ifdef TCP_STDURG + { TCP_STDURG, "TCP_STDURG" }, +#endif +#ifdef TCP_RFC1323 + { TCP_RFC1323, "TCP_RFC1323" }, +#endif +#ifdef TCP_CORK + { TCP_CORK, "TCP_CORK" }, +#endif +#ifdef TCP_KEEPIDLE + { TCP_KEEPIDLE, "TCP_KEEPIDLE" }, +#endif +#ifdef TCP_KEEPINTVL + { TCP_KEEPINTVL, "TCP_KEEPINTVL" }, +#endif +#ifdef TCP_KEEPCNT + { TCP_KEEPCNT, "TCP_KEEPCNT" }, +#endif +#ifdef TCP_SYNCNT + { TCP_SYNCNT, "TCP_SYNCNT" }, +#endif +#ifdef TCP_LINGER2 + { TCP_LINGER2, "TCP_LINGER2" }, +#endif +#ifdef TCP_DEFER_ACCEPT + { TCP_DEFER_ACCEPT, "TCP_ACCEPT" }, +#endif +#ifdef TCP_WINDOW_CLAMP + { TCP_WINDOW_CLAMP, "TCP_WINDOW_CLAMP" }, +#endif +#ifdef TCP_INFO + { TCP_INFO, "TCP_INFO" }, +#endif +#ifdef TCP_QUICKACK + { TCP_QUICKACK, "TCP_QUICKACK" }, +#endif +#ifdef TCP_MD5SIG + { TCP_MD5SIG, "TCP_MD5SIG" }, +#endif +#ifdef TCP_NOOPT + { TCP_NOOPT, "TCP_NOOPT" }, +#endif +#ifdef TCP_NOPUSH + { TCP_NOPUSH, "TCP_NOPUSH" }, +#endif +#ifdef TCP_SACK_DISABLE + { TCP_SACK_DISABLE, "TCP_SACK_DISABLE" }, +#endif +#ifdef TCP_SIGNATURE_ENABLE + { TCP_SIGNATURE_ENABLE, "TCP_SIGNATURE_ENABLE" }, +#endif +#ifdef TCP_ABORT_THRESHOLD + { TCP_ABORT_THRESHOLD, "TCP_ABORT_THRESHOLD" }, +#endif +#ifdef TCP_CONN_ABORT_THRESHOLD + { TCP_CONN_ABORT_THRESHOLD, "TCP_CONN_ABORT_THRESHOLD" }, +#endif +#ifdef TCP_KEEPINIT + { TCP_KEEPINIT, "TCP_KEEPINIT" }, +#endif +#ifdef TCP_PAWS + { TCP_PAWS, "TCP_PAWS" }, +#endif +#ifdef TCP_SACKENA + { TCP_SACKENA, "TCP_SACKENA" }, +#endif +#ifdef TCP_TSOPTENA + { TCP_TSOPTENA, "TCP_TSOPTENA" }, +#endif + {0, NULL} + } ; + const struct sockopt *optname; + + optname = tcpopts; while (optname->so) { + sockoptan(fd, optname, SOL_TCP, outfile); + ++optname; + } + return 0; +} +#endif /* WITH_TCP */ + + +#if WITH_SOCKET +int sockoptan(int fd, const struct sockopt *optname, int socklay, FILE *outfile) { +#define FILAN_OPTLEN 256 + char optval[FILAN_OPTLEN]; + socklen_t optlen; + int result; + + optlen = FILAN_OPTLEN; + result = + Getsockopt(fd, socklay, optname->so, (void *)optval, &optlen); + if (result < 0) { + Debug6("getsockopt(%d, %d, %d, %p, {"F_socklen"}): %s", + fd, socklay, optname->so, optval, optlen, strerror(errno)); + fputc('\t', outfile); + return -1; + } else if (optlen == 0) { + Debug1("getsockopt(,,, {}, %d)", optlen); + fprintf(outfile, "%s=\"\"\t", optname->name); + } else if (optlen == sizeof(int)) { + Debug2("getsockopt(,,, {%d}, %d)", + *(int *)optval, optlen); + fprintf(outfile, "%s=%d\t", optname->name, *(int *)optval); + } else { + char outbuf[FILAN_OPTLEN*9+128], *cp = outbuf; + int i; + for (i = 0; i < optlen/sizeof(unsigned int); ++i) { + cp += sprintf(cp, "%08x ", ((unsigned int *)optval)[i]); + } + *--cp = '\0'; /* delete trailing space */ + Debug2("getsockopt(,,, {%s}, %d)", outbuf, optlen); + fflush(outfile); + fprintf(outfile, "%s={%s}\t", optname->name, outbuf); + } + return 0; +#undef FILAN_OPTLEN +} +#endif /* WITH_SOCKET */ + + +#if WITH_SOCKET +int isasocket(int fd) { + int retval; +#if HAVE_STAT64 + struct stat64 props; +#else + struct stat props; +#endif /* HAVE_STAT64 */ + retval = +#if HAVE_STAT64 + Fstat64(fd, &props); +#else + Fstat(fd, &props); +#endif + if (retval < 0) { + Info3("fstat(%d, %p): %s", fd, &props, strerror(errno)); + return 0; + } + /* note: when S_ISSOCK was undefined, it always gives 0 */ + return S_ISSOCK(props.st_mode); +} +#endif /* WITH_SOCKET */ + + +const char *getfiletypestring(int st_mode) { + const char *s; + + switch (st_mode&S_IFMT) { + case S_IFIFO: s = "pipe"; break; + case S_IFCHR: s = "chrdev"; break; + case S_IFDIR: s = "dir"; break; + case S_IFBLK: s = "blkdev"; break; + case S_IFREG: s = "file"; break; + case S_IFLNK: s = "symlink"; break; + case S_IFSOCK: s = "socket"; break; + /*! AIX: MT? */ + default: s = "undef"; break; + } + return s; +} + +static int printtime(FILE *outfile, time_t time) { + const char *s; + + if (filan_rawoutput) { + fprintf(outfile, "\t"F_time, time); + } else { + fputc('\t', outfile); + s = asctime(localtime(&time)); + if (strchr(s, '\n')) *strchr(s, '\n') = '\0'; + fputs(s, outfile); + } + return 0; +} diff --git a/filan.h b/filan.h new file mode 100644 index 0000000..604ab03 --- /dev/null +++ b/filan.h @@ -0,0 +1,38 @@ +/* $Id: filan.h,v 1.8 2007/03/06 21:19:18 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ + +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __filan_h_included +#define __filan_h_included 1 + +struct sockaddr; /* prevent gcc from spitting silly warning */ +struct sockaddr_un; /* prevent gcc from spitting silly warning */ +struct sockaddr_in; /* prevent gcc from spitting silly warning */ +struct sockaddr_in6; /* prevent gcc from spitting silly warning */ + +extern bool filan_followsymlinks; +extern bool filan_rawoutput; + +extern int filan_file(const char *filename, FILE *outfile); +extern int filan_fd(int fd, FILE *outfile); +extern int filan_stat( +#if HAVE_STAT64 + struct stat64 *buf +#else + struct stat *buf +#endif /* !HAVE_STAT64 */ + , int statfd, int dynfd, FILE *outfile); + +extern int cdevan(int fd, FILE *outfile); + +#if WITH_SOCKET +extern int isasocket(int fd); +extern int sockan(int fd, FILE *outfile); +extern int ipan(int fd, FILE *outfile); +extern int ip6an(int fd, FILE *outfile); +#endif /* WITH_SOCKET */ + +extern int fdname(const char *file, int fd, FILE *outfile); + +#endif /* !defined(__filan_h_included) */ diff --git a/filan_main.c b/filan_main.c new file mode 100644 index 0000000..1231263 --- /dev/null +++ b/filan_main.c @@ -0,0 +1,240 @@ +/* $Id: filan_main.c,v 1.19 2006/07/12 21:59:15 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +const char copyright[] = "filan by Gerhard Rieger - see http://www.dest-unreach.org/socat/"; + +#include "config.h" +#include "xioconfig.h" +#include "sysincludes.h" + +#include "mytypes.h" +#include "compat.h" +#include "error.h" +#include "sycls.h" +#include "filan.h" + + +#define WITH_HELP 1 + +static void filan_usage(FILE *fd); + + +int main(int argc, const char *argv[]) { + const char **arg1, *a; + const char *filename = NULL, *waittimetxt; + unsigned int m = 0, n = 1024; /* this is default on my Linux */ + unsigned int i; + int style = 0; + struct timespec waittime = { 0, 0 }; + FILE *fdout = stdout; + const char *outfname = NULL; + unsigned long fildes; + + diag_set('p', strchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]); + + arg1 = argv+1; --argc; + while (arg1[0] && (arg1[0][0] == '-')) { + switch (arg1[0][1]) { +#if WITH_HELP + case '?': case 'h': + filan_usage(stdout); exit(0); +#endif +#if LATER + case 'V': filan_version(stdout); exit(0); +#endif + case 'L': filan_followsymlinks = true; break; + case 'd': diag_set('d', NULL); break; + case 's': style = 1; break; + case 'r': filan_rawoutput = true; break; + case 'i': if (arg1[0][2]) { + a = *arg1+2; + } else { + ++arg1, --argc; + if ((a = *arg1) == NULL) { + Error("option -i requires an argument"); + filan_usage(stderr); exit(1); + } + } + m = strtoul(a, (char **)&a, 0); + n = m+1; + break; + case 'n': if (arg1[0][2]) { + a = *arg1+2; + } else { + ++arg1, --argc; + if ((a = *arg1) == NULL) { + Error("option -n requires an argument"); + filan_usage(stderr); exit(1); + } + } + n = strtoul(a, (char **)&a, 0); + break; + case 'f': if (arg1[0][2]) { + filename = *arg1+2; + } else { + ++arg1, --argc; + if ((filename = *arg1) == NULL) { + Error("option -f requires an argument"); + filan_usage(stderr); exit(1); + } + } + break; + case 'T': if (arg1[0][2]) { + waittimetxt = *arg1+2; + } else { + ++arg1, --argc; + if ((waittimetxt = *arg1) == NULL) { + Error("option -T requires an argument"); + filan_usage(stderr); exit(1); + } + } + { + double waittimedbl; + waittimedbl = strtod(waittimetxt, NULL); + waittime.tv_sec = waittimedbl; + waittime.tv_nsec = (waittimedbl-waittime.tv_sec) * 1000000000; + } + break; + case 'o': if (arg1[0][2]) { + outfname = *arg1+2; + } else { + ++arg1, --argc; + if ((outfname = *arg1) == NULL) { + Error("option -o requires an argument"); + filan_usage(stderr); exit(1); + } + } + break; + case '\0': break; + default: + diag_set_int('e', E_FATAL); + Error1("unknown option %s", arg1[0]); +#if WITH_HELP + filan_usage(stderr); +#endif + exit(1); + } +#if 0 + if (arg1[0][1] == '\0') + break; +#endif + ++arg1; --argc; + } + if (argc != 0) { + Error1("%d superfluous arguments", argc); + filan_usage(stderr); + exit(1); + } + if (outfname) { + // special cases + if (!strcmp(outfname,"stdin")) { fdout=stdin; } + else if (!strcmp(outfname,"stdout")) { fdout=stdout; } + else if (!strcmp(outfname,"stderr")) { fdout=stderr; } + // file descriptor + else if (*outfname == '+') { + a = outfname+1; + fildes = strtoul(a, (char **)&a, 0); + if ((fdout = fdopen(fildes, "w")) == NULL) { + Error2("can't fdopen file descriptor %lu: %s\n", fildes, strerror(errno)); + exit(1); + } + } else { + // file name + if ((fdout = fopen(outfname, "w")) == NULL) { + Error2("can't fopen '%s': %s\n", + outfname, strerror(errno)); + exit(1); + } + } + } + + Nanosleep(&waittime, NULL); + + if (style == 0) { + /* this style gives detailled infos, but requires a file descriptor */ + if (filename) { +#if LATER /* this is just in case that S_ISSOCK does not work */ + struct stat buf; + int fd; + + if (Stat(filename, &buf) < 0) { + Error3("stat(\"%s\", %p): %s", filename, &buf, strerror(errno)); + } + /* note: when S_ISSOCK was undefined, it always gives 0 */ + if (S_ISSOCK(buf.st_mode)) { + Error("cannot analyze UNIX domain socket"); + } +#endif + filan_file(filename, fdout); + } else { + for (i = m; i < n; ++i) { + filan_fd(i, fdout); + } + } + } else { + /* this style gives only type and path / socket addresses, and works from + file descriptor or filename (with restrictions) */ + if (filename) { + /* filename: NULL means yet unknown; "" means no name at all */ +#if LATER + int fd; + if ((fd = + Open(filename, O_RDONLY|O_NOCTTY|O_NONBLOCK +#ifdef O_LARGEFILE + |O_LARGEFILE +#endif + , 0700)) + < 0) { + Debug2("open(\"%s\", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE, 0700): %s", + filename, strerror(errno)); + } + fdname(filename, fd, fdout); +#endif + fdname(filename, -1, fdout); + } else { + for (i = m; i < n; ++i) { + fdname("", i, fdout); + } + } + } + if (outfname && fdout != stdout && fdout != stderr) { + fclose(fdout); + } + return 0; +} + + +#if WITH_HELP +static void filan_usage(FILE *fd) { + fputs(copyright, fd); fputc('\n', fd); + fputs("Analyze file descriptors of the process\n", fd); + fputs("Usage:\n", fd); + fputs("filan [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 this help text\n", fd); + fputs(" -d increase verbosity (use up to 4 times)\n", fd); +#endif +#if 0 + fputs(" -ly[facility] log to syslog, using facility (default is daemon)\n", fd); + fputs(" -lf log to file\n", fd); + fputs(" -ls log to stderr (default if no other log)\n", fd); +#endif + fputs(" -i only analyze this fd\n", fd); + fputs(" -n analyze all fds from 0 up to fdnum-1 (default: 1024)\n", fd); + fputs(" -s simple output with just type and socket address or path\n", fd); +/* fputs(" -c alternate device visualization\n", fd);*/ + fputs(" -f analyze file system entry\n", fd); + fputs(" -T wait before analyzing, useful to connect with debugger\n", fd); + fputs(" -r raw output for time stamps and rdev\n", fd); + fputs(" -L show symlink properties instead of following it\n", fd); + fputs(" -o output goes to filename, that can be:\n", fd); + fputs(" a regular file name, the output goes to that\n", fd); + fputs(" + , output goes to the file descriptor (which must be open writable)\n", fd); + fputs(" the 3 special names stdin stdout and stderr\n", fd); +} +#endif /* WITH_HELP */ diff --git a/ftp.sh b/ftp.sh new file mode 100755 index 0000000..91e768d --- /dev/null +++ b/ftp.sh @@ -0,0 +1,158 @@ +#! /bin/sh +# $Id: ftp.sh,v 1.11 2006/12/28 07:27:01 gerhard Exp $ +# Copyright Gerhard Rieger 2001-2006 +# Published under the GNU General Public License V.2, see file COPYING + +# example how to write a shell script that communicates with stdio on the front +# end and with a socat address on the back end + +# usage: +# ftp.sh [opts] server directory/ # show directory contents on stdout +# ftp.sh [opts] server file # print file contents to stdout +# opts: +# -socks socksserver # use given socks server, port 1080 +# -proxy proxyserver # use given proxy server, port 8080 +# # must be http proxy that accepts CONNECT +# # method to ports 21 and >=1024 +# -user username # default: "ftp" +# -passwd password # default: "anonymous@domain.org" +# -t # shell script trace+debug +# -d # debug on control connection (use up to 4 times) +# -D # debug on data connection (use up to 4 times) +# -b # block size for data connection +# -v # verbose +# -l* # socat logging options +# example: +# ftp.sh -v -d -d -D -D -D -b 65536 -proxy proxy ftp.ftp.org /README >README + +user="ftp" +passwd="anonymous@domain.org" +#method="socks4:socks" # socks4 is address spec, socks is socks server name +method=tcp +addropts= + +# socat options +SO1= +SO2= + +while :; do + case "$1" in + -socks|-socks4) shift; + case "$1" in + *:*) method="socks4:${1%%:*}"; addropts="socksport=${1#*:}" ;; + *) method="socks4:$1" ;; + esac ;; + -socks4a) shift; + case "$1" in + *:*) method="socks4a:${1%%:*}"; addropts="socksport=${1#*:}" ;; + *) method="socks4a:$1" ;; + esac ;; + -proxy) shift; + case "$1" in + *:*) method="proxy:${1%%:*}"; addropts="proxyport=${1#*:}" ;; + *) method="proxy:$1" ;; + esac ;; + -user) shift; user="$1" ;; + -passwd) shift; passwd="$1" ;; + -t) set -vx ;; + -d) SO1="$SO1 -d" ;; + -D) SO2="$SO2 -d" ;; + -b) SO2="$SO2 -b $2"; shift ;; + -v) SO1="$SO1 -v" ;; + -l*) SO1="$SO1 $1"; SO2="$SO2 $1" ;; + -*) echo "unknown option \"$1\"" >&2; exit 1;; + *) break ;; + esac + shift +done +export SO2 + +server="$1" +dir="$2" + +echo "addr=$method:$server:21,$addropts"; exit + +### this is the central part to establish communication with socat ### +### copy these lines to make new communication shell scripts +TMPDIR=$(if [ -x /bin/mktemp ]; then + /bin/mktemp -d /tmp/$USER/FTPSH.XXXXXX + else + (umask 077; d=/tmp/$USER/FTPSH.$$; mkdir $d; echo $d) + fi) +TO="$TMPDIR/to"; FROM="$TMPDIR/from" +socat $SO1 fifo:$TO,nonblock,ignoreeof!!fifo:$FROM $method:$server:21,$addropts & +S1=$! +while ! [ -p "$TO" -a -p "$FROM" ]; do sleep 1; done +exec 4>$TMPDIR/to 3<$TMPDIR/from +trap "S1=" 17 +#trap "echo cleaning up...>&2; rm -r $TMPDIR; [ -n "$S1" ] && kill $S1" 0 3 +trap "rm -r $TMPDIR" 0 3 +### here the central part ends + + +# this function waits for a complete server message, checks if its status +# is in the permitted range (terminates session if not), and returns. +ftp_chat () { + local cmd="$1" + local errlevel="$2"; [ -z "$errlevel" ] && errlevel=300 + if [ -n "$cmd" ]; then echo "$cmd" >&4; fi + while read status message <&3; + ( case "$status" in [0-9][0-9][0-9]-*) exit 0;; [0-9][0-9][0-9]*) exit 1;; *) exit 1;; esac ) + do :; done + #echo "got \"$status $message\"" >&2 + if [ -z "$status" ]; then echo ftp data connection failed >&2; exit; fi + if [ "$status" -ge "$errlevel" ]; then + echo $message >&2 + echo "QUIT" >&4; exit 1 + fi +set +vx +} + + +# wait for server greeting +ftp_chat + +ftp_chat "USER $user" 400 + +ftp_chat "PASS $passwd" + +#ftp_chat "CWD $dir" + +case "$dir" in +*/) ftp_chat "TYPE A" ;; +*) ftp_chat "TYPE I" ;; +esac + +echo "PASV" >&4; read status message <&3 +info=$(expr "$message" : '.*[^0-9]\([0-9]*,[0-9]*,[0-9]*,[0-9]*,[0-9]*,[0-9]*\).*') +echo $info |tr ',' ' ' |(read i1 i2 i3 i4 p1 p2 + + addr=$i1.$i2.$i3.$i4 + port=$(echo "256*$p1+$p2" |bc) + #echo $addr:$port + + trap : 20 + # open data connection and transfer data + socat -u $SO2 $method:$server:$port,$addropts - +) & +S2=$! + +case "$dir" in +*/) ftp_chat "NLST $dir" ;; +#*/) ftp_chat "LIST $dir" ;; +*) ftp_chat "RETR $dir" ;; +esac +case "$status" in + [45]*) kill $S2;; +esac + +#echo "waiting for process $S2 to terminate" >&2 +wait $S2 + +ftp_chat + +ftp_chat "QUIT" + +#echo "waiting for process $S1 to terminate" >&2 +wait $S1 +exit diff --git a/gatherinfo.sh b/gatherinfo.sh new file mode 100755 index 0000000..18083bd --- /dev/null +++ b/gatherinfo.sh @@ -0,0 +1,172 @@ +#! /bin/sh +# $Id: gatherinfo.sh,v 1.12 2007/03/06 21:01:07 gerhard Exp $ +# Copyright Gerhard Rieger 2001, 2002 +# Published under the GNU General Public License V.2, see file COPYING + +#set -vx + +# use this script after successful porting +# provide the platform name as argument with no dots, e.g. HPUX-11-0 +# it generates the files: +# Config/Makefile.PLATFORM +# Config/config.PLATFORM.h +# Config/socat.PLATFORM.out +# +# Config/config.PLATFORM.log +# Config/compile.PLATFORM.log +# Config/test.PLATFORM.log + +VERBOSE= +LOGGING= +INTERACTIVE= +CONFOPTS= +PLATFORM= +OUTPUT='>/dev/null' + +# how to echo special characters? +if [ `echo "x\c"` = "x" ]; then E="" +elif [ `echo -e "x\c"` = "x" ]; then E="-e" +fi + +while [ -n "$1" ]; do + case "$1" in + -v) VERBOSE=1; shift;; # tell about progress + -d) LOGGING=1; shift;; # show complete output + -i) INTERACTIVE=1; shift;; # diff and ask before overriding old files + -*) CONFOPTS="$CONFOPTS $1"; shift;; + *) PLATFORM="$1"; break;; + esac +done + +#if [ -z "$PLATFORM" ]; then +# echo "please specify a configuration name, e.g. `uname -s`-`uname -r|tr '.' '-'`!" >&2; exit 1; +#fi + +if [ $# -eq 0 ]; then + echo $E "usage: $0 [-v] [-i] [configure options ...] platform" >&2 + echo $E "\t-v\t\tverbose (print actual command)" >&2 + echo $E "\t-d\t\tdump command outputs" >&2 + echo $E "\t-i\t\tinteractive (ask before overwriting something)" >&2 + echo $E "\tconfigure options\toptions for configure script, e.g. --disable-ip6" >&2 + echo $E "\tplatform\tdescribe your OS, e.g. `uname -s`-`uname -r|tr '.' '-'`" >&2 + exit 1 +fi + +case "$PLATFORM" in +*.*) echo "platform name must not contain '.'" >&2; exit 1;; +esac + + +# now, lets begin! + +if [ -f Makefile ]; then + COMMAND="make distclean" + [ "$VERBOSE" ] && echo "$COMMAND" + $COMMAND >/dev/null 2>&1 || echo "*** failed: $COMMAND" 1>&2 +fi + +# implicitly generates Makefile, config.h, config.log +COMMAND="./configure $CONFOPTS" +LOGFILE="compile.log" +[ "$VERBOSE" ] && echo "$COMMAND" +if [ "$LOGGING" ]; then + { $COMMAND; echo "$?" >socat.rc; } 2>&1 |tee $LOGFILE; + if [ `cat socat.rc` -ne 0 ]; then echo "*** failed: $COMMAND" 1>&2; exit 1; fi +else + $COMMAND >$LOGFILE 2>&1 || { echo "*** failed: $COMMAND" 1>&2; exit 1; } +fi + +COMMAND="make -k" +LOGFILE="compile.log" +[ "$VERBOSE" ] && echo "$COMMAND" +if [ "$LOGGING" ]; then + { $COMMAND; echo "$?" >socat.rc; } 2>&1 |tee -a $LOGFILE; + if [ `cat socat.rc` -ne 0 ]; then echo "*** failed: $COMMAND" 1>&2; exit 1; fi +else + $COMMAND >>$LOGFILE 2>&1 || { echo "*** failed: $COMMAND" 1>&2; exit 1; } +fi + +# generates socat.out +COMMAND="make info" +[ "$VERBOSE" ] && echo "$COMMAND" +$COMMAND >/dev/null || echo "*** failed: $COMMAND" 1>&2 + +COMMAND="./test.sh" +LOGFILE="test.log" +[ "$VERBOSE" ] && echo "$COMMAND" +if [ "$LOGGING" ]; then + { $COMMAND; echo "$?" >socat.rc; } 2>&1 |tee $LOGFILE; + if [ `cat socat.rc` -ne 0 ]; then + echo "*** failed: $COMMAND" 1>&2 + if [ `cat socat.rc` -ge 128 ]; then + exit 1 + fi + fi +else + $COMMAND >$LOGFILE 2>&1 || echo "*** failed: $COMMAND" 1>&2 +fi + +FILES= + +b=Makefile; e=; f=$b; p=Config/$b.$PLATFORM +if [ "$INTERACTIVE" -a -f $p ]; then + if ! diff $p $f; then + cp -pi $f $p + fi +else + cp -p $f $p +fi +FILES="$p" + +b=config; e=h; f=$b.$e; p=Config/$b.$PLATFORM.$e +if [ "$INTERACTIVE" -a -f $p ]; then + if ! diff $p $f; then + cp -pi $f $p + fi +else + cp -p $f $p +fi +FILES="$FILES $p" + +b=socat; e=out; f=$b.$e; p=Config/$b.$PLATFORM.$e +if [ "$INTERACTIVE" -a -f $p ]; then + if ! diff $p $f; then + cp -pi $f $p + fi +else + cp -p $f $p +fi +FILES="$FILES $p" + +b=config; e=log; f=$b.$e; p=Config/$b.$PLATFORM.$e +if [ "$INTERACTIVE" -a -f $p ]; then + if ! diff $p $f; then + cp -pi $f $p + fi +else + cp -p $f $p +fi +FILES="$FILES $p" + +b=compile; e=log; f=$b.$e; p=Config/$b.$PLATFORM.$e +if [ "$INTERACTIVE" -a -f $p ]; then + if ! diff $p $f; then + cp -pi $f $p + fi +else + cp -p $f $p +fi +FILES="$FILES $p" + +b=test; e=log; f=$b.$e; p=Config/$b.$PLATFORM.$e +if [ "$INTERACTIVE" -a -f $p ]; then + if ! diff $p $f; then + cp -pi $f $p + fi +else + cp -p $f $p +fi +FILES="$FILES $p" + +echo "output files:" +echo "$FILES" diff --git a/hostan.c b/hostan.c new file mode 100644 index 0000000..75501e0 --- /dev/null +++ b/hostan.c @@ -0,0 +1,82 @@ +/* $Id: hostan.c,v 1.2 2007/03/06 21:02:01 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2006-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* the subroutine hostan makes a "HOST ANalysis". It gathers information + about the host environment it is running in without modifying its state + (almost). + */ + +#include "xiosysincludes.h" +#include "mytypes.h" +#include "compat.h" +#include "error.h" +#include "sycls.h" +#include "sysutils.h" +#include "filan.h" + +#include "hostan.h" + +static int iffan(FILE *outfile); + +int hostan(FILE *outfile) { +#if WITH_SOCKET + iffan(outfile); +#endif + return 0; +} + +#if WITH_SOCKET +static int iffan(FILE *outfile) { + /* Linux: man 7 netdevice */ + /* FreeBSD: man 4 networking */ + /* Solaris: man 7 if_tcp */ + +/* currently we support Linux and a little FreeBSD */ +#ifdef SIOCGIFCONF /* not Solaris */ +#ifdef SIOCGIFINDEX /* not OpenBSD */ + +#define IFBUFSIZ 32*sizeof(struct ifreq) /*1024*/ + int s; + unsigned char buff[IFBUFSIZ]; + struct ifconf ic; + int i; + + if ((s = Socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) { + Error1("socket(PF_INET, SOCK_DGRAM, IPPROTO_IP): %s", strerror(errno)); + return -1; + } + + for (i=0; i < IFBUFSIZ; ++i) { + buff[i] = 255; + } + ic.ifc_len = sizeof(buff); + ic.ifc_ifcu.ifcu_buf = (caddr_t)buff; + if (Ioctl(s, SIOCGIFCONF, &ic) < 0) { + Error3("ioctl(%d, SIOCGIFCONF, %p): %s", s, &ic, strerror(errno)); + return -1; + } + + for (i = 0; i < ic.ifc_len; i += sizeof(struct ifreq)) { + struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i); + struct ifreq ifr; + + strcpy(ifr.ifr_name, ifp->ifr_name); + if (Ioctl(s, SIOCGIFINDEX, &ifr) < 0) { + Error3("ioctl(%d, SIOCGIFINDEX, {\"%s\"}): %s", + s, &ifr.ifr_name, strerror(errno)); + return 1; + } + /*fprintf(outfile, "%2d: %s\n", ifr.ifr_ifindex, ifp->ifr_ifrn.ifrn_name);*/ +#if HAVE_STRUCT_IFREQ_IFR_INDEX + fprintf(outfile, "%2d: %s\n", ifr.ifr_index, ifp->ifr_name); +#elif HAVE_STRUCT_IFREQ_IFR_IFINDEX + fprintf(outfile, "%2d: %s\n", ifr.ifr_ifindex, ifp->ifr_name); +#endif /* HAVE_STRUCT_IFREQ_IFR_INDEX */ + } + Close(s); +#endif /* defined(SIOCGIFCONF) */ +#endif /* defined(SIOCGIFINDEX) */ + return 0; +} +#endif /* WITH_SOCKET */ diff --git a/hostan.h b/hostan.h new file mode 100644 index 0000000..ab9b8e0 --- /dev/null +++ b/hostan.h @@ -0,0 +1,10 @@ +/* $Id: hostan.h,v 1.1 2006/12/31 17:49:25 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __hostan_h_included +#define __hostan_h_included 1 + +extern int hostan(FILE *outfile); + +#endif /* !defined(__hostan_h_included) */ diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..ebc6691 --- /dev/null +++ b/install-sh @@ -0,0 +1,250 @@ +#! /bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/mail.sh b/mail.sh new file mode 100755 index 0000000..669ac75 --- /dev/null +++ b/mail.sh @@ -0,0 +1,71 @@ +#! /bin/sh +# $Id: mail.sh,v 1.11 2005/09/10 16:48:38 gerhard Exp $ +# Copyright Gerhard Rieger 2001-2005 +# Published under the GNU General Public License V.2, see file COPYING + +#set -vx + +# This is an example for a shell script that can be fed to socat with exec. +# Its clue is that it does not use stdin/stdout for communication with socat, +# so you may feed the mail message via stdin to the script. The message should +# contain appropriate mail headers. +# Lines with only a dot are not permitted - use two dots as escape. +# This script supports multiline answers from server, but not much more yet. + +# Usage: cat message.txt |socat exec:"mail.sh target@domain.com",fdin=3,fdout=4 tcp:mail.relay.org:25,crlf + +while [ "$1" ]; do + case "$1" in + -f) shift; mailfrom="$1"; shift;; + *) break;; + esac +done + +rcptto="$1" +[ -z "$1" ] && rcptto="root@loopback" +#server=$(expr "$rcptto" : '[^@]*@\(.*\)') +[ -z "$mailfrom" ] && mailfrom="$USER@$(hostname)" + +# this function waits for a complete server message, checks if its status +# is in the permitted range (terminates session if not), and returns. +mail_chat () { + local cmd="$1" + local errlevel="$2"; [ -z "$errlevel" ] && errlevel=300 + + if [ "$cmd" ]; then echo "> $cmd" >&2; fi + if [ -n "$cmd" ]; then echo "$cmd" >&4; fi + while read status message <&3; + ( + case "$status" in + [0-9][0-9][0-9]-*) exit 0;; + [0-9][0-9][0-9]*) exit 1;; + *) exit 1;; + esac + ) + do :; done + if [ -z "$status" ]; then echo smtp connection failed >&2; exit; fi + echo "< $status $message" >&2 + if [ "$status" -ge "$errlevel" ]; then + echo $message >&2 + echo "QUIT" >&4; exit 1 + fi +} + + +# expect server greeting +mail_chat + +mail_chat "HELO $(hostname)" + +mail_chat "MAIL FROM: $mailfrom" + +mail_chat "RCPT TO: $rcptto" + +mail_chat "DATA" 400 + +while read l; do echo "$l" >&4; done +mail_chat "." + +mail_chat "QUIT" + +exit 0 diff --git a/mytypes.h b/mytypes.h new file mode 100644 index 0000000..f96eaa2 --- /dev/null +++ b/mytypes.h @@ -0,0 +1,17 @@ +/* $Id: mytypes.h,v 1.4 2006/05/06 14:15:47 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __mytypes_h_included +#define __mytypes_h_included 1 + +/* some types and macros I miss in C89 */ + +typedef enum { false, true } bool; + +#define Min(x,y) ((x)<=(y)?(x):(y)) +#define Max(x,y) ((x)>=(y)?(x):(y)) + +#define SOCKADDR_MAX UNIX_PATH_MAX + +#endif /* __mytypes_h_included */ diff --git a/nestlex.c b/nestlex.c new file mode 100644 index 0000000..a9099ef --- /dev/null +++ b/nestlex.c @@ -0,0 +1,237 @@ +/* $Id: nestlex.c,v 1.4 2006/06/23 17:04:36 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* a function for lexical scanning of nested character patterns */ + +#include "config.h" +#include "mytypes.h" + +#include "sysincludes.h" + + +/* sub: scan a string and copy its value to output string + end scanning when an unescaped, unnested string from ends array is found + does not copy the end pattern + does not write a trailing \0 to token + allows escaping with \ and quoting (\ and quotes are removed) + allows nesting with div. parens + returns -1 if out string was too small + returns 1 if addr ended unexpectedly + returns 0 if token could be extracted successfully +*/ +int nestlex(const char **addr, /* input string; aft points to end token */ + char **token, /* output token; aft points to first unwritten + char (caller might want to set it to \0) */ + size_t *len, /* remaining bytes in token space (incl. \0) */ + const char *ends[], /* list of end strings */ + const char *hquotes[],/* list of strings that quote (hard qu.) */ + const char *squotes[],/* list of strings that quote softly */ + const char *nests[],/* list of strings that start nesting; + every second one is matching end */ + bool dropquotes, /* drop the outermost quotes */ + bool c_esc, /* solve C char escapes: \n \t \0 etc */ + bool html_esc /* solve HTML char escapes: %0d %08 etc */ + ) { + const char *in = *addr; /* pointer into input string */ + const char **endx; /* loops over end patterns */ + const char **quotx; /* loops over quote patterns */ + const char **nestx; /* loops over nest patterns */ + char *out = *token; /* pointer into output token */ + char c; + int i; + int result; + + while (true) { + + /* is this end of input string? */ + if (*in == 0) { + + break; /* end of string */ + } + + /* first check the end patterns (e.g. for ']') */ + endx = ends; i = 0; + while (*endx) { + if (!strncmp(in, *endx, strlen(*endx))) { + /* this end pattern matches */ + *addr = in; + *token = out; + return 0; + } + ++endx; + } + + /* check for hard quoting pattern */ + quotx = hquotes; + while (hquotes && *quotx) { + if (!strncmp(in, *quotx, strlen(*quotx))) { + /* this quote pattern matches */ + const char *endnest[2]; + if (dropquotes) { + /* we strip this quote */ + in += strlen(*quotx); + } else { + for (i = strlen(*quotx); i > 0; --i) { + *out++ = *in++; + if (--*len <= 0) { *addr = in; *token = out; return -1; } + } + } + /* we call nestlex recursively */ + endnest[0] = *quotx; + endnest[1] = NULL; + result = + nestlex(&in, &out, len, endnest, NULL/*hquotes*/, + NULL/*squotes*/, NULL/*nests*/, + false, c_esc, html_esc); + if (result == 0 && dropquotes) { + /* we strip this quote */ + in += strlen(*quotx); + } else { + /* we copy the trailing quote */ + for (i = strlen(*quotx); i > 0; --i) { + *out++ = *in++; + if (--*len <= 0) { *addr = in; *token = out; return -1; } + } + } + + break; + } + ++quotx; + } + if (hquotes && *quotx != NULL) { + /* there was a quote; string might continue with hard quote */ + continue; + } + + /* check for soft quoting pattern */ + quotx = squotes; + while (squotes && *quotx) { + if (!strncmp(in, *quotx, strlen(*quotx))) { + /* this quote pattern matches */ + /* we strip this quote */ + /* we call nestlex recursively */ + const char *endnest[2]; + if (dropquotes) { + /* we strip this quote */ + in += strlen(*quotx); + } else { + for (i = strlen(*quotx); i > 0; --i) { + *out++ = *in++; + if (--*len <= 0) { *addr = in; *token = out; return -1; } + } + } + endnest[0] = *quotx; + endnest[1] = NULL; + result = + nestlex(&in, &out, len, endnest, hquotes, + squotes, nests, + false, c_esc, html_esc); + + if (result == 0 && dropquotes) { + /* we strip the trailing quote */ + in += strlen(*quotx); + } else { + /* we copy the trailing quote */ + for (i = strlen(*quotx); i > 0; --i) { + *out++ = *in++; + if (--*len <= 0) { *addr = in; *token = out; return -1; } + } + } + break; + } + ++quotx; + } + if (squotes && *quotx != NULL) { + /* there was a soft quote; string might continue with any quote */ + continue; + } + + /* check patterns that start a nested clause */ + nestx = nests; i = 0; + while (nests && *nestx) { + if (!strncmp(in, *nestx, strlen(*nestx))) { + /* this nest pattern matches */ + const char *endnest[2]; + endnest[0] = nestx[1]; + endnest[1] = NULL; + + for (i = strlen(nestx[1]); i > 0; --i) { + *out++ = *in++; + if (--*len <= 0) { *addr = in; *token = out; return -1; } + } + + result = + nestlex(&in, &out, len, endnest, hquotes, squotes, nests, + false, c_esc, html_esc); + if (result == 0) { + /* copy endnest */ + i = strlen(nestx[1]); while (i > 0) { + *out++ = *in++; + if (--*len <= 0) { + *addr = in; + *token = out; + return -1; + } + --i; + } + } + break; + } + nestx += 2; /* skip matching end pattern in table */ + } + if (nests && *nestx) { + /* we handled a nested expression, continue loop */ + continue; + } + + /* "normal" data, possibly escaped */ + c = *in++; + if (c == '\\') { + /* found a plain \ escaped part */ + c = *in++; + if (c == 0) { /* Warn("trailing '\\'");*/ break; } + if (c_esc) { /* solve C char escapes: \n \t \0 etc */ + switch (c) { + case '0': c = '\0'; break; + case 'a': c = '\a'; break; + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'v': c = '\v'; break; +#if LATER + case 'x': !!! 1 to 2 hex digits; break; + case 'u': !!! 4 hex digits?; break; + case 'U': !!! 8 hex digits?; break; +#endif + default: break; + } + } + *out++ = c; + --*len; + if (len == 0) { + *addr = in; + *token = out; + return -1; /* output overflow */ + } + continue; + } + + /* just a simple char */ + *out++ = c; + --*len; + if (len == 0) { + *addr = in; + *token = out; + return -1; /* output overflow */ + } + + } + /* never come here? */ + + *addr = in; + *token = out; + return 0; /* OK */ +} diff --git a/nestlex.h b/nestlex.h new file mode 100644 index 0000000..af0828a --- /dev/null +++ b/nestlex.h @@ -0,0 +1,23 @@ +/* $Id: nestlex.h,v 1.3 2006/06/23 17:04:39 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __nestlex_h_included +#define __nestlex_h_included 1 + +extern +int nestlex(const char **addr, /* input string; aft points to end token */ + char **token, /* output token; aft points to first unwritten + char (caller might want to set it to \0) */ + size_t *len, /* remaining bytes in token space (incl. \0) */ + const char *ends[], /* list of end strings */ + const char *hquotes[],/* list of strings that quote (hard qu.) */ + const char *squotes[],/* list of strings that quote softly */ + const char *nests[],/* list of strings that start nesting; + every second one is matching end */ + bool dropquotes, /* drop the outermost quotes */ + bool c_esc, /* solve C char escapes: \n \t \0 etc */ + bool html_esc /* solve HTML char escapes: %0d %08 etc */ + ); + +#endif /* !defined(__nestlex_h_included) */ diff --git a/procan.c b/procan.c new file mode 100644 index 0000000..b25efee --- /dev/null +++ b/procan.c @@ -0,0 +1,169 @@ +/* $Id: procan.c,v 1.17 2006/12/28 07:25:01 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* the subroutine procan makes a "PROCess ANalysis". It gathers information + about the process environment it is running in without modifying its state + (almost). + */ + +#include "xiosysincludes.h" +#include "mytypes.h" +#include "compat.h" +#include "error.h" +#include "sycls.h" +#include "sysutils.h" +#include "filan.h" + +#include + +#include "procan.h" + +/* dirty workaround so we dont get an error on AIX when getting linked with + libwrap */ +int allow_severity, deny_severity; + + +int procan(FILE *outfile) { + + /*filan(0, outfile);*/ + + /* controlling terminal */ + fprintf(outfile, "process id = "F_pid"\n", Getpid()); + fprintf(outfile, "process parent id = "F_pid"\n", Getppid()); + { + int fd; + if ((fd = Open("/dev/tty", O_NOCTTY, 0)) < 0) { + fprintf(outfile, "controlling terminal: -\n"); + } else { +#if 1 + fprintf(outfile, "controlling terminal: \"%s\"\n", Ttyname(fd)); +#else + char procpath[PATH_MAX], devpath[PATH_MAX+1]; + int devlen; + sprintf(procpath, "/proc/"F_pid"/fd/%d", Getpid(), 0 /*! fd*/); + if ((devlen = Readlink(procpath, devpath, sizeof(devpath))) < 0) { + ; + } else { + devpath[devlen] = '\0'; + fprintf(outfile, "controlling terminal: \"%s\"\n", devpath); + } +#endif + } + } + fprintf(outfile, "process group id = "F_pid"\n", Getpgrp()); +#if HAVE_GETSID + fprintf(outfile, "process session id = "F_pid"\n", Getsid(0)); +#endif + fprintf(outfile, "process group id if fg process / stdin = "F_pid"\n", Tcgetpgrp(0)); + fprintf(outfile, "process group id if fg process / stdout = "F_pid"\n", Tcgetpgrp(1)); + fprintf(outfile, "process group id if fg process / stderr = "F_pid"\n", Tcgetpgrp(2)); + { + int fd; + if ((fd = Open("/dev/tty", O_RDWR, 0600)) >= 0) { + fprintf(outfile, "process has a controlling terminal\n"); + Close(fd); + } else { + fprintf(outfile, "process does not have a controlling terminal\n"); + } + } + + /* process owner, groups */ + fprintf(outfile, "user id = "F_uid"\n", Getuid()); + fprintf(outfile, "effective user id = "F_uid"\n", Geteuid()); + fprintf(outfile, "group id = "F_gid"\n", Getgid()); + fprintf(outfile, "effective group id = "F_gid"\n", Getegid()); + + { + struct rlimit rlim; + + fprintf(outfile, "\nRESOURCE LIMITS\n"); + fprintf(outfile, "resource current maximum\n"); + if (getrlimit(RLIMIT_CPU, &rlim) < 0) { + Warn2("getrlimit(RLIMIT_CPU, %p): %s", &rlim, strerror(errno)); + } else { + fprintf(outfile, + "cpu time (seconds) %16"F_rlim_max"%16"F_rlim_max"\n", + rlim.rlim_cur, rlim.rlim_max); + } + if (getrlimit(RLIMIT_FSIZE, &rlim) < 0) { + Warn2("getrlimit(RLIMIT_FSIZE, %p): %s", &rlim, strerror(errno)); + } else { + fprintf(outfile, + "file size (blocks) %16"F_rlim_max"%16"F_rlim_max"\n", + rlim.rlim_cur, rlim.rlim_max); + } + if (getrlimit(RLIMIT_DATA, &rlim) < 0) { + Warn2("getrlimit(RLIMIT_DATA, %p): %s", &rlim, strerror(errno)); + } else { + fprintf(outfile, + "data seg size (kbytes) %16"F_rlim_max"%16"F_rlim_max"\n", + rlim.rlim_cur, rlim.rlim_max); + } + if (getrlimit(RLIMIT_STACK, &rlim) < 0) { + Warn2("getrlimit(RLIMIT_STACK, %p): %s", &rlim, strerror(errno)); + } else { + fprintf(outfile, + "stack size (blocks) %16"F_rlim_max"%16"F_rlim_max"\n", + rlim.rlim_cur, rlim.rlim_max); + } + if (getrlimit(RLIMIT_CORE, &rlim) < 0) { + Warn2("getrlimit(RLIMIT_CORE, %p): %s", &rlim, strerror(errno)); + } else { + fprintf(outfile, + "core file size (blocks) %16"F_rlim_max"%16"F_rlim_max"\n", + rlim.rlim_cur, rlim.rlim_max); + } +#ifdef RLIMIT_RSS /* Linux, AIX; not Cygwin */ + if (getrlimit(RLIMIT_RSS, &rlim) < 0) { + Warn2("getrlimit(RLIMIT_RSS, %p): %s", &rlim, strerror(errno)); + } else { + fprintf(outfile, + "max resident set size %16"F_rlim_max"%16"F_rlim_max"\n", + rlim.rlim_cur, rlim.rlim_max); + } +#endif +#ifdef RLIMIT_NPROC /* Linux, not AIX, Cygwin */ + if (getrlimit(RLIMIT_NPROC, &rlim) < 0) { + Warn2("getrlimit(RLIMIT_NPROC, %p): %s", &rlim, strerror(errno)); + } else { + fprintf(outfile, + "max user processes %16"F_rlim_max"%16"F_rlim_max"\n", + rlim.rlim_cur, rlim.rlim_max); + } +#endif +#ifdef RLIMIT_NOFILE /* not AIX 4.1 */ + if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { + Warn2("getrlimit(RLIMIT_NOFILE, %p): %s", &rlim, strerror(errno)); + } else { + fprintf(outfile, + "open files %16"F_rlim_max"%16"F_rlim_max"\n", + rlim.rlim_cur, rlim.rlim_max); + } +#endif +#ifdef RLIMIT_MEMLOCK /* Linux, not AIX, Cygwin */ + if (getrlimit(RLIMIT_MEMLOCK, &rlim) < 0) { + Warn2("getrlimit(RLIMIT_MEMLOCK, %p): %s", &rlim, strerror(errno)); + } else { + fprintf(outfile, + "max locked-in-memory address space %16"F_rlim_max"%16"F_rlim_max"\n", + rlim.rlim_cur, rlim.rlim_max); + } +#endif +#ifdef RLIMIT_AS + if (getrlimit(RLIMIT_AS, &rlim) < 0) { + Warn2("getrlimit(RLIMIT_AS, %p): %s", &rlim, strerror(errno)); + } else { + fprintf(outfile, + "virtual memory (kbytes) %16"F_rlim_max"%16"F_rlim_max"\n", + rlim.rlim_cur, rlim.rlim_max); + } +#endif + } + + /* file descriptors */ + + /* what was this for?? */ + /*Sleep(1);*/ + return 0; +} diff --git a/procan.h b/procan.h new file mode 100644 index 0000000..0825c54 --- /dev/null +++ b/procan.h @@ -0,0 +1,10 @@ +/* $Id: procan.h,v 1.2 2001/06/30 14:02:39 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __procan_h_included +#define __procan_h_included 1 + +extern int procan(FILE *outfile); + +#endif /* !defined(__procan_h_included) */ diff --git a/procan_main.c b/procan_main.c new file mode 100644 index 0000000..b368ac1 --- /dev/null +++ b/procan_main.c @@ -0,0 +1,94 @@ +/* $Id: procan_main.c,v 1.13 2007/03/06 21:19:18 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +const char copyright[] = "procan by Gerhard Rieger - send bug reports to socat@dest-unreach.org"; + +#include /* strtoul() */ +#include +#include +#include "mytypes.h" +#include "error.h" +#include "procan.h" +#include "hostan.h" + + +#define WITH_HELP 1 + +static void procan_usage(FILE *fd); + + +int main(int argc, const char *argv[]) { + const char **arg1; +#if 0 + unsigned int n = 1024; /* this is default on my Linux */ +#endif + + diag_set('p', strchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]); + + arg1 = argv+1; --argc; + while (arg1[0] && (arg1[0][0] == '-')) { + switch (arg1[0][1]) { +#if WITH_HELP + case '?': case 'h': procan_usage(stdout); exit(0); +#endif /* WITH_HELP */ +#if LATER + case 'V': procan_version(stdout); exit(0); + case 'l': diag_set(arg1[0][2], &arg1[0][3]); break; + case 'd': diag_set('d', NULL); break; +#endif +#if 0 + case 'n': n = strtoul(&arg1[0][2], NULL, 0); break; +#endif + case '\0': break; + default: + diag_set_int('e', E_FATAL); + Error1("unknown option \"%s\"", arg1[0]); +#if WITH_HELP + procan_usage(stderr); +#endif + exit(1); + } + if (arg1[0][1] == '\0') + break; + ++arg1; --argc; + } + if (argc != 0) { + Error1("%d superfluous arguments", argc); +#if WITH_HELP + procan_usage(stderr); +#endif + exit(1); + } + procan(stdout); + hostan(stdout); + return 0; +} + + +#if WITH_HELP +static void procan_usage(FILE *fd) { + fputs(copyright, fd); fputc('\n', fd); + fputs("Analyze system parameters of process\n", 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 +#if LATER + fputs(" -d increase verbosity (use up to 4 times; 2 are recommended)\n", fd); +#endif +#if 0 + fputs(" -ly[facility] log to syslog, using facility (default is daemon)\n", fd); + fputs(" -lf log to file\n", fd); + fputs(" -ls log to stderr (default if no other log)\n", fd); +#endif +#if 0 + fputs(" -n first file descriptor number not analyzed\n", fd); +#endif +} +#endif /* WITH_HELP */ diff --git a/proxy.sh b/proxy.sh new file mode 100755 index 0000000..e4da38c --- /dev/null +++ b/proxy.sh @@ -0,0 +1,76 @@ +#! /bin/bash +# $Id: proxy.sh,v 1.3 2004/07/11 07:55:57 gerhard Exp $ +# Copyright Gerhard Rieger 2003-2004 +# Published under the GNU General Public License V.2, see file COPYING + +# perform primitive simulation of a proxy server. +# accepts and answers correct HTTP CONNECT requests on stdio, and tries to +# establish the connection to the given server. +# it is required for socats test.sh +# for TCP, use this script as: +# socat tcp-l:8080,reuseaddr,fork exec:"proxy.sh",nofork + +if [ -z "$SOCAT" ]; then + if type socat >/dev/null 2>&1; then + SOCAT=socat + else + SOCAT="./socat" + fi +fi + +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 + exit 1 +fi +ECHO="echo $E" +CR=$($ECHO "\r") +#echo "CR=$($ECHO "$CR\c" |od -c)" >&2 + +case `uname` in +HP-UX|OSF1) + # their cats are too stupid to work with unix domain sockets + CAT="$SOCAT -u stdin stdout" + ;; +*) + CAT=cat + ;; +esac + +SPACES=" " +while [ -n "$1" ]; do + case "$1" in + -w) n="$2"; while [ "$n" -gt 0 ]; do SPACES="$SPACES "; n=$((n-1)); done + shift ;; + #-s) STAT="$2"; shift ;; + esac + shift +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.[01]' >/dev/null +then + : go on below +else + $ECHO "HTTP/1.0${SPACES}500 Bad Request$CR" + $ECHO "$CR" + exit +fi + +# extract target server name/address +s=`echo $l |awk '{print($2);}'` + +# read more headers until empty line +while [ "$l" != "$CR" ]; do + read l +done + +# send status +$ECHO "HTTP/1.0${SPACES}200 OK$CR" +# send empty line +$ECHO "$CR" + +# perform proxy (relay) function +exec $SOCAT $SOCAT_OPTS - tcp:$s diff --git a/proxyecho.sh b/proxyecho.sh new file mode 100755 index 0000000..545fe68 --- /dev/null +++ b/proxyecho.sh @@ -0,0 +1,59 @@ +#! /bin/bash +# $Id: proxyecho.sh,v 1.5 2004/06/06 17:33:22 gerhard Exp $ +# Copyright Gerhard Rieger 2003 +# Published under the GNU General Public License V.2, see file COPYING + +# perform primitive simulation of a proxy server with echo function via stdio. +# accepts and answers correct HTTP CONNECT requests, but then just echoes data. +# it is required for test.sh +# for TCP, use this script as: +# socat tcp-l:8080,reuseaddr,crlf system:"proxyecho.sh" + +if 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 + +SPACES=" " +while [ -n "$1" ]; do + case "$1" in + -w) n="$2"; while [ "$n" -gt 0 ]; do SPACES="$SPACES "; n=$((n-1)); done + shift ;; + #-s) STAT="$2"; shift ;; + esac + shift +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.[01]$' >/dev/null +then + : go on below +else + echo "HTTP/1.0${SPACES}500 Bad Request" + echo + exit +fi + +# read more headers until empty line +while [ -n "$l" ]; do + read l +done + +# send status +echo "HTTP/1.0${SPACES}200 OK" +# send empty line +echo + +# perform echo function +$CAT diff --git a/readline-test.sh b/readline-test.sh new file mode 100755 index 0000000..83c24a2 --- /dev/null +++ b/readline-test.sh @@ -0,0 +1,46 @@ +#! /bin/bash +# $Id: readline-test.sh,v 1.1 2003/12/23 21:28:12 gerhard Exp $ +# Copyright Gerhard Rieger 2003 +# Published under the GNU General Public License V.2, see file COPYING + +# script that simulates a simple program with authentication. +# is just for testing the readline features +# perform the test with something like: +# ./socat readline,history=$HOME/.history,noecho='^Password: ' system:./readline-test.sh,pty,setsid,ctty,stderr,sigint,sigquit,echo=0,raw + + +BANNER='readline feature test program' +USERPROMPT='Authentication required\nUsername: ' +PWDPROMPT='Password: ' +PROMPT='prog> ' + +# degenerated user database +CREDUSER="user" +CREDPASS="password" + +if [ $(echo "x\c") = "x" ]; then ECHO="echo" +elif [ $(echo -e "x\c") = "x" ]; then ECHO="echo -e" +fi + +#trap "$ECHO $0 got SIGINT" INT +trap "$ECHO $0 got SIGINT" INT +trap "$ECHO $0 got SIGQUIT" QUIT + +# print banner +$ECHO "$BANNER" + +read -r -p "$($ECHO "$USERPROMPT")" USERNAME +read -rs -p "$PWDPROMPT" PASSWORD +$ECHO + +if [ "$USERNAME" != "$CREDUSER" -o "$PASSWORD" != "$CREDPASS" ]; then + $ECHO "Authentication failed" >&2 + exit -1 +fi + +while read -r -p "$PROMPT" COMMAND; do + if [ "$COMMAND" = "exit" ]; then + break; + fi + $ECHO "executing $COMMAND" +done diff --git a/readline.sh b/readline.sh new file mode 100755 index 0000000..26cd1df --- /dev/null +++ b/readline.sh @@ -0,0 +1,30 @@ +#! /bin/bash +# $Id: readline.sh,v 1.3 2004/08/25 15:52:59 gerhard Exp $ +# Copyright Gerhard Rieger 2003-2004 +# 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 + +withhistfile=1 + +while true; do + case "X$1" in + X-nh|X-nohist*) withhistfile=; shift; continue ;; + *) break;; + esac +done + +PROGRAM="$@" +if [ "$withhistfile" ]; then + HISTFILE="$HOME/.$1_history" + HISTOPT=",history=$HISTFILE" +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 + diff --git a/socat.c b/socat.c new file mode 100644 index 0000000..1231694 --- /dev/null +++ b/socat.c @@ -0,0 +1,1370 @@ +/* $Id: socat.c,v 1.111 2007/03/06 21:03:28 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this is the main source, including command line option parsing, general + control, and the data shuffler */ + +#include "config.h" +#include "xioconfig.h" /* what features are enabled */ + +#include "sysincludes.h" + +#include "mytypes.h" +#include "compat.h" +#include "error.h" + +#include "sycls.h" +#include "sysutils.h" +#include "dalan.h" +#include "filan.h" +#include "xio.h" +#include "xioopts.h" +#include "xiolockfile.h" + + +/* command line options */ +struct { + size_t bufsiz; + bool verbose; + bool verbhex; + struct timeval pollintv; /* with ignoreeof, reread after seconds */ + struct timeval closwait; /* after close of x, die after seconds */ + struct timeval total_timeout;/* when nothing happens, die after seconds */ + bool debug; + bool strictopts; /* stop on errors in address options */ + char logopt; /* y..syslog; s..stderr; f..file; m..mixed */ + bool lefttoright; /* first addr ro, second addr wo */ + bool righttoleft; /* first addr wo, second addr ro */ + xiolock_t lock; /* a lock file */ +} socat_opts = { + 8192, /* bufsiz */ + false, /* verbose */ + false, /* verbhex */ + {1,0}, /* pollintv */ + {0,500000}, /* closwait */ + {0,0}, /* total_timeout */ + 0, /* debug */ + 0, /* strictopts */ + 's', /* logopt */ + false, /* lefttoright */ + false, /* righttoleft */ + { NULL, 0 }, /* lock */ +}; + +void socat_usage(FILE *fd); +void socat_version(FILE *fd); +int socat(const char *address1, const char *address2); +int _socat(void); +int cv_newline(unsigned char **buff, ssize_t *bytes, int lineterm1, int lineterm2); +void socat_signal(int sig); +static int socat_sigchild(struct single *file); + +void lftocrlf(char **in, ssize_t *len, size_t bufsiz); +void crlftolf(char **in, ssize_t *len, size_t bufsiz); + +static int socat_lock(void); +static void socat_unlock(void); +static int socat_newchild(void); + +static const char socatversion[] = +#include "./VERSION" + ; +static const char timestamp[] = __DATE__" "__TIME__; + +const char copyright_socat[] = "socat by Gerhard Rieger - see www.dest-unreach.org"; +#if WITH_OPENSSL +const char copyright_openssl[] = "This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit. (http://www.openssl.org/)"; +const char copyright_ssleay[] = "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"; +#endif + +bool havelock; + + +int main(int argc, const char *argv[]) { + const char **arg1, *a; + char buff[10]; + double rto; + int i, argc0, result; + struct utsname ubuf; + int lockrc; + + diag_set('p', strchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]); + + /* we must init before applying options because env settings have lower + priority and are to be overridden by options */ + if (xioinitialize() != 0) { + Exit(1); + } + + xiosetopt('p', "!!"); + xiosetopt('o', ":"); + + argc0 = argc; /* save for later use */ + arg1 = argv+1; --argc; + while (arg1[0] && (arg1[0][0] == '-')) { + switch (arg1[0][1]) { + case 'V': socat_version(stdout); Exit(0); +#if WITH_HELP + case '?': + case 'h': + socat_usage(stdout); + xioopenhelp(stdout, (arg1[0][2]=='?'||arg1[0][2]=='h') ? (arg1[0][3]=='?'||arg1[0][3]=='h') ? 2 : 1 : 0); + Exit(0); +#endif /* WITH_HELP */ + case 'd': diag_set('d', NULL); break; +#if WITH_FILAN + case 'D': socat_opts.debug = true; break; +#endif + case 'l': + switch (arg1[0][2]) { + case 'm': /* mixed mode: stderr, then switch to syslog; + facility */ + diag_set('s', NULL); + xiosetopt('l', "m"); + socat_opts.logopt = arg1[0][2]; + xiosetopt('y', &arg1[0][3]); + break; + case 'y': /* syslog + facility */ + diag_set(arg1[0][2], &arg1[0][3]); + break; + case 'f': /* to file, +filename */ + case 'p': /* artificial program name */ + if (arg1[0][3]) { + diag_set(arg1[0][2], &arg1[0][3]); + } else if (arg1[1]) { + diag_set(arg1[0][2], arg1[1]); + ++arg1, --argc; + } else { + Error1("option -l%c requires an argument; use option \"-h\" for help", arg1[0][2]); + } + break; + case 's': /* stderr */ + diag_set(arg1[0][2], NULL); + break; + case 'u': + diag_set('u', NULL); + break; + case 'h': + diag_set_int('h', true); + break; + default: + Error1("unknown log option \"%s\"; use option \"-h\" for help", arg1[0]); + break; + } + break; + case 'v': socat_opts.verbose = true; break; + case 'x': socat_opts.verbhex = true; break; + case 'b': if (arg1[0][2]) { + a = *arg1+2; + } else { + ++arg1, --argc; + if ((a = *arg1) == NULL) { + Error("option -b requires an argument; use option \"-h\" for help"); + Exit(1); + } + } + socat_opts.bufsiz = strtoul(a, (char **)&a, 0); + break; + case 's': + diag_set_int('e', E_FATAL); break; + case 't': if (arg1[0][2]) { + a = *arg1+2; + } else { + ++arg1, --argc; + if ((a = *arg1) == NULL) { + Error("option -t requires an argument; use option \"-h\" for help"); + Exit(1); + } + } + rto = strtod(a, (char **)&a); + socat_opts.closwait.tv_sec = rto; + socat_opts.closwait.tv_usec = + (rto-socat_opts.closwait.tv_sec) * 1000000; + break; + case 'T': if (arg1[0][2]) { + a = *arg1+2; + } else { + ++arg1, --argc; + if ((a = *arg1) == NULL) { + Error("option -T requires an argument; use option \"-h\" for help"); + Exit(1); + } + } + rto = strtod(a, (char **)&a); + socat_opts.total_timeout.tv_sec = rto; + socat_opts.total_timeout.tv_usec = + (rto-socat_opts.total_timeout.tv_sec) * 1000000; + break; + case 'u': socat_opts.lefttoright = true; break; + case 'U': socat_opts.righttoleft = true; break; + case 'g': xioopts_ignoregroups = true; break; + case 'L': if (socat_opts.lock.lockfile) + Error("only one -L and -W option allowed"); + if (arg1[0][2]) { + socat_opts.lock.lockfile = *arg1+2; + } else { + ++arg1, --argc; + if ((socat_opts.lock.lockfile = *arg1) == NULL) { + Error("option -L requires an argument; use option \"-h\" for help"); + Exit(1); + } + } + break; + case 'W': if (socat_opts.lock.lockfile) + Error("only one -L and -W option allowed"); + if (arg1[0][2]) { + socat_opts.lock.lockfile = *arg1+2; + } else { + ++arg1, --argc; + if ((socat_opts.lock.lockfile = *arg1) == NULL) { + Error("option -W requires an argument; use option \"-h\" for help"); + Exit(1); + } + } + socat_opts.lock.waitlock = true; + socat_opts.lock.intervall.tv_sec = 1; + socat_opts.lock.intervall.tv_nsec = 0; + break; +#if WITH_IP4 || WITH_IP6 +#if WITH_IP4 + case '4': +#endif +#if WITH_IP6 + case '6': +#endif + xioopts.default_ip = arg1[0][1]; + xioopts.preferred_ip = arg1[0][1]; + break; +#endif /* WITH_IP4 || WITH_IP6 */ + case '\0': + case ',': + case ':': break; /* this "-" is a variation of STDIO */ + default: + xioinqopt('p', buff, sizeof(buff)); + if (arg1[0][1] == buff[0]) { + break; + } + Error1("unknown option \"%s\"; use option \"-h\" for help", arg1[0]); + Exit(1); + } + /* the leading "-" might be a form of the first address */ + xioinqopt('p', buff, sizeof(buff)); + if (arg1[0][0] == '-' && + (arg1[0][1] == '\0' || arg1[0][1] == ':' || + arg1[0][1] == ',' || arg1[0][1] == buff[0])) + break; + ++arg1; --argc; + } + if (argc != 2) { + Error1("exactly 2 addresses required (there are %d); use option \"-h\" for help", argc); + Exit(1); + } + if (socat_opts.lefttoright && socat_opts.righttoleft) { + Error("-U and -u must not be combined"); + } + + Info(copyright_socat); +#if WITH_OPENSSL + Info(copyright_openssl); + Info(copyright_ssleay); +#endif + Debug2("socat version %s on %s", socatversion, timestamp); + uname(&ubuf); /* ! here we circumvent internal tracing (Uname) */ + Debug4("running on %s version %s, release %s, machine %s\n", + ubuf.sysname, ubuf.version, ubuf.release, ubuf.machine); + +#if WITH_MSGLEVEL <= E_DEBUG + for (i = 0; i < argc0; ++i) { + Debug2("argv[%d]: \"%s\"", i, argv[i]); + } +#endif /* WITH_MSGLEVEL <= E_DEBUG */ + + /* not sure what signal should print a message */ + Signal(SIGHUP, socat_signal); + Signal(SIGINT, socat_signal); + Signal(SIGQUIT, socat_signal); + Signal(SIGILL, socat_signal); + /* SIGABRT for assert; catching caused endless recursion on assert in libc + (tzfile.c:498: __tzfile_compute: Assertion 'num_types == 1' failed.) */ + /*Signal(SIGABRT, socat_signal);*/ + Signal(SIGBUS, socat_signal); + Signal(SIGFPE, socat_signal); + Signal(SIGSEGV, socat_signal); + Signal(SIGTERM, socat_signal); + + /* set xio hooks */ + xiohook_newchild = &socat_newchild; + + if (lockrc = socat_lock()) { + /* =0: goon; >0: locked; <0: error, printed in sub */ + if (lockrc > 0) + Error1("could not obtain lock \"%s\"", socat_opts.lock.lockfile); + Exit(1); + } + + Atexit(socat_unlock); + + result = socat(arg1[0], arg1[1]); + Notice1("exiting with status %d", result); + Exit(result); + return 0; /* not reached, just for gcc -Wall */ +} + + +void socat_usage(FILE *fd) { + fputs(copyright_socat, fd); fputc('\n', fd); + fputs("Usage:\n", fd); + fputs("socat [options] \n", fd); + fputs(" options:\n", fd); + fputs(" -V print version and feature information to stdout, and exit\n", fd); +#if WITH_HELP + fputs(" -h|-? print a help text describing command line options and addresses\n", fd); + fputs(" -hh like -h, plus a list of all common address option names\n", fd); + fputs(" -hhh like -hh, plus a list of all available address option names\n", fd); +#endif /* WITH_HELP */ + fputs(" -d increase verbosity (use up to 4 times; 2 are recommended)\n", fd); +#if WITH_FILAN + fputs(" -D analyze file descriptors before loop\n", fd); +#endif + fputs(" -ly[facility] log to syslog, using facility (default is daemon)\n", fd); + fputs(" -lf log to file\n", fd); + fputs(" -ls log to stderr (default if no other log)\n", fd); + fputs(" -lm[facility] mixed log mode (stderr during initialization, then syslog)\n", fd); + fputs(" -lp set the program name used for logging\n", fd); + fputs(" -lu use microseconds for logging timestamps\n", fd); + fputs(" -lh add hostname to log messages\n", fd); + fputs(" -v verbose data traffic, text\n", fd); + fputs(" -x verbose data traffic, hexadecimal\n", fd); + fputs(" -b set data buffer size (8192)\n", fd); + fputs(" -s sloppy (continue on error)\n", fd); + fputs(" -t wait seconds before closing second channel\n", fd); + fputs(" -T total inactivity timeout in seconds\n", fd); + fputs(" -u unidirectional mode (left to right)\n", fd); + fputs(" -U unidirectional mode (right to left)\n", fd); + fputs(" -g do not check option groups\n", fd); + fputs(" -L try to obtain lock, or fail\n", fd); + fputs(" -W try to obtain lock, or wait\n", fd); +#if WITH_IP4 + fputs(" -4 prefer IPv4 if version is not explicitly specified\n", fd); +#endif +#if WITH_IP6 + fputs(" -6 prefer IPv6 if version is not explicitly specified\n", fd); +#endif +} + + +void socat_version(FILE *fd) { + struct utsname ubuf; + + fputs(copyright_socat, fd); fputc('\n', fd); + fprintf(fd, "socat version %s on %s\n", socatversion, timestamp); + Uname(&ubuf); + fprintf(fd, " running on %s version %s, release %s, machine %s\n", + ubuf.sysname, ubuf.version, ubuf.release, ubuf.machine); + fputs("features:\n", fd); +#ifdef WITH_STDIO + fprintf(fd, " #define WITH_STDIO %d\n", WITH_STDIO); +#else + fputs(" #undef WITH_STDIO\n", fd); +#endif +#ifdef WITH_FDNUM + fprintf(fd, " #define WITH_FDNUM %d\n", WITH_FDNUM); +#else + fputs(" #undef WITH_FDNUM\n", fd); +#endif +#ifdef WITH_FILE + fprintf(fd, " #define WITH_FILE %d\n", WITH_FILE); +#else + fputs(" #undef WITH_FILE\n", fd); +#endif +#ifdef WITH_CREAT + fprintf(fd, " #define WITH_CREAT %d\n", WITH_CREAT); +#else + fputs(" #undef WITH_CREAT\n", fd); +#endif +#ifdef WITH_GOPEN + fprintf(fd, " #define WITH_GOPEN %d\n", WITH_GOPEN); +#else + fputs(" #undef WITH_GOPEN\n", fd); +#endif +#ifdef WITH_TERMIOS + fprintf(fd, " #define WITH_TERMIOS %d\n", WITH_TERMIOS); +#else + fputs(" #undef WITH_TERMIOS\n", fd); +#endif +#ifdef WITH_PIPE + fprintf(fd, " #define WITH_PIPE %d\n", WITH_PIPE); +#else + fputs(" #undef WITH_PIPE\n", fd); +#endif +#ifdef WITH_UNIX + fprintf(fd, " #define WITH_UNIX %d\n", WITH_UNIX); +#else + fputs(" #undef WITH_UNIX\n", fd); +#endif /* WITH_UNIX */ +#ifdef WITH_ABSTRACT_UNIXSOCKET + fprintf(fd, " #define WITH_ABSTRACT_UNIXSOCKET %d\n", WITH_ABSTRACT_UNIXSOCKET); +#else + fputs(" #undef WITH_ABSTRACT_UNIXSOCKET\n", fd); +#endif /* WITH_ABSTRACT_UNIXSOCKET */ +#ifdef WITH_IP4 + fprintf(fd, " #define WITH_IP4 %d\n", WITH_IP4); +#else + fputs(" #undef WITH_IP4\n", fd); +#endif +#ifdef WITH_IP6 + fprintf(fd, " #define WITH_IP6 %d\n", WITH_IP6); +#else + fputs(" #undef WITH_IP6\n", fd); +#endif +#ifdef WITH_RAWIP + fprintf(fd, " #define WITH_RAWIP %d\n", WITH_RAWIP); +#else + fputs(" #undef WITH_RAWIP\n", fd); +#endif +#ifdef WITH_TCP + fprintf(fd, " #define WITH_TCP %d\n", WITH_TCP); +#else + fputs(" #undef WITH_TCP\n", fd); +#endif +#ifdef WITH_UDP + fprintf(fd, " #define WITH_UDP %d\n", WITH_UDP); +#else + fputs(" #undef WITH_UDP\n", fd); +#endif +#ifdef WITH_LISTEN + fprintf(fd, " #define WITH_LISTEN %d\n", WITH_LISTEN); +#else + fputs(" #undef WITH_LISTEN\n", fd); +#endif +#ifdef WITH_SOCKS4 + fprintf(fd, " #define WITH_SOCKS4 %d\n", WITH_SOCKS4); +#else + fputs(" #undef WITH_SOCKS4\n", fd); +#endif +#ifdef WITH_SOCKS4A + fprintf(fd, " #define WITH_SOCKS4A %d\n", WITH_SOCKS4A); +#else + fputs(" #undef WITH_SOCKS4A\n", fd); +#endif +#ifdef WITH_PROXY + fprintf(fd, " #define WITH_PROXY %d\n", WITH_PROXY); +#else + fputs(" #undef WITH_PROXY\n", fd); +#endif +#ifdef WITH_SYSTEM + fprintf(fd, " #define WITH_SYSTEM %d\n", WITH_SYSTEM); +#else + fputs(" #undef WITH_SYSTEM\n", fd); +#endif +#ifdef WITH_EXEC + fprintf(fd, " #define WITH_EXEC %d\n", WITH_EXEC); +#else + fputs(" #undef WITH_EXEC\n", fd); +#endif +#ifdef WITH_READLINE + fprintf(fd, " #define WITH_READLINE %d\n", WITH_READLINE); +#else + fputs(" #undef WITH_READLINE\n", fd); +#endif +#ifdef WITH_TUN + fprintf(fd, " #define WITH_TUN %d\n", WITH_TUN); +#else + fputs(" #undef WITH_TUN\n", fd); +#endif +#ifdef WITH_PTY + fprintf(fd, " #define WITH_PTY %d\n", WITH_PTY); +#else + fputs(" #undef WITH_PTY\n", fd); +#endif +#ifdef WITH_OPENSSL + fprintf(fd, " #define WITH_OPENSSL %d\n", WITH_OPENSSL); +#else + fputs(" #undef WITH_OPENSSL\n", fd); +#endif +#ifdef WITH_FIPS + fprintf(fd, " #define WITH_FIPS %d\n", WITH_FIPS); +#else + fputs(" #undef WITH_FIPS\n", fd); +#endif +#ifdef WITH_LIBWRAP + fprintf(fd, " #define WITH_LIBWRAP %d\n", WITH_LIBWRAP); +#else + fputs(" #undef WITH_LIBWRAP\n", fd); +#endif +#ifdef WITH_SYCLS + fprintf(fd, " #define WITH_SYCLS %d\n", WITH_SYCLS); +#else + fputs(" #undef WITH_SYCLS\n", fd); +#endif +#ifdef WITH_FILAN + fprintf(fd, " #define WITH_FILAN %d\n", WITH_FILAN); +#else + fputs(" #undef WITH_FILAN\n", fd); +#endif +#ifdef WITH_RETRY + fprintf(fd, " #define WITH_RETRY %d\n", WITH_RETRY); +#else + fputs(" #undef WITH_RETRY\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]); +#else + fputs(" #undef WITH_MSGLEVEL\n", fd); +#endif +} + + +xiofile_t *sock1, *sock2; +int closing = 0; /* 0..no eof yet, 1..first eof just occurred, + 2..counting down closing timeout */ + +/* call this function when the common command line options are parsed, and the + addresses are extracted (but not resolved). */ +int socat(const char *address1, const char *address2) { + int mayexec; + +#if 1 + if (Signal(SIGPIPE, SIG_IGN) == SIG_ERR) { + Warn1("signal(SIGPIPE, SIG_IGN): %s", strerror(errno)); + } +#endif + + if (socat_opts.lefttoright) { + if ((sock1 = xioopen(address1, XIO_RDONLY|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) { + return -1; + } + xiosetsigchild(sock1, socat_sigchild); + } else if (socat_opts.righttoleft) { + if ((sock1 = xioopen(address1, XIO_WRONLY|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) { + return -1; + } + xiosetsigchild(sock1, socat_sigchild); + } else { + if ((sock1 = xioopen(address1, XIO_RDWR|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) { + return -1; + } + xiosetsigchild(sock1, socat_sigchild); + } +#if 1 /*! */ + if (XIO_READABLE(sock1) && + (XIO_RDSTREAM(sock1)->howtoend == END_KILL || + XIO_RDSTREAM(sock1)->howtoend == END_CLOSE_KILL || + XIO_RDSTREAM(sock1)->howtoend == END_SHUTDOWN_KILL)) { + if (XIO_RDSTREAM(sock1)->para.exec.pid == diedunknown1) { + /* child has alread died... but it might have put regular data into + the communication channel, so continue */ + Info1("child "F_pid" has already died (diedunknown1)", + XIO_RDSTREAM(sock1)->para.exec.pid); + diedunknown1 = 0; + XIO_RDSTREAM(sock1)->para.exec.pid = 0; + /* return STAT_RETRYLATER; */ + } else if (XIO_RDSTREAM(sock1)->para.exec.pid == diedunknown2) { + Info1("child "F_pid" has already died (diedunknown2)", + XIO_RDSTREAM(sock1)->para.exec.pid); + diedunknown2 = 0; + XIO_RDSTREAM(sock1)->para.exec.pid = 0; + } else if (XIO_RDSTREAM(sock1)->para.exec.pid == diedunknown3) { + Info1("child "F_pid" has already died (diedunknown3)", + XIO_RDSTREAM(sock1)->para.exec.pid); + diedunknown3 = 0; + XIO_RDSTREAM(sock1)->para.exec.pid = 0; + } else if (XIO_RDSTREAM(sock1)->para.exec.pid == diedunknown4) { + Info1("child "F_pid" has already died (diedunknown4)", + XIO_RDSTREAM(sock1)->para.exec.pid); + diedunknown4 = 0; + XIO_RDSTREAM(sock1)->para.exec.pid = 0; + } + } +#endif + + mayexec = (sock1->common.flags&XIO_DOESCONVERT ? 0 : XIO_MAYEXEC); + if (XIO_WRITABLE(sock1)) { + if (XIO_READABLE(sock1)) { + if ((sock2 = xioopen(address2, XIO_RDWR|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) { + return -1; + } + xiosetsigchild(sock2, socat_sigchild); + } else { + if ((sock2 = xioopen(address2, XIO_RDONLY|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) { + return -1; + } + xiosetsigchild(sock2, socat_sigchild); + } + } else { /* assuming sock1 is readable */ + if ((sock2 = xioopen(address2, XIO_WRONLY|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) { + return -1; + } + xiosetsigchild(sock2, socat_sigchild); + } +#if 1 /*! */ + if (XIO_READABLE(sock2) && + (XIO_RDSTREAM(sock2)->howtoend == END_KILL || + XIO_RDSTREAM(sock2)->howtoend == END_CLOSE_KILL || + XIO_RDSTREAM(sock2)->howtoend == END_SHUTDOWN_KILL)) { + if (XIO_RDSTREAM(sock2)->para.exec.pid == diedunknown1) { + /* child has alread died... but it might have put regular data into + the communication channel, so continue */ + Info1("child "F_pid" has already died (diedunknown1)", + XIO_RDSTREAM(sock2)->para.exec.pid); + diedunknown1 = 0; + XIO_RDSTREAM(sock2)->para.exec.pid = 0; + /* return STAT_RETRYLATER; */ + } else if (XIO_RDSTREAM(sock2)->para.exec.pid == diedunknown2) { + Info1("child "F_pid" has already died (diedunknown2)", + XIO_RDSTREAM(sock2)->para.exec.pid); + diedunknown2 = 0; + XIO_RDSTREAM(sock2)->para.exec.pid = 0; + } else if (XIO_RDSTREAM(sock2)->para.exec.pid == diedunknown3) { + Info1("child "F_pid" has already died (diedunknown3)", + XIO_RDSTREAM(sock2)->para.exec.pid); + diedunknown3 = 0; + XIO_RDSTREAM(sock2)->para.exec.pid = 0; + } else if (XIO_RDSTREAM(sock2)->para.exec.pid == diedunknown4) { + Info1("child "F_pid" has already died (diedunknown4)", + XIO_RDSTREAM(sock2)->para.exec.pid); + diedunknown4 = 0; + XIO_RDSTREAM(sock2)->para.exec.pid = 0; + } + } +#endif + + Info("resolved and opened all sock addresses"); + return + _socat(); /* nsocks, sockets are visible outside function */ +} + +/* checks if this is a connection to a child process, and if so, sees if the + child already died, leaving some data for us. + returns <0 if an error occurred; + returns 0 if no child or not yet died or died without data (sets eof); + returns >0 if child died and left data +*/ +int childleftdata(xiofile_t *xfd) { + fd_set in, out, expt; + int retval; + /* have to check if a child process died before, but left read data */ + if (XIO_READABLE(xfd) && + (XIO_RDSTREAM(xfd)->howtoend == END_KILL || + XIO_RDSTREAM(xfd)->howtoend == END_CLOSE_KILL || + XIO_RDSTREAM(xfd)->howtoend == END_SHUTDOWN_KILL) && + XIO_RDSTREAM(xfd)->para.exec.pid == 0) { + struct timeval time0 = { 0,0 }; + + FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt); + if (XIO_READABLE(xfd) && !(XIO_RDSTREAM(xfd)->eof >= 2 && !XIO_RDSTREAM(xfd)->ignoreeof)) { + FD_SET(XIO_GETRDFD(xfd), &in); + /*0 FD_SET(XIO_GETRDFD(xfd), &expt);*/ + } + do { + retval = Select(FOPEN_MAX, &in, &out, &expt, &time0); + } while (retval < 0 && errno == EINTR); + + if (retval < 0) { +#if HAVE_FDS_BITS + Error5("select(%d, &0x%lx, &0x%lx, &0x%lx, {0}): %s", + FOPEN_MAX, in.fds_bits[0], out.fds_bits[0], + expt.fds_bits[0], strerror(errno)); +#else + Error5("select(%d, &0x%lx, &0x%lx, &0x%lx, {0}): %s", + FOPEN_MAX, in.__fds_bits[0], out.__fds_bits[0], + expt.__fds_bits[0], strerror(errno)); +#endif + return -1; + } else if (retval == 0) { + Info("terminated child did not leave data for us"); + XIO_RDSTREAM(xfd)->eof = 2; + xfd->stream.eof = 2; + closing = MAX(closing, 1); + } + } + return 0; +} + +int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe, + unsigned char **buff, size_t bufsiz, bool righttoleft); + +bool mayrd1; /* sock1 has read data or eof, according to select() */ +bool mayrd2; /* sock2 has read data or eof, according to select() */ +bool maywr1; /* sock1 can be written to, according to select() */ +bool maywr2; /* sock2 can be written to, according to select() */ + +/* here we come when the sockets are opened (in the meaning of C language), + and their options are set/applied + returns -1 on error or 0 on success */ +int _socat(void) { + fd_set in, out, expt; + int retval; + unsigned char *buff; + ssize_t bytes1, bytes2; + int polling = 0; /* handling ignoreeof */ + int wasaction = 1; /* last select was active, do NOT sleep before next */ + struct timeval total_timeout; /* the actual total timeout timer */ + +#if WITH_FILAN + if (socat_opts.debug) { + int fdi, fdo; + int msglevel, exitlevel; + + msglevel = diag_get_int('D'); /* save current message level */ + diag_set_int('D', E_ERROR); /* only print errors and fatals in filan */ + exitlevel = diag_get_int('e'); /* save current exit level */ + diag_set_int('e', E_FATAL); /* only exit on fatals */ + + fdi = XIO_GETRDFD(sock1); + fdo = XIO_GETWRFD(sock1); + filan_fd(fdi, stderr); + if (fdo != fdi) { + filan_fd(fdo, stderr); + } + + fdi = XIO_GETRDFD(sock2); + fdo = XIO_GETWRFD(sock2); + filan_fd(fdi, stderr); + if (fdo != fdi) { + filan_fd(fdo, stderr); + } + + diag_set_int('e', exitlevel); /* restore old exit level */ + diag_set_int('D', msglevel); /* restore old message level */ + } +#endif /* WITH_FILAN */ + + /* when converting nl to crnl, size might double */ + buff = Malloc(2*socat_opts.bufsiz+1); + if (buff == NULL) return -1; + + if (socat_opts.logopt == 'm' && xioinqopt('l', NULL, 0) == 'm') { + Info("switching to syslog"); + diag_set('y', xioopts.syslogfac); + xiosetopt('l', "\0"); + } + total_timeout = socat_opts.total_timeout; + + Notice4("starting data transfer loop with FDs [%d,%d] and [%d,%d]", + XIO_GETRDFD(sock1), XIO_GETWRFD(sock1), + XIO_GETRDFD(sock2), XIO_GETWRFD(sock2)); + while (XIO_RDSTREAM(sock1)->eof <= 1 || + XIO_RDSTREAM(sock2)->eof <= 1) { + struct timeval timeout, *to = NULL; + + Debug6("data loop: sock1->eof=%d, sock2->eof=%d, closing=%d, wasaction=%d, total_to={"F_tv_sec"."F_tv_usec"}", + XIO_RDSTREAM(sock1)->eof, XIO_RDSTREAM(sock2)->eof, + closing, wasaction, + total_timeout.tv_sec, total_timeout.tv_usec); + + /* for ignoreeof */ + if (polling) { + if (!wasaction) { + /* yes we could do it with select but I like readable trace output */ + if (socat_opts.pollintv.tv_sec) Sleep(socat_opts.pollintv.tv_sec); + if (socat_opts.pollintv.tv_usec) Usleep(socat_opts.pollintv.tv_usec); + + if (socat_opts.total_timeout.tv_sec != 0 || + socat_opts.total_timeout.tv_usec != 0) { + if (total_timeout.tv_usec < socat_opts.pollintv.tv_usec) { + total_timeout.tv_usec += 1000000; + total_timeout.tv_sec -= 1; + } + total_timeout.tv_sec -= socat_opts.pollintv.tv_sec; + total_timeout.tv_usec -= socat_opts.pollintv.tv_usec; + if (total_timeout.tv_sec < 0 || + total_timeout.tv_sec == 0 && total_timeout.tv_usec < 0) { + Notice("inactivity timeout triggered"); + return 0; + } + } + + } else { + wasaction = 0; + } + } + + if (polling) { + /* 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) { + /* there might occur a total inactivity timeout */ + timeout = socat_opts.total_timeout; + to = &timeout; + } else { + to = NULL; + } + + if (closing>=1) { + /* first eof already occurred, start end timer */ + timeout = socat_opts.closwait; + to = &timeout; + closing = 2; + } + + do { + int _errno; + FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt); + + childleftdata(sock1); + childleftdata(sock2); + + if (closing>=1) { + /* first eof already occurred, start end timer */ + timeout = socat_opts.closwait; + to = &timeout; + closing = 2; + } + + if (XIO_READABLE(sock1) && + !(XIO_RDSTREAM(sock1)->eof > 1 && !XIO_RDSTREAM(sock1)->ignoreeof) && + !socat_opts.righttoleft) { + if (!mayrd1) { + FD_SET(XIO_GETRDFD(sock1), &in); + } + if (!maywr2) { + FD_SET(XIO_GETWRFD(sock2), &out); + } + } + if (XIO_READABLE(sock2) && + !(XIO_RDSTREAM(sock2)->eof > 1 && !XIO_RDSTREAM(sock2)->ignoreeof) && + !socat_opts.lefttoright) { + if (!mayrd2) { + FD_SET(XIO_GETRDFD(sock2), &in); + } + if (!maywr1) { + FD_SET(XIO_GETWRFD(sock1), &out); + } + } + retval = Select(FOPEN_MAX, &in, &out, &expt, to); + _errno = errno; + if (retval < 0 && errno == EINTR) { + Info1("select(): %s", strerror(errno)); + } + errno = _errno; + } while (retval < 0 && errno == EINTR); + + /* attention: + when an exec'd process sends data and terminates, it is unpredictable + whether the data or the sigchild arrives first. + */ + + if (retval < 0) { +#if HAVE_FDS_BITS + Error7("select(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu): %s", + FOPEN_MAX, in.fds_bits[0], out.fds_bits[0], + expt.fds_bits[0], to?"&":"NULL/", to?to->tv_sec:0, + strerror(errno)); +#else + Error7("select(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu): %s", + FOPEN_MAX, in.__fds_bits[0], out.__fds_bits[0], + expt.__fds_bits[0], to?"&":"NULL/", to?to->tv_sec:0, + strerror(errno)); +#endif + return -1; + } else if (retval == 0) { + Info2("select timed out (no data within %ld.%06ld seconds)", + closing>=1?socat_opts.closwait.tv_sec:socat_opts.total_timeout.tv_sec, + closing>=1?socat_opts.closwait.tv_usec:socat_opts.total_timeout.tv_usec); + if (polling && !wasaction) { + /* there was a ignoreeof poll timeout, use it */ + ; + } else if (socat_opts.total_timeout.tv_sec != 0 || + socat_opts.total_timeout.tv_usec != 0) { + /* there was a total inactivity timeout */ + Notice("inactivity timeout triggered"); + return 0; + } + + if (closing) { + break; + } + /* one possibility to come here is ignoreeof on some fd, but no EOF + and no data on any descriptor - this is no indication for end! */ + continue; + } + + if (XIO_READABLE(sock1) && XIO_GETRDFD(sock1) >= 0 && + FD_ISSET(XIO_GETRDFD(sock1), &in)) { + mayrd1 = true; + } + if (XIO_READABLE(sock2) && XIO_GETRDFD(sock2) >= 0 && + FD_ISSET(XIO_GETRDFD(sock2), &in)) { + mayrd2 = true; + } + if (XIO_GETWRFD(sock1) >= 0 && FD_ISSET(XIO_GETWRFD(sock1), &out)) { + maywr1 = true; + } + if (XIO_GETWRFD(sock2) >= 0 && FD_ISSET(XIO_GETWRFD(sock2), &out)) { + maywr2 = true; + } + + if (mayrd1 && maywr2) { + mayrd1 = false; + if ((bytes1 = xiotransfer(sock1, sock2, &buff, socat_opts.bufsiz, false)) + < 0) { + if (errno != EAGAIN) { + closing = MAX(closing, 1); + Notice("socket 1 to socket 2 is in error"); + if (socat_opts.lefttoright) { + break; + } + } + } else if (bytes1 > 0) { + maywr2 = false; + total_timeout = socat_opts.total_timeout; + wasaction = 1; + /* is more data available that has already passed select()? */ + mayrd1 = (xiopending(sock1) > 0); + if (XIO_RDSTREAM(sock1)->readbytes != 0 && + XIO_RDSTREAM(sock1)->actbytes == 0) { + /* avoid idle when all readbytes already there */ + mayrd1 = true; + } + } + /* (bytes1 == 0) handled later */ + } else { + bytes1 = -1; + } + + if (mayrd2 && maywr1) { + mayrd2 = false; + if ((bytes2 = xiotransfer(sock2, sock1, &buff, socat_opts.bufsiz, true)) + < 0) { + if (errno != EAGAIN) { + closing = MAX(closing, 1); + Notice("socket 2 to socket 1 is in error"); + if (socat_opts.righttoleft) { + break; + } + } + } else if (bytes2 > 0) { + maywr1 = false; + total_timeout = socat_opts.total_timeout; + wasaction = 1; + /* is more data available that has already passed select()? */ + mayrd2 = (xiopending(sock2) > 0); + if (XIO_RDSTREAM(sock2)->readbytes != 0 && + XIO_RDSTREAM(sock2)->actbytes == 0) { + /* avoid idle when all readbytes already there */ + mayrd2 = true; + } + } + /* (bytes2 == 0) handled later */ + } else { + bytes2 = -1; + } + + /* NOW handle EOFs */ + + if (bytes1 == 0 || XIO_RDSTREAM(sock1)->eof >= 2) { + if (XIO_RDSTREAM(sock1)->ignoreeof && !closing) { + Debug1("socket 1 (fd %d) is at EOF, ignoring", + XIO_RDSTREAM(sock1)->fd); /*! */ + polling = 1; + } else { + Notice1("socket 1 (fd %d) is at EOF", XIO_GETRDFD(sock1)); + xioshutdown(sock2, SHUT_WR); + if (socat_opts.lefttoright) { + break; + } + } + } + + if (bytes2 == 0 || XIO_RDSTREAM(sock2)->eof >= 2) { + if (XIO_RDSTREAM(sock2)->ignoreeof && !closing) { + Debug1("socket 2 (fd %d) is at EOF, ignoring", + XIO_RDSTREAM(sock2)->fd); + polling = 1; + } else { + Notice1("socket 2 (fd %d) is at EOF", XIO_GETRDFD(sock2)); + xioshutdown(sock1, SHUT_WR); + if (socat_opts.righttoleft) { + break; + } + } + } + } + + /* close everything that's still open */ + xioclose(sock1); + xioclose(sock2); + + return 0; +} + + +#define MAXTIMESTAMPLEN 128 +/* prints the timestamp to the buffer and terminates it with '\0'. This buffer + 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_GETTIMEOFDAY || 1 + struct timeval now; + int result; + time_t nowt; +#else /* !HAVE_GETTIMEOFDAY */ + time_t now; +#endif /* !HAVE_GETTIMEOFDAY */ + +#if HAVE_GETTIMEOFDAY || 1 + result = gettimeofday(&now, NULL); + if (result < 0) { + return result; + } else { + nowt = now.tv_sec; +#if HAVE_STRFTIME + bytes = strftime(timestamp, 20, "%Y/%m/%d %H:%M:%S", localtime(&nowt)); + bytes += sprintf(timestamp+19, "."F_tv_usec" ", now.tv_usec); +#else + strcpy(timestamp, ctime(&nowt)); + bytes = strlen(timestamp); +#endif + } +#else /* !HAVE_GETTIMEOFDAY */ + now = time(NULL); if (now == (time_t)-1) { + return -1; + } else { +#if HAVE_STRFTIME + bytes = strftime(timestamp, 21, "%Y/%m/%d %H:%M:%S ", localtime(&now)); +#else + strcpy(timestamp, ctime(&now)); + bytes = strlen(timestamp); +#endif + } +#endif /* !HAVE_GETTIMEOFDAY */ + return 0; +} + +static const char *prefixltor = "> "; +static const char *prefixrtol = "< "; +static unsigned long numltor; +static unsigned long numrtol; +/* print block header (during verbose or hex dump) + returns 0 on success or -1 if an error occurred */ +static int + xioprintblockheader(FILE *file, size_t bytes, bool righttoleft) { + char timestamp[MAXTIMESTAMPLEN]; + char buff[128+MAXTIMESTAMPLEN]; + if (gettimestamp(timestamp) < 0) { + return -1; + } + if (righttoleft) { + sprintf(buff, "%s%s length="F_Zu" from=%lu to=%lu\n", + prefixrtol, timestamp, bytes, numrtol, numrtol+bytes-1); + numrtol+=bytes; + } else { + sprintf(buff, "%s%s length="F_Zu" from=%lu to=%lu\n", + prefixltor, timestamp, bytes, numltor, numltor+bytes-1); + numltor+=bytes; + } + fputs(buff, file); + return 0; +} + + +/* inpipe is suspected to have read data available; read at most bufsiz bytes + and transfer them to outpipe. Perform required data conversions. + buff should be at least twice as large as bufsiz, to allow all standard + conversions. Returns the number of bytes written, or 0 on EOF or <0 if an + error occurred or when data was read but none written due to conversions + (with EAGAIN). EAGAIN also occurs when reading from a nonblocking FD where + the file has a mandatory lock. + If 0 bytes were read (EOF), it does NOT shutdown or close a channel, and it + does NOT write a zero bytes block. + */ +/* inpipe, outpipe must be single descriptors (not dual!) */ +int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe, + unsigned char **buff, size_t bufsiz, bool righttoleft) { + ssize_t bytes, writt; + + bytes = xioread(inpipe, *buff, socat_opts.bufsiz); + if (bytes < 0) { + if (errno != EAGAIN) + XIO_RDSTREAM(inpipe)->eof = 2; + /*xioshutdown(inpipe, SHUT_RD);*/ + return -1; + } + if (bytes == 0 && XIO_RDSTREAM(inpipe)->ignoreeof && !closing) { + writt = 0; + } else if (bytes == 0) { + XIO_RDSTREAM(inpipe)->eof = 2; + closing = MAX(closing, 1); + writt = 0; + } + + else /* if (bytes > 0)*/ { + + if (XIO_RDSTREAM(inpipe)->lineterm != + XIO_WRSTREAM(outpipe)->lineterm) { + cv_newline(buff, &bytes, + XIO_RDSTREAM(inpipe)->lineterm, + XIO_WRSTREAM(outpipe)->lineterm); + } + if (bytes == 0) { + errno = EAGAIN; return -1; + } + + if (socat_opts.verbose && socat_opts.verbhex) { + /* Hack-o-rama */ + size_t i = 0; + size_t j; + size_t N = 16; + const unsigned char *end, *s, *t; + s = *buff; + end = (*buff)+bytes; + xioprintblockheader(stderr, bytes, righttoleft); + while (s < end) { + /*! prefix? */ + j = Min(N, (size_t)(end-s)); + + /* print hex */ + t = s; + i = 0; + while (i < j) { + int c = *t++; + fprintf(stderr, " %02x", c); + ++i; + if (c == '\n') break; + } + + /* fill hex column */ + while (i < N) { + fputs(" ", stderr); + ++i; + } + fputs(" ", stderr); + + /* print acsii */ + t = s; + i = 0; + while (i < j) { + int c = *t++; + if (c == '\n') { + fputc('.', stderr); + break; + } + if (!isprint(c)) + c = '.'; + fputc(c, stderr); + ++i; + } + + fputc('\n', stderr); + s = t; + } + fputs("--\n", stderr); + } else if (socat_opts.verbose) { + size_t i = 0; + xioprintblockheader(stderr, bytes, righttoleft); + while (i < (size_t)bytes) { + int c = (*buff)[i]; + if (i > 0 && (*buff)[i-1] == '\n') + /*! prefix? */; + switch (c) { + case '\a' : fputs("\\a", stderr); break; + case '\b' : fputs("\\b", stderr); break; + case '\t' : fputs("\t", stderr); break; + case '\n' : fputs("\n", stderr); break; + case '\v' : fputs("\\v", stderr); break; + case '\f' : fputs("\\f", stderr); break; + case '\r' : fputs("\\r", stderr); break; + case '\\' : fputs("\\\\", stderr); break; + default: + if (!isprint(c)) + c = '.'; + fputc(c, stderr); + break; + } + ++i; + } + } else if (socat_opts.verbhex) { + int i; + /*! prefix? */ + for (i = 0; i < bytes; ++i) { + fprintf(stderr, " %02x", (*buff)[i]); + } + fputc('\n', stderr); + } + + writt = xiowrite(outpipe, *buff, bytes); + if (writt < 0) { + /* EAGAIN when nonblocking but a mandatory lock is on file. + the problem with EAGAIN is that the read cannot be repeated, + so we need to buffer the data and try to write it later + again. not yet implemented, sorry. */ +#if 0 + if (errno == EPIPE) { + return 0; /* can no longer write; handle like EOF */ + } +#endif + return -1; + } else { + Info3("transferred "F_Zu" bytes from %d to %d", + writt, XIO_GETRDFD(inpipe), XIO_GETWRFD(outpipe)); + } + } + return writt; +} + +#define CR '\r' +#define LF '\n' + + +int cv_newline(unsigned char **buff, ssize_t *bytes, + int lineterm1, int lineterm2) { + /* must perform newline changes */ + if (lineterm1 <= LINETERM_CR && lineterm2 <= LINETERM_CR) { + /* no change in data length */ + unsigned char from, to, *p, *z; + if (lineterm1 == LINETERM_RAW) { + from = '\n'; to = '\r'; + } else { + from = '\r'; to = '\n'; + } + z = *buff + *bytes; + p = *buff; + while (p < z) { + if (*p == from) *p = to; + ++p; + } + + } else if (lineterm1 == LINETERM_CRNL) { + /* buffer becomes shorter */ + unsigned char to, *s, *t, *z; + if (lineterm2 == LINETERM_RAW) { + to = '\n'; + } else { + to = '\r'; + } + z = *buff + *bytes; + s = t = *buff; + while (s < z) { + if (*s == '\r') { + ++s; + continue; + } + if (*s == '\n') { + *t++ = to; ++s; + } else { + *t++ = *s++; + } + } + *bytes = t - *buff; + } else { + /* buffer becomes longer, must alloc another space */ + unsigned char *buf2; + unsigned char from; unsigned char *s, *t, *z; + if (lineterm1 == LINETERM_RAW) { + from = '\n'; + } else { + from = '\r'; + } + if ((buf2 = Malloc(2*socat_opts.bufsiz+1)) == NULL) { + return -1; + } + s = *buff; t = buf2; z = *buff + *bytes; + while (s < z) { + if (*s == from) { + *t++ = '\r'; *t++ = '\n'; + ++s; + continue; + } else { + *t++ = *s++; + } + } + free(*buff); + *buff = buf2; + *bytes = t - buf2;; + } + return 0; +} + +void socat_signal(int signum) { + switch (signum) { + case SIGQUIT: + case SIGILL: + case SIGABRT: + case SIGBUS: + case SIGFPE: + case SIGSEGV: + case SIGPIPE: + diag_set_int('x', 128+signum); /* in case Error exits for us */ + Error1("exiting on signal %d", signum); + diag_set_int('x', 0); /* in case Error did not exit */ + break; + case SIGTERM: + Warn1("exiting on signal %d", signum); break; + case SIGHUP: + case SIGINT: + Notice1("exiting on signal %d", signum); break; + } + Exit(128+signum); +} + +/* this is the callback when the child of an address died */ +static int socat_sigchild(struct single *file) { + if (file->ignoreeof && !closing) { + ; + } else { + file->eof = MAX(file->eof, 1); + closing = 1; + } + return 0; +} + +static int socat_lock(void) { + int lockrc; + +#if 1 + if ((lockrc = xiolock(&socat_opts.lock)) < 0) { + return -1; + } + if (lockrc == 0) { + havelock = true; + } + return lockrc; +#else + if (socat_opts.lock.lockfile) { + if ((lockrc = xiolock(socat_opts.lock.lockfile)) < 0) { + /*Error1("error with lockfile \"%s\"", socat_opts.lock.lockfile);*/ + return -1; + } + if (lockrc) { + return 1; + } + havelock = true; + /*0 Info1("obtained lock \"%s\"", socat_opts.lock.lockfile);*/ + } + + if (socat_opts.lock.waitlock) { + if (xiowaitlock(socat_opts.lock.waitlock, socat_opts.lock.intervall)) { + /*Error1("error with lockfile \"%s\"", socat_opts.lock.lockfile);*/ + return -1; + } else { + havelock = true; + /*0 Info1("obtained lock \"%s\"", socat_opts.lock.waitlock);*/ + } + } + return 0; +#endif +} + +static void socat_unlock(void) { + if (!havelock) return; + if (socat_opts.lock.lockfile) { + if (Unlink(socat_opts.lock.lockfile) < 0) { + Warn2("unlink(\"%s\"): %s", + socat_opts.lock.lockfile, strerror(errno)); + } else { + Info1("released lock \"%s\"", socat_opts.lock.lockfile); + } + } +} + +/* this is a callback function that may be called by the newchild hook of xio + */ +static int socat_newchild(void) { + havelock = false; + return 0; +} diff --git a/socat.spec b/socat.spec new file mode 100644 index 0000000..db6beac --- /dev/null +++ b/socat.spec @@ -0,0 +1,52 @@ + +%define majorver 1.6 +%define minorver 0.0 + +Summary: socat - multipurpose relay +Name: socat +Version: %{majorver}.%{minorver} +Release: 1 +Copyright: GPL +Group: Applications/Communications +Source0: http://www.dest-unreach.org/socat/download/socat-%{version}.tar.gz +Requires: readline +Requires: openssl +BuildRoot: /var/tmp/%{name}-buildroot + +%description +socat is a relay for bidirectional data transfer between two independent data +channels. Each of these data channels may be a file, pipe, device (terminal or +modem etc.), socket (UNIX, IP4, IP6 - raw, UDP, TCP), a file descriptor (stdin +etc.), a program, or an arbitrary combination of two of these. + +%prep +%setup -n %{name}-%{majorver} + +%build +# the CPPFLAGS setting is required for RedHat Linux +if [ -d /usr/kerberos/include ]; then + CPPFLAGS="-I/usr/kerberos/include" ./configure --prefix=%{_prefix} --mandir=%{_mandir} +else + ./configure --prefix=%{_prefix} --mandir=%{_mandir} +fi +make + +%install +rm -rf $RPM_BUILD_ROOT + +mkdir -p $RPM_BUILD_ROOT%{_bindir} +mkdir -p $RPM_BUILD_ROOT%{_mandir}/man1 + +make install DESTDIR=$RPM_BUILD_ROOT + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +%doc README CHANGES EXAMPLES SECURITY xio.help socat.html FAQ BUGREPORTS +%doc COPYING COPYING.OpenSSL FILES PORTING DEVELOPMENT +%{_bindir}/socat +%{_bindir}/procan +%{_bindir}/filan +%{_mandir}/man1/socat.1* diff --git a/socks4a-echo.sh b/socks4a-echo.sh new file mode 100755 index 0000000..2ab8142 --- /dev/null +++ b/socks4a-echo.sh @@ -0,0 +1,114 @@ +#! /bin/bash +# $Id: socks4a-echo.sh,v 1.2 2004/08/25 16:01:30 gerhard Exp $ +#set -vx + +# Copyright Gerhard Rieger 2004 +# Published under the GNU General Public License V.2, see file COPYING + +# perform primitive simulation of a socks4a server with echo function via stdio. +# accepts and answers correct SOCKS4a requests, but then just echoes data. +# it is required for test.sh +# for TCP, use this script as: +# socat tcp-l:1080,reuseaddr,crlf system:"socks4a-echo.sh" + +# 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 + HAVE_READ_N=1 +else + HAVE_READ_N= +fi + +if 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 + +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 + exit 1 +fi +ECHO="echo $E" + +if [ $($ECHO "\0101") = "A" ]; then + SOCKSREPLY_FAILED="\0\0133\0\0\0\0\0\0\c" + SOCKSREPLY_OK="\0\0132\0\0\0\0\0\0\c" +else + SOCKSREPLY_FAILED="\0\133\0\0\0\0\0\0\c" + SOCKSREPLY_OK="\0\132\0\0\0\0\0\0\c" +fi + +# read and parse SOCKS4a header +if [ "$HAVE_READ_N" ]; then + read -r -n 1 vn # bash 2.0.3 does not support -n +else + vn=$(dd bs=1 count=1 2>/dev/null) +fi +if [ "$vn" != $($ECHO "\04") ]; then + $ECHO "$SOCKSREPLY_FAILED" + echo "invalid socks version requested" >&2 + exit +fi + +if [ "$HAVE_READ_N" ]; then + read -r -n 1 cd +else + cd=$(dd bs=1 count=1 2>/dev/null) +fi +if [ "$cd" != $($ECHO "\01") ]; then + $ECHO "$SOCKSREPLY_FAILED" + echo "invalid socks operation requested" >&2 + exit +fi + +a=$(dd bs=1 count=6 2>/dev/null) +#echo a a a >/dev/tty +#echo "$a" |od -c >/dev/tty +#$ECHO "$a" |od -c >/dev/tty +#echo>/dev/tty +#echo a a a >/dev/tty +if [ "$a" != "$($ECHO "}m\0\0\0\01")" ]; then + sleep 1 + $ECHO "$SOCKSREPLY_FAILED" + echo "wrong socks address or port requested" >&2 + exit +fi + +if [ "$HAVE_READ_N" ]; then + read -r -n 7 u +else + u=$(dd bs=1 count=7 2>/dev/null) +fi +if [ "$u" != "nobody" ]; then + $ECHO "$SOCKSREPLY_FAILED" + echo "wrong socks user requested" >&2 + exit +fi + +if [ "$HAVE_READ_N" ]; then + read -r -n 10 h +else + h=$(dd bs=1 count=10 2>/dev/null) +fi +if [ "$h" != "localhost" ]; then + $ECHO "$SOCKSREPLY_FAILED" + echo "wrong socks address requested" >&2 + exit +fi + +# send ok status +$ECHO "$SOCKSREPLY_OK" + +# perform echo function +$CAT diff --git a/socks4echo.sh b/socks4echo.sh new file mode 100755 index 0000000..343d32f --- /dev/null +++ b/socks4echo.sh @@ -0,0 +1,101 @@ +#! /bin/bash +# $Id: socks4echo.sh,v 1.4 2006/03/21 18:48:53 gerhard Exp $ + +# Copyright Gerhard Rieger 2004-2006 +# Published under the GNU General Public License V.2, see file COPYING + +# perform primitive simulation of a socks4 server with echo function via stdio. +# accepts and answers correct SOCKS4 requests, but then just echoes data. +# it is required for test.sh +# for TCP, use this script as: +# socat tcp-l:1080,reuseaddr,crlf system:"socks4echo.sh" + +# 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 + HAVE_READ_N=1 +else + HAVE_READ_N= +fi + +if 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 + +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 + exit 1 +fi +ECHO="echo $E" + +if [ $($ECHO "\0101") = "A" ]; then + SOCKSREPLY_FAILED="\0\0133\0\0\0\0\0\0\c" + SOCKSREPLY_OK="\0\0132\0\0\0\0\0\0\c" +else + SOCKSREPLY_FAILED="\0\133\0\0\0\0\0\0\c" + SOCKSREPLY_OK="\0\132\0\0\0\0\0\0\c" +fi + +# read and parse SOCKS4 header +if [ "$HAVE_READ_N" ]; then + read -r -n 1 vn # bash 2.0.3 does not support -n +else + vn=$(dd bs=1 count=1 2>/dev/null) +fi +if [ "$vn" != $($ECHO "\04") ]; then + $ECHO "$SOCKSREPLY_FAILED" + echo "invalid socks version requested" >&2 + exit +fi + +if [ "$HAVE_READ_N" ]; then + read -r -n 1 cd +else + cd=$(dd bs=1 count=1 2>/dev/null) +fi +if [ "$cd" != $($ECHO "\01") ]; then + $ECHO "$SOCKSREPLY_FAILED" + echo "invalid socks operation requested" >&2 + exit +fi + +if [ "$HAVE_READ_N" ]; then + read -r -n 6 a +else + a=$(dd bs=1 count=6 2>/dev/null) +fi +if [ "$a" != "$($ECHO "}m bL6")" ]; then + $ECHO "$SOCKSREPLY_FAILED" + echo "$0: wrong socks address or port requested" >&2 + echo "$0: expected $($ECHO "}m bL6"|od -t x1), received $($ECHO "$a"|od -t x1)" >&2 + exit +fi + +if [ "$HAVE_READ_N" ]; then + read -r -n 7 u +else + u=$(dd bs=1 count=7 2>/dev/null) +fi +if [ "$u" != "nobody" ]; then + $ECHO "$SOCKSREPLY_FAILED" + echo "wrong socks user requested" >&2 + exit +fi + +# send ok status +$ECHO "$SOCKSREPLY_OK" + +# perform echo function +$CAT diff --git a/sslcls.c b/sslcls.c new file mode 100644 index 0000000..5bea174 --- /dev/null +++ b/sslcls.c @@ -0,0 +1,318 @@ +/* $Id: sslcls.c,v 1.8 2007/02/26 21:30:58 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* explicit system call and C library trace function, for those who miss strace + */ + +#include "config.h" +#include "xioconfig.h" /* what features are enabled */ + +#if WITH_SYCLS && WITH_OPENSSL + +#include "sysincludes.h" + +#include "mytypes.h" +#include "compat.h" +#include "errno.h" + +#include "error.h" +#include "filan.h" +#include "sysutils.h" +#include "sycls.h" + +void sycSSL_load_error_strings(void) { + Debug("SSL_load_error_strings()"); + SSL_load_error_strings(); + Debug("SSL_load_error_strings() ->"); +} + +int sycSSL_library_init(void) { + int result; + Debug("SSL_library_init()"); + result = SSL_library_init(); + Debug1("SSL_library_init() -> %d", result); + return result; +} + +SSL_METHOD *sycSSLv2_client_method(void) { + SSL_METHOD *result; + Debug("SSLv2_client_method()"); + result = SSLv2_client_method(); + Debug1("SSLv2_client_method() -> %p", result); + return result; +} + +SSL_METHOD *sycSSLv2_server_method(void) { + SSL_METHOD *result; + Debug("SSLv2_server_method()"); + result = SSLv2_server_method(); + Debug1("SSLv2_server_method() -> %p", result); + return result; +} + +SSL_METHOD *sycSSLv3_client_method(void) { + SSL_METHOD *result; + Debug("SSLv3_client_method()"); + result = SSLv3_client_method(); + Debug1("SSLv3_client_method() -> %p", result); + return result; +} + +SSL_METHOD *sycSSLv3_server_method(void) { + SSL_METHOD *result; + Debug("SSLv3_server_method()"); + result = SSLv3_server_method(); + Debug1("SSLv3_server_method() -> %p", result); + return result; +} + +SSL_METHOD *sycSSLv23_client_method(void) { + SSL_METHOD *result; + Debug("SSLv23_client_method()"); + result = SSLv23_client_method(); + Debug1("SSLv23_client_method() -> %p", result); + return result; +} + +SSL_METHOD *sycSSLv23_server_method(void) { + SSL_METHOD *result; + Debug("SSLv23_server_method()"); + result = SSLv23_server_method(); + Debug1("SSLv23_server_method() -> %p", result); + return result; +} + +SSL_METHOD *sycTLSv1_client_method(void) { + SSL_METHOD *result; + Debug("TLSv1_client_method()"); + result = TLSv1_client_method(); + Debug1("TLSv1_client_method() -> %p", result); + return result; +} + +SSL_METHOD *sycTLSv1_server_method(void) { + SSL_METHOD *result; + Debug("TLSv1_server_method()"); + result = TLSv1_server_method(); + Debug1("TLSv1_server_method() -> %p", result); + return result; +} + +SSL_CTX *sycSSL_CTX_new(SSL_METHOD *method) { + SSL_CTX *result; + Debug1("SSL_CTX_new(%p)", method); + result = SSL_CTX_new(method); + Debug1("SSL_CTX_new() -> %p", result); + return result; +} + +SSL *sycSSL_new(SSL_CTX *ctx) { + SSL *result; + Debug1("SSL_new(%p)", ctx); + result = SSL_new(ctx); + Debug1("SSL_new() -> %p", result); + return result; +} + +int sycSSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, + const char *CApath) { + int result; + Debug7("SSL_CTX_load_verify_locations(%p, %s%s%s, %s%s%s)", ctx, + CAfile?"\"":"", CAfile?CAfile:NULL, CAfile?"\"":"", + CApath?"\"":"", CApath?CApath:NULL, CApath?"\"":""); + result = SSL_CTX_load_verify_locations(ctx, CAfile, CApath); + Debug1("SSL_CTX_load_verify_locations() -> %d", result); + return result; +} + +int sycSSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type) { + int result; + Debug3("SSL_CTX_use_certificate_file(%p, \"%s\", %d)", ctx, file, type); + result = SSL_CTX_use_certificate_file(ctx, file, type); + Debug1("SSL_CTX_use_certificate_file() -> %d", result); + return result; +} + +int sycSSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) { + int result; + Debug2("SSL_CTX_use_certificate_chain_file(%p, \"%s\")", ctx, file); + result = SSL_CTX_use_certificate_chain_file(ctx, file); + Debug1("SSL_CTX_use_certificate_chain_file() -> %d", result); + return result; +} + +int sycSSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) { + int result; + Debug3("SSL_CTX_use_PrivateKey_file(%p, \"%s\", %d)", ctx, file, type); + result = SSL_CTX_use_PrivateKey_file(ctx, file, type); + Debug1("SSL_CTX_use_PrivateKey_file() -> %d", result); + return result; +} + +void sycSSL_CTX_set_verify(SSL_CTX *ctx, int mode, + int (*verify_callback)(int, X509_STORE_CTX *)) { + Debug3("SSL_CTX_set_verify(%p, %u, %p)", ctx, mode, verify_callback); + SSL_CTX_set_verify(ctx, mode, verify_callback); + Debug("SSL_CTX_set_verify() -> "); +} + +int sycSSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) { + int result; + Debug2("SSL_CTX_set_cipher_list(%p, \"%s\")", ctx, str); + result = SSL_CTX_set_cipher_list(ctx, str); + Debug1("SSL_CTX_set_cipher_list() -> %d", result); + return result; +} + +int sycSSL_CTX_set_tmp_dh(SSL_CTX *ctx, DH *dh) { + int result; + Debug2("SSL_CTX_set_tmp_dh(%p, %p)", ctx, dh); + result = SSL_CTX_set_tmp_dh(ctx, dh); + Debug1("SSL_CTX_set_tmp_dh() -> %d", result); + return result; +} + +int sycSSL_set_cipher_list(SSL *ssl, const char *str) { + int result; + Debug2("SSL_set_cipher_list(%p, \"%s\")", ssl, str); + result = SSL_set_cipher_list(ssl, str); + Debug1("SSL_set_cipher_list() -> %d", result); + return result; +} + +long sycSSL_get_verify_result(SSL *ssl) { + long result; + Debug1("SSL_get_verify_result(%p)", ssl); + result = SSL_get_verify_result(ssl); + Debug1("SSL_get_verify_result() -> %lx", result); + return result; +} + +int sycSSL_set_fd(SSL *ssl, int fd) { + int result; + Debug2("SSL_set_fd(%p, %d)", ssl, fd); + result = SSL_set_fd(ssl, fd); + Debug1("SSL_set_fd() -> %d", result); + return result; +} + +int sycSSL_connect(SSL *ssl) { + int result; + Debug1("SSL_connect(%p)", ssl); + result = SSL_connect(ssl); + Debug1("SSL_connect() -> %d", result); + return result; +} + +int sycSSL_accept(SSL *ssl) { + int result; + Debug1("SSL_accept(%p)", ssl); + result = SSL_accept(ssl); + Debug1("SSL_accept() -> %d", result); + return result; +} + +int sycSSL_read(SSL *ssl, void *buf, int num) { + int result; + Debug3("SSL_read(%p, %p, %d)", ssl, buf, num); + result = SSL_read(ssl, buf, num); + Debug1("SSL_read() -> %d", result); + return result; +} + +int sycSSL_pending(SSL *ssl) { + int result; + Debug1("SSL_pending(%p)", ssl); + result = SSL_pending(ssl); + Debug1("SSL_pending() -> %d", result); + return result; +} + +int sycSSL_write(SSL *ssl, const void *buf, int num) { + int result; + Debug3("SSL_write(%p, %p, %d)", ssl, buf, num); + result = SSL_write(ssl, buf, num); + Debug1("SSL_write() -> %d", result); + return result; +} + +X509 *sycSSL_get_peer_certificate(SSL *ssl) { + X509 *result; + Debug1("SSL_get_peer_certificate(%p)", ssl); + result = SSL_get_peer_certificate(ssl); + if (result) { + Debug1("SSL_get_peer_certificate() -> %p", result); + } else { + Debug("SSL_get_peer_certificate() -> NULL"); + } + return result; +} + +int sycSSL_shutdown(SSL *ssl) { + int result; + Debug1("SSL_shutdown(%p)", ssl); + result = SSL_shutdown(ssl); + Debug1("SSL_shutdown() -> %d", result); + return result; +} + +void sycSSL_CTX_free(SSL_CTX *ctx) { + Debug1("SSL_CTX_free(%p)", ctx); + SSL_CTX_free(ctx); + Debug("SSL_CTX_free() -> void"); + return; +} + +void sycSSL_free(SSL *ssl) { + Debug1("SSL_free(%p)", ssl); + SSL_free(ssl); + Debug("SSL_free() -> void"); + return; +} + +int sycRAND_egd(const char *path) { + int result; + Debug1("RAND_egd(\"%s\")", path); + result = RAND_egd(path); + Debug1("RAND_egd() -> %d", result); + return result; +} + +DH *sycPEM_read_bio_DHparams(BIO *bp, DH **x, pem_password_cb *cb, void *u) { + DH *result; + Debug4("PEM_read_bio_DHparams(%p, %p, %p, %p)", + bp, x, cb, u); + result = PEM_read_bio_DHparams(bp, x, cb, u); + if (result) { + /*Debug2("PEM_read_bio_DHparams(, {%p},,) -> %p", *x, result);*/ + Debug1("PEM_read_bio_DHparams() -> %p", result); + } else { + Debug("PEM_read_bio_DHparams() -> NULL"); + } + return result; +} + +BIO *sycBIO_new_file(const char *filename, const char *mode) { + BIO *result; + Debug2("BIO_new_file(\"%s\", \"%s\")", filename, mode); + result = BIO_new_file(filename, mode); + if (result) { + Debug1("BIO_new_file() -> %p", result); + } else { + Debug("BIO_new_file() -> NULL"); + } + return result; +} + +#if WITH_FIPS +int sycFIPS_mode_set(int onoff) { + int result; + Debug1("FIPS_mode_set(%d)", onoff); + result = FIPS_mode_set(onoff); + Debug1("FIPS_mode_set() -> %d", result); + return result; +} +#endif /* WITH_FIPS */ + +#endif /* WITH_SYCLS && WITH_OPENSSL */ diff --git a/sslcls.h b/sslcls.h new file mode 100644 index 0000000..e3de001 --- /dev/null +++ b/sslcls.h @@ -0,0 +1,102 @@ +/* $Id: sslcls.h,v 1.9 2007/02/26 21:30:58 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __sslcls_h_included +#define __sslcls_h_included 1 + +#if WITH_SYCLS +#if WITH_OPENSSL + +void sycSSL_load_error_strings(void); +int sycSSL_library_init(void); +SSL_METHOD *sycSSLv2_client_method(void); +SSL_METHOD *sycSSLv2_server_method(void); +SSL_METHOD *sycSSLv3_client_method(void); +SSL_METHOD *sycSSLv3_server_method(void); +SSL_METHOD *sycSSLv23_client_method(void); +SSL_METHOD *sycSSLv23_server_method(void); +SSL_METHOD *sycTLSv1_client_method(void); +SSL_METHOD *sycTLSv1_server_method(void); +SSL_CTX *sycSSL_CTX_new(SSL_METHOD *method); +SSL *sycSSL_new(SSL_CTX *ctx); +int sycSSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, + const char *CApath); +int sycSSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type); +int sycSSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file); +int sycSSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type); +void sycSSL_CTX_set_verify(SSL_CTX *ctx, int mode, + int (*verify_callback)(int, X509_STORE_CTX *)); +int sycSSL_CTX_set_tmp_dh(SSL_CTX *ctx, DH *dh); +int sycSSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str); +int sycSSL_set_cipher_list(SSL *ssl, const char *str); +long sycSSL_get_verify_result(SSL *ssl); +int sycSSL_set_fd(SSL *ssl, int fd); +int sycSSL_connect(SSL *ssl); +int sycSSL_accept(SSL *ssl); +int sycSSL_read(SSL *ssl, void *buf, int num); +int sycSSL_pending(SSL *ssl); +int sycSSL_write(SSL *ssl, const void *buf, int num); +X509 *sycSSL_get_peer_certificate(SSL *ssl); +int sycSSL_shutdown(SSL *ssl); +void sycSSL_CTX_free(SSL_CTX *ctx); +void sycSSL_free(SSL *ssl); +int sycRAND_egd(const char *path); + +DH *sycPEM_read_bio_DHparams(BIO *bp, DH **x, pem_password_cb *cb, void *u); + +BIO *sycBIO_new_file(const char *filename, const char *mode); + +int sycFIPS_mode_set(int onoff); + +#endif /* WITH_OPENSSL */ + +#else /* !WITH_SYCLS */ + +#if WITH_OPENSSL + +#define sycSSL_load_error_strings() SSL_load_error_strings() +#define sycSSL_library_init() SSL_library_init() +#define sycSSLv2_client_method() SSLv2_client_method() +#define sycSSLv2_server_method() SSLv2_server_method() +#define sycSSLv3_client_method() SSLv3_client_method() +#define sycSSLv3_server_method() SSLv3_server_method() +#define sycSSLv23_client_method() SSLv23_client_method() +#define sycSSLv23_server_method() SSLv23_server_method() +#define sycTLSv1_client_method() TLSv1_client_method() +#define sycTLSv1_server_method() TLSv1_server_method() +#define sycSSL_CTX_new(m) SSL_CTX_new(m) +#define sycSSL_new(c) SSL_new(c) +#define sycSSL_CTX_load_verify_locations(c,f,p) SSL_CTX_load_verify_locations(c,f,p) +#define sycSSL_CTX_use_certificate_file(c,f,t) SSL_CTX_use_certificate_file(c,f,t) +#define sycSSL_CTX_use_certificate_chain_file(c,f) SSL_CTX_use_certificate_chain_file(c,f) +#define sycSSL_CTX_use_PrivateKey_file(c,f,t) SSL_CTX_use_PrivateKey_file(c,f,t) +#define sycSSL_CTX_set_verify(c,m,v) SSL_CTX_set_verify(c,m,v) +#define sycSSL_CTX_set_tmp_dh(c,d) SSL_CTX_set_tmp_dh(c,d) +#define sycSSL_CTX_set_cipher_list(c,s) SSL_CTX_set_cipher_list(c,s) +#define sycSSL_set_cipher_list(s,t) SSL_set_cipher_list(s,t) +#define sycSSL_get_verify_result(s) SSL_get_verify_result(s) +#define sycSSL_set_fd(s,f) SSL_set_fd(s,f) +#define sycSSL_connect(s) SSL_connect(s) +#define sycSSL_accept(s) SSL_accept(s) +#define sycSSL_read(s,b,n) SSL_read(s,b,n) +#define sycSSL_pending(s) SSL_pending(s) +#define sycSSL_write(s,b,n) SSL_write(s,b,n) +#define sycSSL_get_peer_certificate(s) SSL_get_peer_certificate(s) +#define sycSSL_shutdown(s) SSL_shutdown(s) +#define sycSSL_CTX_free(c) SSL_CTX_free(c) +#define sycSSL_free(s) SSL_free(s) +#define sycRAND_egd(p) RAND_egd(p) + +#define sycPEM_read_bio_DHparams(b,x,p,u) PEM_read_bio_DHparams(b,x,p,u) + +#define sycBIO_new_file(f,m) BIO_new_file(f,m) + +#endif /* WITH_OPENSSL */ + +#define sycFIPS_mode_set(o) FIPS_mode_set(o) + +#endif /* !WITH_SYCLS */ + +#endif /* !defined(__sslcls_h_included) */ + diff --git a/sycls.c b/sycls.c new file mode 100644 index 0000000..d30d9b3 --- /dev/null +++ b/sycls.c @@ -0,0 +1,1503 @@ +/* $Id: sycls.c,v 1.75 2007/03/06 21:04:12 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* explicit system call and C library trace function, for those who miss strace + */ + +#include "config.h" +#include "xioconfig.h" /* what features are enabled */ + +#if WITH_SYCLS + +#include "sysincludes.h" + +#include "mytypes.h" +#include "compat.h" +#include "errno.h" + +#include "error.h" +#include "filan.h" +#include "sysutils.h" +#include "sycls.h" + + +mode_t Umask(mode_t mask) { + mode_t result; + int _errno; + Debug1("umask("F_mode")", mask); + result = umask(mask); + _errno = errno; + Debug1("umask() -> "F_mode, result); + errno = _errno; + return result; +} + +int Open(const char *pathname, int flags, mode_t mode) { + int result, _errno; + Debug3("open(\"%s\", 0%o, 0%03o)", pathname, flags, mode); + result = open(pathname, flags, mode); + _errno = errno; + Info4("open(\"%s\", 0%o, 0%03o) -> %d", pathname, flags, mode, result); + errno = _errno; + return result; +} + +int Creat(const char *pathname, mode_t mode) { + int result, _errno; + Debug2("creat(\"%s\", 0%03o)", pathname, mode); + result = creat(pathname, mode); + _errno = errno; + Info3("creat(\"%s\", 0%03o) -> %d", pathname, mode, result); + errno = _errno; + return result; +} + +off_t Lseek(int fildes, off_t offset, int whence) { + int _errno; + off_t result; + Debug3("lseek(%d, "F_off", %d)", fildes, offset, whence); + result = lseek(fildes, offset, whence); + _errno = errno; + Debug1("lseek() -> "F_off, result); + errno = _errno; + return result; +} + +#if HAVE_LSEEK64 +off64_t Lseek64(int fildes, off64_t offset, int whence) { + int _errno; + off64_t result; + Debug3("lseek64(%d, "F_off64", %d)", fildes, offset, whence); + result = lseek64(fildes, offset, whence); + _errno = errno; + Debug1("lseek64() -> "F_off64, result); + errno = _errno; + return result; +} +#endif /* HAVE_LSEEK64 */ + +pid_t Getpid(void) { + pid_t result; + int _errno; + Debug("getpid()"); + result = getpid(); + _errno = errno; + Debug1("getpid() -> "F_pid, result); + errno = _errno; + return result; +} + +pid_t Getppid(void) { + pid_t result; + int _errno; + Debug("getppid()"); + result = getppid(); + _errno = errno; + Debug1("getppid() -> "F_pid, result); + errno = _errno; + return result; +} + +pid_t Getpgrp(void) { + pid_t result; + int _errno; + Debug("getpgrp()"); + result = getpgrp(); + _errno = errno; + Debug1("getpgrp() -> "F_pid, result); + errno = _errno; + return result; +} + +#if 0 /* does not compile for FreeBSD */ +/* setpgrp() is not BSD compatible, needs setpgid(..., ...) instead */ +int Setpgrp(void) { + int result, _errno; + Debug("setpgrp()"); + result = setpgrp(); + _errno = errno; + Debug1("setpgrp() -> %d", result); + errno = _errno; + return result; +} +#endif + +#if HAVE_GETPGID +int Getpgid(pid_t pid) { + pid_t result; + int _errno; + Debug1("getpgid("F_pid")", pid); + result = getpgid(pid); + _errno = errno; + Debug1("getpgid() -> "F_pid, result); + errno = _errno; + return result; +} +#endif + +int Setpgid(pid_t pid, pid_t pgid) { + int result, _errno; + Debug2("setpgid("F_pid", "F_pid")", pid, pgid); + result = setpgid(pid, pgid); + _errno = errno; + Debug1("setpgid() -> %d", result); + errno = _errno; + return result; +} + +pid_t Tcgetpgrp(int fd) { + int result, _errno; + Debug1("tcgetpgrp(%d)", fd); + result = tcgetpgrp(fd); + _errno = errno; + Debug1("tcgetpgrp() -> %d", result); + errno = _errno; + return result; +} + +int Tcsetpgrp(int fd, pid_t pgrpid) { + int result, _errno; + Debug2("tcsetpgrp(%d, "F_pid")", fd, pgrpid); + result = tcsetpgrp(fd, pgrpid); + _errno = errno; + Debug1("tcsetpgrp() -> %d", result); + errno = _errno; + return result; +} + +#if HAVE_GETSID +pid_t Getsid(pid_t pid) { + int result, _errno; + Debug1("getsid("F_pid")", pid); + result = getsid(pid); + _errno = errno; + Debug1("getsid() -> "F_pid, result); + errno = _errno; + return result; +} +#endif + +pid_t Setsid(void) { + int result, _errno; + Debug("setsid()"); + result = setsid(); + _errno = errno; + Debug1("setsid() -> "F_pid, result); + errno = _errno; + return result; +} + +uid_t Getuid(void) { + uid_t result; + int _errno; + Debug("getuid()"); + result = getuid(); + _errno = errno; + Debug1("getuid() -> "F_uid, result); + errno = _errno; + return result; +} + +uid_t Geteuid(void) { + uid_t result; + int _errno; + Debug("geteuid()"); + result = geteuid(); + _errno = errno; + Debug1("geteuid() -> "F_uid, result); + errno = _errno; + return result; +} + +int Setuid(uid_t uid) { + int result, _errno; + Debug1("setuid("F_uid")", uid); + result = setuid(uid); + _errno = errno; + Debug1("setuid() -> %d", result); + errno = _errno; + return result; +} + +gid_t Getgid(void) { + gid_t result; + int _errno; + Debug("getgid()"); + result = getgid(); + _errno = errno; + Debug1("getgid() -> "F_gid, result); + errno = _errno; + return result; +} + +gid_t Getegid(void) { + gid_t result; + int _errno; + Debug("getegid()"); + result = getegid(); + _errno = errno; + Debug1("getegid() -> "F_gid, result); + errno = _errno; + return result; +} + +int Setgid(gid_t gid) { + int result, _errno; + Debug1("setgid("F_gid")", gid); + result = setgid(gid); + _errno = errno; + Debug1("setgid() -> %d", result); + errno = _errno; + return result; +} + +int Initgroups(const char *user, gid_t group) { + int result, _errno; + Debug2("initgroups(\"%s\", "F_gid")", user, group); + result = initgroups(user, group); + _errno = errno; + Debug1("initgroups() -> %d", result); + errno = _errno; + return result; +} + +int Getgroups(int size, gid_t list[]) { + int result, _errno; + Debug2("getgroups(%d, "F_gid",...)", size, list[0]); + result = getgroups(size, list); + _errno = errno; + Debug1("getgroups() -> %d", result); + errno = _errno; + return result; +} + +#if HAVE_SETGROUPS +int Setgroups(size_t size, const gid_t *list) { + int result, _errno; + Debug2("setgroups("F_Zu", "F_gid",...)", size, list[0]); + result = setgroups(size, list); + _errno = errno; + Debug1("setgroups() -> %d", result); + errno = _errno; + return result; +} +#endif + +int Chdir(const char *path) { + int result, _errno; + Debug1("chdir(\"%s\")", path); + result = chdir(path); + _errno = errno; + Debug1("chdir() -> %d", result); + errno = _errno; + return result; +} + +int Chroot(const char *path) { + int result, _errno; + Debug1("chroot(\"%s\")", path); + result = chroot(path); + _errno = errno; + Debug1("chroot() -> %d", result); + errno = _errno; + return result; +} + +int Gettimeofday(struct timeval *tv, struct timezone *tz) { + int result, _errno; +#if WITH_MSGLEVEL <= E_DEBUG + if (tz) { + Debug3("gettimeofday(%p, {%d,%d})", + tv, tz->tz_minuteswest, tz->tz_dsttime); + } else { + Debug1("gettimeofday(%p, NULL)", tv); + } +#endif /* WITH_MSGLEVEL <= E_DEBUG */ + result = gettimeofday(tv, tz); + _errno = errno; +#if WITH_MSGLEVEL <= E_DEBUG + if (tz) { + Debug5("gettimeofday({%ld,%ld}, {%d,%d}) -> %d", + tv->tv_sec, tv->tv_usec, tz->tz_minuteswest, tz->tz_dsttime, + result); + } else { + Debug3("gettimeofday({%ld,%ld},) -> %d", + tv->tv_sec, tv->tv_usec, result); + } +#endif /* WITH_MSGLEVEL <= E_DEBUG */ + errno = _errno; + return result; +} + +int Mknod(const char *pathname, mode_t mode, dev_t dev) { + int result, _errno; + Debug3("mknod(\"%s\", 0%o, %d)", pathname, mode, dev); + result = mknod(pathname, mode, dev); + _errno = errno; + Debug1("mknod() -> %d", result); + errno = _errno; + return result; +} + +int Mkfifo(const char *pathname, mode_t mode) { + int result, _errno; + Debug2("mkfifo(\"%s\", 0%o)", pathname, mode); + result = mkfifo(pathname, mode); + _errno = errno; + Debug1("mkfifo() -> %d", result); + errno = _errno; + return result; +} + +static void prtstat(const char *func, struct stat *buf, int result) { + char txt[256], *t = txt; + + t += sprintf(t, "%s(, {"F_st_dev","F_st_ino","F_mode","F_st_nlink","F_uid","F_gid, + func, buf->st_dev, buf->st_ino, + buf->st_mode, buf->st_nlink, buf->st_uid, buf->st_gid); +#if HAVE_ST_RDEV + t += sprintf(t, ","F_st_dev, buf->st_rdev); +#endif + t += sprintf(t, ","F_st_size, buf->st_size); +#if HAVE_ST_BLKSIZE + t += sprintf(t, ","F_st_blksize, buf->st_blksize); +#endif +#if HAVE_ST_BLOCKS + t += sprintf(t, ","F_st_blocks, buf->st_blocks); +#endif + sprintf(t, ",...}) -> %d", result); + Debug(txt); +} + +#if defined(HAVE_STAT64) || defined(HAVE_FSTAT64) || defined(HAVE_LSTAT64) +static void prtstat64(const char *func, struct stat64 *buf, int result) { + char txt[256], *t = txt; + + if (result < 0) { + sprintf(t, "%s(, {}) -> %d", func, result); + } else { + t += sprintf(t, "%s(, {"F_st_dev","F_st64_ino","F_mode","F_st_nlink","F_uid","F_gid, + func, buf->st_dev, buf->st_ino, + buf->st_mode, buf->st_nlink, buf->st_uid, buf->st_gid); +#if HAVE_ST_RDEV + t += sprintf(t, ","F_st_dev, buf->st_rdev); +#endif + t += sprintf(t, ","F_st64_size, buf->st_size); +#if HAVE_ST_BLKSIZE + t += sprintf(t, ","F_st_blksize, buf->st_blksize); +#endif +#if HAVE_ST_BLOCKS + t += sprintf(t, ","F_st64_blocks, buf->st_blocks); +#endif + sprintf(t, ",...}) -> %d", result); + } + Debug(txt); +} +#endif /* defined(HAVE_STAT64) || defined(HAVE_FSTAT64) || defined(HAVE_LSTAT64) */ + +int Stat(const char *file_name, struct stat *buf) { + int result, _errno; + Debug2("stat(%s, %p)", file_name, buf); + result = stat(file_name, buf); + _errno = errno; + prtstat("stat", buf, result); + errno = _errno; + return result; +} + +#if HAVE_STAT64 +int Stat64(const char *file_name, struct stat64 *buf) { + int result, _errno; + Debug2("stat64(%s, %p)", file_name, buf); + result = stat64(file_name, buf); + _errno = errno; + prtstat64("stat64", buf, result); + errno = _errno; + return result; +} +#endif /* HAVE_STAT64 */ + +int Fstat(int filedes, struct stat *buf) { + int result, _errno; + Debug2("fstat(%d, %p)", filedes, buf); + result = fstat(filedes, buf); + _errno = errno; + prtstat("fstat", buf, result); + errno = _errno; + return result; +} + +#if HAVE_FSTAT64 +int Fstat64(int filedes, struct stat64 *buf) { + int result, _errno; + Debug2("fstat64(%d, %p)", filedes, buf); + result = fstat64(filedes, buf); + _errno = errno; + prtstat64("fstat64", buf, result); + errno = _errno; + return result; +} +#endif /* HAVE_FSTAT64 */ + +int Lstat(const char *file_name, struct stat *buf) { + int result, _errno; + Debug2("lstat(%s, %p)", file_name, buf); + result = lstat(file_name, buf); + _errno = errno; + prtstat("lstat", buf, result); + errno = _errno; + return result; +} + +#if HAVE_LSTAT64 +int Lstat64(const char *file_name, struct stat64 *buf) { + int result, _errno; + Debug2("lstat64(%s, %p)", file_name, buf); + result = lstat64(file_name, buf); + _errno = errno; + prtstat64("lstat64", buf, result); + errno = _errno; + return result; +} +#endif /* HAVE_LSTAT64 */ + +int Dup(int oldfd) { + int newfd, _errno; + Debug1("dup(%d)", oldfd); + newfd = dup(oldfd); + _errno = errno; + Info2("dup(%d) -> %d", oldfd, newfd); + errno = _errno; + return newfd; +} + +int Dup2(int oldfd, int newfd) { + int result, _errno; + Debug2("dup2(%d, %d)", oldfd, newfd); + result = dup2(oldfd, newfd); + _errno = errno; + Info3("dup2(%d, %d) -> %d", oldfd, newfd, result); + errno = _errno; + return result; +} + +int Pipe(int filedes[2]) { + int result, _errno; + Debug1("pipe(%p)", filedes); + result = pipe(filedes); + _errno = errno; + Info3("pipe({%d,%d}) -> %d", filedes[0], filedes[1], result); + errno = _errno; + return result; +} + +ssize_t Read(int fd, void *buf, size_t count) { + ssize_t result; + int _errno; + Debug3("read(%d, %p, "F_Zu")", fd, buf, count); + result = read(fd, buf, count); + _errno = errno; + Debug1("read -> "F_Zd, result); + errno = _errno; + return result; +} + +ssize_t Write(int fd, const void *buf, size_t count) { + ssize_t result; + int _errno; + Debug3("write(%d, %p, "F_Zu")", fd, buf, count); + result = write(fd, buf, count); + _errno = errno; + Debug1("write -> "F_Zd, result); + errno = _errno; + return result; +} + +int Fcntl(int fd, int cmd) { + int result, _errno; + Debug2("fcntl(%d, %d)", fd, cmd); + result = fcntl(fd, cmd); + _errno = errno; + Debug1("fcntl() -> %d", result); + errno = _errno; + return result; +} + +int Fcntl_l(int fd, int cmd, long arg) { + int result, _errno; + Debug3("fcntl(%d, %d, %ld)", fd, cmd, arg); + result = fcntl(fd, cmd, arg); + _errno = errno; + Debug1("fcntl() -> %d", result); + errno = _errno; + return result; +} + +int Fcntl_lock(int fd, int cmd, struct flock *l) { + int result, _errno; + Debug7("fcntl(%d, %d, {type=%hd,whence=%hd,start="F_off",len="F_off",pid="F_pid"})", + fd, cmd, l->l_type, l->l_whence, l->l_start, l->l_len, l->l_pid); + result = fcntl(fd, cmd, l); + _errno = errno; + Debug1("fcntl() -> %d", result); + errno = _errno; + return result; +} + +int Ftruncate(int fd, off_t length) { + int retval, _errno; + Debug2("ftruncate(%d, "F_off")", fd, length); + retval = ftruncate(fd, length); + _errno = errno; + Debug1("ftruncate() -> %d", retval); + errno = _errno; + return retval; +} + +#if HAVE_FTRUNCATE64 +int Ftruncate64(int fd, off64_t length) { + int retval, _errno; + Debug2("ftruncate64(%d, "F_off64")", fd, length); + retval = ftruncate64(fd, length); + _errno = errno; + Debug1("ftruncate64() -> %d", retval); + errno = _errno; + return retval; +} +#endif /* HAVE_FTRUNCATE64 */ + +#if HAVE_FLOCK +int Flock(int fd, int operation) { + int retval, _errno; + Debug2("flock(%d, %d)", fd, operation); + retval = flock(fd, operation); + _errno = errno; + Debug1("flock() -> %d", retval); + errno = _errno; + return retval; +} +#endif /* HAVE_FLOCK */ + +int Ioctl(int d, int request, void *argp) { + int retval, _errno; + if (argp > (void *)0x10000) { /* fuzzy...*/ + Debug4("ioctl(%d, 0x%x, %p{%lu})", d, request, argp, *(unsigned long *)argp); + } else { + Debug3("ioctl(%d, 0x%x, 0x%p)", d, request, argp); + } + retval = ioctl(d, request, argp); + _errno = errno; + Debug1("ioctl() -> %d", retval); + errno = _errno; + return retval; +} + +int Close(int fd) { + int retval, _errno; + Info1("close(%d)", fd); + retval = close(fd); + _errno = errno; + Debug1("close() -> %d", retval); + errno = _errno; + return retval; +} + +int Fchown(int fd, uid_t owner, gid_t group) { + int retval, _errno; + Debug3("fchown(%d, "F_uid", "F_gid")", fd, owner, group); + retval = fchown(fd, owner, group); + _errno = errno; + Debug1("fchown() -> %d", retval); + errno = _errno; + return retval; +} + +int Fchmod(int fd, mode_t mode) { + int retval, _errno; + Debug2("fchmod(%d, 0%o)", fd, mode); + retval = fchmod(fd, mode); + _errno = errno; + Debug1("fchmod() -> %d", retval); + errno = _errno; + return retval; +} + +int Unlink(const char *pathname) { + int retval, _errno; + Debug1("unlink(\"%s\")", pathname); + retval = unlink(pathname); + _errno = errno; + Debug1("unlink() -> %d", retval); + errno = _errno; + return retval; +} + +int Symlink(const char *oldpath, const char *newpath) { + int retval, _errno; + Debug2("symlink(\"%s\", \"%s\")", oldpath, newpath); + retval = symlink(oldpath, newpath); + _errno = errno; + Debug1("symlink() -> %d", retval); + errno = _errno; + return retval; +} + +int Readlink(const char *path, char *buf, size_t bufsiz) { + int retval, _errno; + Debug3("readlink(\"%s\", %p, "F_Zu")", path, buf, bufsiz); + retval = readlink(path, buf, bufsiz); + _errno = errno; + Debug1("readlink() -> %d", retval); + errno = _errno; + return retval; +} + +int Chown(const char *path, uid_t owner, gid_t group) { + int retval, _errno; + Debug3("chown(\"%s\", "F_uid", "F_gid")", path, owner, group); + retval = chown(path, owner, group); + _errno = errno; + Debug1("chown() -> %d", retval); + errno = _errno; + return retval; +} + +int Chmod(const char *path, mode_t mode) { + int retval, _errno; + Debug2("chmod(\"%s\", 0%o)", path, mode); + retval = chmod(path, mode); + _errno = errno; + Debug1("chmod() -> %d", retval); + errno = _errno; + return retval; +} + +#if HAVE_POLL +/* we only show the first struct pollfd; hope this is enough for most cases. */ +int Poll(struct pollfd *ufds, unsigned int nfds, int timeout) { + int result; + Debug4("poll({%d, 0x%02hx, }, %u, %d)", ufds[0].fd, ufds[0].events, nfds, timeout); + result = poll(ufds, nfds, timeout); + Debug2("poll(, {,, 0x%02hx}) -> %d", ufds[0].revents, result); + return result; +} +#endif /* HAVE_POLL */ + +/* we only show the first word of the fd_set's; hope this is enough for most + cases. */ +int Select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + struct timeval *timeout) { + int result, _errno; +#if HAVE_FDS_BITS + Debug7("select(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu."F_tv_usec")", + n, readfds->fds_bits[0], writefds->fds_bits[0], + exceptfds->fds_bits[0], + timeout?"&":"NULL/", timeout?timeout->tv_sec:0, + timeout?timeout->tv_usec:0); +#else + Debug7("select(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu.%06u)", + n, readfds->__fds_bits[0], writefds->__fds_bits[0], + exceptfds->__fds_bits[0], + timeout?"&":"NULL/", timeout?timeout->tv_sec:0, + timeout?timeout->tv_usec:0); +#endif + result = select(n, readfds, writefds, exceptfds, timeout); + _errno = errno; +#if HAVE_FDS_BITS + Debug7("select -> (, 0x%lx, 0x%lx, 0x%lx, %s%lu."F_tv_usec"), %d", + readfds->fds_bits[0], writefds->fds_bits[0], exceptfds->fds_bits[0], + timeout?"&":"NULL/", timeout?timeout->tv_sec:0, + timeout?timeout->tv_usec:0, result); +#else + Debug7("select -> (, 0x%lx, 0x%lx, 0x%lx, %s%lu.%06u), %d", + readfds->__fds_bits[0], writefds->__fds_bits[0], + exceptfds->__fds_bits[0], + timeout?"&":"NULL/", timeout?timeout->tv_sec:0, + timeout?timeout->tv_usec:0, result); +#endif + errno = _errno; + return result; +} + +pid_t Fork(void) { + pid_t pid; + int _errno; + Debug("fork()"); + pid = fork(); + _errno = errno; + Debug1("fork() -> %d", pid); /* attention: called twice! */ + errno = _errno; + return pid; +} + +pid_t Waitpid(pid_t pid, int *status, int options) { + int _errno; + pid_t retval; + Debug3("waitpid("F_pid", %p, %d)", pid, status, options); + retval = waitpid(pid, status, options); + _errno = errno; + Debug2("waitpid(, {%d}, ) -> "F_pid, *status, retval); + errno = _errno; + return retval; +} + +sighandler_t Signal(int signum, sighandler_t handler) { + int _errno; + sighandler_t retval; + Debug2("signal(%d, %p)", signum, handler); + retval = signal(signum, handler); + _errno = errno; + Debug1("signal() -> %p", retval); + errno = _errno; + return retval; +} + +#if HAVE_SIGACTION +int Sigaction(int signum, const struct sigaction *act, + struct sigaction *oldact) { + int retval; + Debug3("sigaction(%d, %p, %p)", signum, act, oldact); + retval = sigaction(signum, act, oldact); + Debug1("sigaction() -> %d", retval); + return retval; +} +#endif /* HAVE_SIGACTION */ + +int Sigprocmask(int how, const sigset_t *set, sigset_t *oset) { + int retval; + Debug3("sigprocmask(%d, %p, %p)", how, set, oset); + retval = sigprocmask(how, set, oset); + Debug1("sigprocmask() -> %d", retval); + return retval; +} + +unsigned int Alarm(unsigned int seconds) { + unsigned int retval; + Debug1("alarm(%u)", seconds); + retval = alarm(seconds); + Debug1("alarm() -> %u", retval); + return retval; +} + +int Kill(pid_t pid, int sig) { + int retval, _errno; + Debug2("kill("F_pid", %d)", pid, sig); + retval = kill(pid, sig); + _errno = errno; + Debug1("kill() -> %d", retval); + errno = _errno; + return retval; +} + +int Link(const char *oldpath, const char *newpath) { + int retval, _errno; + Debug2("link(\"%s\", \"%s\")", oldpath, newpath); + retval = link(oldpath, newpath); + _errno = errno; + Debug1("link() -> %d", retval); + errno = _errno; + return retval; +} + +int Execvp(const char *file, char *const argv[]) { + int result, _errno; + if (argv[1] == NULL) + Debug2("execvp(\"%s\", \"%s\")", file, argv[0]); + else if (argv[2] == NULL) + Debug3("execvp(\"%s\", \"%s\" \"%s\")", file, argv[0], argv[1]); + else if (argv[3] == NULL) + Debug4("execvp(\"%s\", \"%s\" \"%s\" \"%s\")", file, argv[0], argv[1], argv[2]); + else if (argv[4] == NULL) + Debug5("execvp(\"%s\", \"%s\" \"%s\" \"%s\" \"%s\")", file, argv[0], argv[1], argv[2], argv[3]); + else if (argv[5] == NULL) + Debug6("execvp(\"%s\", \"%s\" \"%s\" \"%s\" \"%s\" \"%s\")", file, argv[0], argv[1], argv[2], argv[3], argv[4]); + else + Debug6("execvp(\"%s\", \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" ...)", file, argv[0], argv[1], argv[2], argv[3], argv[4]); + + result = execvp(file, argv); + _errno = errno; + Debug1("execvp() -> %d", result); + errno = _errno; + return result; +} + +int System(const char *string) { + int result, _errno; + Debug1("system(\"%s\")", string); + result = system(string); + _errno = errno; + Debug1("system() -> %d", result); + errno = _errno; + return result; +} + +int Socketpair(int d, int type, int protocol, int sv[2]) { + int result, _errno; + Debug4("socketpair(%d, %d, %d, %p)", d, type, protocol, sv); + result = socketpair(d, type, protocol, sv); + _errno = errno; + Info6("socketpair(%d, %d, %d, {%d,%d}) -> %d", d, type, protocol, sv[0], sv[1], result); + errno = _errno; + return result; +} + +#if _WITH_SOCKET +int Socket(int domain, int type, int protocol) { + int result, _errno; + Debug3("socket(%d, %d, %d)", domain, type, protocol); + result = socket(domain, type, protocol); + _errno = errno; + Info4("socket(%d, %d, %d) -> %d", domain, type, protocol, result); + errno = _errno; + return result; +} +#endif /* _WITH_SOCKET */ + +#if _WITH_SOCKET +int Bind(int sockfd, struct sockaddr *my_addr, int addrlen) { + int result, _errno; + char infobuff[256]; + + sockaddr_info(my_addr, addrlen, infobuff, sizeof(infobuff)); + Debug3("bind(%d, %s, "F_Zd")", sockfd, infobuff, addrlen); + result = bind(sockfd, my_addr, addrlen); + _errno = errno; + Debug1("bind() -> %d", result); + errno = _errno; + return result; +} +#endif /* _WITH_SOCKET */ + +#if _WITH_SOCKET +int Connect(int sockfd, const struct sockaddr *serv_addr, int addrlen) { + int result, _errno; + char infobuff[256]; + + /*sockaddr_info(serv_addr, infobuff, sizeof(infobuff)); + Debug3("connect(%d, %s, "F_Zd")", sockfd, infobuff, addrlen);*/ +#if 0 + Debug18("connect(%d,{0x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x}, "F_Zd")", + sockfd, + ((unsigned char *)serv_addr)[0], ((unsigned char *)serv_addr)[1], + ((unsigned char *)serv_addr)[2], ((unsigned char *)serv_addr)[3], + ((unsigned char *)serv_addr)[4], ((unsigned char *)serv_addr)[5], + ((unsigned char *)serv_addr)[6], ((unsigned char *)serv_addr)[7], + ((unsigned char *)serv_addr)[8], ((unsigned char *)serv_addr)[9], + ((unsigned char *)serv_addr)[10], ((unsigned char *)serv_addr)[11], + ((unsigned char *)serv_addr)[12], ((unsigned char *)serv_addr)[13], + ((unsigned char *)serv_addr)[14], ((unsigned char *)serv_addr)[15], + addrlen); +#else + Debug4("connect(%d, {%d,%s}, "F_Zd")", + sockfd, serv_addr->sa_family, + sockaddr_info(serv_addr, addrlen, infobuff, sizeof(infobuff)), + addrlen); +#endif + result = connect(sockfd, serv_addr, addrlen); + _errno = errno; + Debug1("connect() -> %d", result); + errno = _errno; + return result; +} +#endif /* _WITH_SOCKET */ + +#if _WITH_SOCKET +int Listen(int s, int backlog) { + int result, _errno; + Debug2("listen(%d, %d)", s, backlog); + result = listen(s, backlog); + _errno = errno; + Debug1("listen() -> %d", result); + errno = _errno; + return result; +} +#endif /* _WITH_SOCKET */ + +#if _WITH_SOCKET +/* don't forget to handle EINTR when using Accept() ! */ +int Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { + int result, _errno; + + Debug3("accept(%d, %p, %p)", s, addr, addrlen); + result = accept(s, addr, addrlen); + _errno = errno; + if (result >= 0) { + char infobuff[256]; + sockaddr_info(addr, *addrlen, infobuff, sizeof(infobuff)); + Info5("accept(%d, {%d, %s}, "F_Zd") -> %d", s, + addr->sa_family, + sockaddr_info(addr, *addrlen, infobuff, sizeof(infobuff)), + *addrlen, result); + } else { + Debug1("accept(,,) -> %d", result); + } + errno = _errno; + return result; +} +#endif /* _WITH_SOCKET */ + +#if _WITH_SOCKET +int Getsockname(int s, struct sockaddr *name, socklen_t *namelen) { + int result, _errno; + char infobuff[256]; + + Debug4("getsockname(%d, %p, %p{"F_socklen"})", s, name, namelen, *namelen); + result = getsockname(s, name, namelen); + _errno = errno; + /*Debug2("getsockname(,, {"F_socklen"}) -> %d", + *namelen, result);*/ + Debug3("getsockname(, {%s}, {"F_socklen"}) -> %d", + sockaddr_info(name, *namelen, infobuff, sizeof(infobuff)), + *namelen, result); + errno = _errno; + return result; +} +#endif /* _WITH_SOCKET */ + +#if _WITH_SOCKET +int Getpeername(int s, struct sockaddr *name, socklen_t *namelen) { + int result, _errno; + char infobuff[256]; + + Debug4("getpeername(%d, %p, %p{"F_socklen"})", s, name, namelen, *namelen); + result = getpeername(s, name, namelen); + _errno = errno; + sockaddr_info(name, *namelen, infobuff, sizeof(infobuff)); + Debug3("getpeername(, {%s}, {"F_socklen"}) -> %d", + infobuff, *namelen, result); + errno = _errno; + return result; +} +#endif /* _WITH_SOCKET */ + +#if _WITH_SOCKET +int Getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) { + int result, _errno; + Debug5("getsockopt(%d, %d, %d, %p, {"F_Zd"})", + s, level, optname, optval, *optlen); + result = getsockopt(s, level, optname, optval, optlen); + _errno = errno; + Debug3("getsockopt() -> (,,, 0x%08x, %d), %d", + *(int *)optval, *optlen, result); + errno = _errno; + return result; +} +#endif /* _WITH_SOCKET */ + +#if _WITH_SOCKET +int Setsockopt(int s, int level, int optname, const void *optval, int optlen) { + int result, _errno; + if (optlen <= sizeof(int)) { + Debug5("setsockopt(%d, %d, %d, {0x%x}, %d)", + s, level, optname, *(unsigned int *)optval, optlen); + } else { + Debug6("setsockopt(%d, %d, %d, {0x%08x,%08x}, %d)", + s, level, optname, + ((unsigned int *)optval)[0], ((unsigned int *)optval)[1], + optlen); + } + result = setsockopt(s, level, optname, optval, optlen); + _errno = errno; + Debug1("setsockopt() -> %d", result); + errno = _errno; + return result; +} +#endif /* _WITH_SOCKET */ + +#if _WITH_SOCKET +int Recv(int s, void *buf, size_t len, int flags) { + int retval, _errno; + Debug4("recv(%d, %p, "F_Zu", %d)", s, buf, len, flags); + retval = recv(s, buf, len, flags); + _errno = errno; + Debug1("recv() -> %d", retval); + errno = _errno; + return retval; +} +#endif /* _WITH_SOCKET */ + +#if _WITH_SOCKET +int Recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, + socklen_t *fromlen) { + int retval, _errno; + char infobuff[256]; + Debug6("recvfrom(%d, %p, "F_Zu", %d, %p, "F_Zu")", + s, buf, len, flags, from, *fromlen); + retval = recvfrom(s, buf, len, flags, from, fromlen); + _errno = errno; + if (from) { + Debug4("recvfrom(,,,, {%d,%s}, "F_Zd") -> %d", + from->sa_family, + sockaddr_info(from, *fromlen, infobuff, sizeof(infobuff)), + *fromlen, retval); + } else { + Debug1("recvfrom(,,,, NULL, NULL) -> %d", retval); + } + errno = _errno; + return retval; +} +#endif /* _WITH_SOCKET */ + +#if _WITH_SOCKET +int Recvmsg(int s, struct msghdr *msgh, int flags) { + int retval, _errno; + char infobuff[256]; + Debug3("recvmsg(%d, %p, %d)", s, msgh, flags); + retval = recvmsg(s, msgh, flags); + _errno = errno; + Debug2("recvmsg(, {%s}, ) -> %d", + msgh->msg_name?sockaddr_info(msgh->msg_name, msgh->msg_namelen, infobuff, sizeof(infobuff)):"NULL", + retval); + errno = _errno; + return retval; +} +#endif /* _WITH_SOCKET */ + +#if _WITH_SOCKET +int Send(int s, const void *mesg, size_t len, int flags) { + int retval, _errno; + Debug5("send(%d, %p[%08x...], "F_Zu", %d)", + s, mesg, ntohl(*(unsigned long *)mesg), len, flags); + retval = send(s, mesg, len, flags); + _errno = errno; + Debug1("send() -> %d", retval); + errno = _errno; + return retval; +} +#endif /* _WITH_SOCKET */ + +#if _WITH_SOCKET +int Sendto(int s, const void *mesg, size_t len, int flags, + const struct sockaddr *to, socklen_t tolen) { + int retval, _errno; + char infobuff[256]; + + sockaddr_info(to, tolen, infobuff, sizeof(infobuff)); + Debug7("sendto(%d, %p[%08x...], "F_Zu", %d, {%s}, %d)", + s, mesg, htonl(*(unsigned long *)mesg), len, flags, infobuff, tolen); + retval = sendto(s, mesg, len, flags, to, tolen); + _errno = errno; + Debug1("sendto() -> %d", retval); + errno = _errno; + return retval; +} +#endif /* _WITH_SOCKET */ + +#if _WITH_SOCKET +int Shutdown(int fd, int how) { + int retval, _errno; + Info2("shutdown(%d, %d)", fd, how); + retval = shutdown(fd, how); + _errno = errno; + Debug1("shutdown() -> %d", retval); + errno = _errno; + return retval; +} +#endif /* _WITH_SOCKET */ + +unsigned int Sleep(unsigned int seconds) { + unsigned int retval; + Debug1("sleep(%u)", seconds); + retval = sleep(seconds); + Debug1("sleep() -> %u", retval); + return retval; +} + +void Usleep(unsigned long usec) { + Debug1("usleep(%lu)", usec); + usleep(usec); + Debug("usleep() ->"); + return; +} + +#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); + retval = nanosleep(req, rem); + _errno = errno; + if (rem) { + Debug3("nanosleep(,{"F_time",%ld}) -> %d", + rem->tv_sec, rem->tv_nsec, retval); + } else { + Debug1("nanosleep() -> %d", retval); + } + errno = _errno; + return retval; +} +#endif /* HAVE_NANOSLEEP */ + +int Pause(void) { + int retval, _errno; + Debug("pause()"); + retval = pause(); + _errno = errno; + Debug1("pause() -> %d", retval); + errno = _errno; + return retval; +} + +#if WITH_IP4 || WITH_IP6 +struct hostent *Gethostbyname(const char *name) { + struct hostent *hent; + Debug1("gethostbyname(\"%s\")", name); + hent = gethostbyname(name); + if (hent == NULL) { + Debug("gethostbyname() -> NULL"); + } else { + Debug4("gethostbyname() -> %d.%d.%d.%d", + ((unsigned char *)hent->h_addr_list[0])[0], + ((unsigned char *)hent->h_addr_list[0])[1], + ((unsigned char *)hent->h_addr_list[0])[2], + ((unsigned char *)hent->h_addr_list[0])[3]); + } + return hent; +} +#endif /* WITH_IP4 || WITH_IP6 */ + +#if (_WITH_IP4 || _WITH_IP6) && HAVE_GETADDRINFO +int Getaddrinfo(const char *node, const char *service, + const struct addrinfo *hints, struct addrinfo **res) { + int result; + Debug15("getaddrinfo(%s%s%s, %s%s%s, {%d,%d,%d,%d,"F_Zu",%p,%p,%p}, %p)", + node?"\"":"", node?node:"NULL", node?"\"":"", + service?"\"":"", service?service:"NULL", service?"\"":"", + hints->ai_flags, hints->ai_family, hints->ai_socktype, + hints->ai_protocol, hints->ai_addrlen, hints->ai_addr, + hints->ai_canonname, hints->ai_next, res); + result = getaddrinfo(node, service, hints, res); + if (result == 0) { + char sockbuff[256]; + sockaddr_info((*res)->ai_addr, hints->ai_addrlen, sockbuff, sizeof(sockbuff)); + Debug2("getaddrinfo(,,,{{%s, %s}) -> 0", + sockbuff, + (*res)->ai_canonname?(*res)->ai_canonname:""); + } else { + Debug2("getaddrinfo(,,,{%p}) -> %d", *res, result); + } + return result; +} +#endif /* (_WITH_IP4 || _WITH_IP6) && HAVE_GETADDRINFO */ + +#if (WITH_IP4 || WITH_IP6) && HAVE_GETIPNODEBYNAME +struct hostent *Getipnodebyname(const char *name, int af, int flags, + int *error_num) { + struct hostent *result; + Debug4("getipnodebyname(\"%s\", %d, %d, %p)", name, af, flags, error_num); + result = getipnodebyname(name, af, flags, error_num); + if (result == NULL) { + Debug1("getipnodebyname(,,, {%d}) -> NULL", *error_num); + } else { + Debug4("getipnodebyname() -> {\"%s\", %p, %d, %d, ???}", + result->h_name, result->h_aliases, result->h_addrtype, + result->h_length); + } + return result; +} +#endif /* (WITH_IP4 || WITH_IP6) && HAVE_GETIPNODEBYNAME */ + +void *Malloc(size_t size) { + void *result; + Debug1("malloc("F_Zd")", size); + result = malloc(size); + Debug1("malloc() -> %p", result); + if (result == NULL) { + Error1("malloc("F_Zd"): out of memory", size); + return NULL; + } + return result; +} + +void *Calloc(size_t nmemb, size_t size) { + void *result; + Debug2("calloc("F_Zd", "F_Zd")", nmemb, size); + result = calloc(nmemb, size); + Debug1("calloc() -> %p", result); + if (result == NULL) { + Error2("calloc("F_Zd", "F_Zd"): out of memory", nmemb, size); + return NULL; + } + return result; +} + +void *Realloc(void *ptr, size_t size) { + void *result; + Debug2("realloc(%p, "F_Zd")", ptr, size); + result = realloc(ptr, size); + Debug1("realloc() -> %p", result); + if (result == NULL) { + Error2("realloc(%p, "F_Zd"): out of memory", ptr, size); + return NULL; + } + return result; +} + +int Tcgetattr(int fd, struct termios *termios_p) { + int i, result, _errno; + char chars[5*NCCS], *cp = chars; + + Debug2("tcgetattr(%d, %p)", fd, termios_p); + result = tcgetattr(fd, termios_p); + _errno = errno; + + for (i = 0; i < NCCS-1; ++i) { + cp += sprintf(cp, "%02x,", termios_p->c_cc[i]); + } + sprintf(cp, "%02x", termios_p->c_cc[i]); + Debug6("tcgetattr(, {%08x,%08x,%08x,%08x,%s}) -> %d", + termios_p->c_iflag, termios_p->c_oflag, + termios_p->c_cflag, termios_p->c_lflag, + chars, result); + errno = _errno; + return result; +} + +int Tcsetattr(int fd, int optional_actions, struct termios *termios_p) { + int i, result, _errno; + char chars[5*NCCS], *cp = chars; + + for (i = 0; i < NCCS-1; ++i) { + cp += sprintf(cp, "%02x,", termios_p->c_cc[i]); + } + sprintf(cp, "%02x", termios_p->c_cc[i]); + Debug7("tcsetattr(%d, %d, {%08x,%08x,%08x,%08x,%s})", fd, optional_actions, + termios_p->c_iflag, termios_p->c_oflag, + termios_p->c_cflag, termios_p->c_lflag, chars); + result = tcsetattr(fd, optional_actions, termios_p); + _errno = errno; + Debug1("tcsetattr() -> %d", result); + errno = _errno; + return result; +} + +char *Ttyname(int fd) { + char *result; + int _errno; + Debug1("ttyname(%d)", fd); + result = ttyname(fd); + _errno = errno; + if (result) + Debug1("ttyname() -> %s", result); + else + Debug("ttyname() -> NULL"); + errno = _errno; + return result; +} + +int Isatty(int fd) { + int result, _errno; + Debug1("isatty(%d)", fd); + result = isatty(fd); + _errno = errno; + Debug1("isatty() -> %d", result); + errno = _errno; + return result; +} + +#if HAVE_OPENPTY +int Openpty(int *ptyfd, int *ttyfd, char *ptyname, struct termios *termp, + struct winsize *winp) { + int result, _errno; + Debug5("openpty(%p, %p, %p, %p, %p)", ptyfd, ttyfd, ptyname, termp, winp); + result = openpty(ptyfd, ttyfd, ptyname, termp, winp); + _errno = errno; + Info4("openpty({%d}, {%d}, {\"%s\"},,) -> %d", *ptyfd, *ttyfd, ptyname, + result); + errno = _errno; + return result; +} +#endif /* HAVE_OPENPTY */ + +#if HAVE_GRANTPT +int Grantpt(int fd) { + int result, _errno; + Debug1("grantpt(%d)", fd); + result = grantpt(fd); + _errno = errno; + Debug1("grantpt() -> %d", result); + errno = _errno; + return result; +} +#endif /* HAVE_GRANTPT */ + +#if HAVE_UNLOCKPT +int Unlockpt(int fd) { + int result, _errno; + Debug1("unlockpt(%d)", fd); + result = unlockpt(fd); + _errno = errno; + Debug1("unlockpt() -> %d", result); + errno = _errno; + return result; +} +#endif /* HAVE_UNLOCKPT */ + +#if HAVE_PTSNAME /* AIX, not Linux */ +char *Ptsname(int fd) { + char *result; + int _errno; + Debug1("ptsname(%d)", fd); + result = ptsname(fd); + _errno = errno; + if (result) + Debug1("ptsname() -> %s", result); + else + Debug("ptsname() -> NULL"); + errno = _errno; + return result; +} +#endif /* HAVE_PTSNAME */ + +int Uname(struct utsname *buf) { + int result, _errno; + Debug1("uname(%p)", buf); + result = uname(buf); + _errno = errno; +#if UNAME_DOMAINNAME + Debug6("uname({%s, %s, %s, %s, %s, %s})", + buf->sysname, buf->nodename, buf->release, + buf->version, buf->machine, buf->domainname); +#else + Debug5("uname({%s, %s, %s, %s, %s})", + buf->sysname, buf->nodename, buf->release, + buf->version, buf->machine); +#endif + errno = _errno; + return result; +} + +int Gethostname(char *name, size_t len) { + int result, _errno; + Debug2("gethostname(%p, "F_Zu")", name, len); + result = gethostname(name, len); + _errno = errno; + Debug2("gethostname(\"%s\", ) -> %d", name, result); + errno = _errno; + return result; +} + +/* due to Linux docu, it does not set errno */ +int Atexit(void (*func)(void)) { + int result; + Debug1("atexit(%p)", func); + result = atexit(func); + Debug1("atexit() -> %d", result); + return result; +} + + +void Exit(int status) { + Debug1("exit(%d)", status); + exit(status); +} + +void Abort(void) { + Debug("abort()"); + abort(); +} + +int Mkstemp(char *template) { + int result, _errno; + Debug1("mkstemp(\"%s\")", template); + result = mkstemp(template); + _errno = errno; + Info2("mkstemp({%s}) -> %d", template, result); + errno = _errno; + return result; +} + +#if WITH_READLINE + +char *Readline(const char *prompt) { + char *result; + + if (prompt) { + Debug1("readline(\"%s\")", prompt); + } else { + Debug("readline(NULL)"); + } + result = readline(prompt); + if (result) { + Debug("readline() -> \"...\""); + } else { + Debug("readline() -> NULL"); + } + return result; +} + +void Using_history(void) { + Debug("using_history()"); + using_history(); + Debug("using_history() ->"); +} + +int Read_history(const char *filename) { + int result; + + if (filename) { + Debug1("read_history(\"%s\")", filename); + } else { + Debug("read_history(NULL)"); + } + result = read_history(filename); + if (result) { + Debug1("read_history() -> %d", result); + } else { + Debug("read_history() -> 0"); + } + return result; +} + +int Write_history(const char *filename) { + int result; + + if (filename) { + Debug1("write_history(\"%s\")", filename); + } else { + Debug("write_history(NULL)"); + } + result = write_history(filename); + if (result) { + Debug1("write_history() -> %d", result); + } else { + Debug("write_history() -> 0"); + } + return result; +} + +int Append_history(int nelements, const char *filename) { + int result; + + if (filename) { + Debug2("append_history(%d, \"%s\")", nelements, filename); + } else { + Debug1("append_history(%d, NULL)", nelements); + } + result = append_history(nelements, filename); + if (result) { + Debug1("append_history() -> %d", result); + } else { + Debug("append_history() -> 0"); + } + return result; +} + +int Where_history(void) { + int result; + + Debug("where_history()"); + result = where_history(); + Debug1("where_history() -> %d", result); + return result; +} + +void Add_history(const char *string) { + Debug1("add_history(\"%s\")", string); + add_history(string); + Debug("add_history() ->"); +} + +#endif /* WITH_READLINE */ + +#endif /* WITH_SYCLS */ diff --git a/sycls.h b/sycls.h new file mode 100644 index 0000000..ffe49db --- /dev/null +++ b/sycls.h @@ -0,0 +1,270 @@ +/* $Id: sycls.h,v 1.50 2007/03/06 21:04:26 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __sycls_h_included +#define __sycls_h_included 1 + +#if WITH_SYCLS +struct termios; /* prevent gcc from spitting silly warning */ +struct utsname; +struct flock; +struct addrinfo; + +mode_t Umask(mode_t mask); +int Open(const char *pathname, int flags, mode_t mode); +int Creat(const char *pathname, mode_t mode); +off_t Lseek(int fildes, off_t offset, int whence); +#if HAVE_LSEEK64 +off64_t Lseek64(int fildes, off64_t offset, int whence); +#endif +pid_t Getpid(void); +pid_t Getppid(void); +pid_t Getpgrp(void); +int Getpgid(pid_t pid); +int Setpgid(pid_t pid, pid_t pgid); +int Setpgrp(void); +pid_t Tcgetpgrp(int fd); +int Tcsetpgrp(int fd, pid_t pgrpid); +pid_t Getsid(pid_t pid); +pid_t Setsid(void); +uid_t Getuid(void); +uid_t Geteuid(void); +int Setuid(uid_t uid); +gid_t Getgid(void); +gid_t Getegid(void); +int Setgid(gid_t gid); +int Initgroups(const char *user, gid_t group); +int Getgroups(int size, gid_t list[]); +int Setgroups(size_t size, const gid_t *list); +int Chdir(const char *path); +int Chroot(const char *path); +int Gettimeofday(struct timeval *tv, struct timezone *tz); +int Mknod(const char *pathname, mode_t mode, dev_t dev); +int Mkfifo(const char *pathname, mode_t mode); +int Stat(const char *file_name, struct stat *buf); +int Fstat(int filedes, struct stat *buf); +int Lstat(const char *file_name, struct stat *buf); +#if HAVE_STAT64 +int Stat64(const char *file_name, struct stat64 *buf); +int Fstat64(int filedes, struct stat64 *buf); +int Lstat64(const char *file_name, struct stat64 *buf); +#endif /* HAVE_STAT64 */ +int Dup(int oldfd); +int Dup2(int oldfd, int newfd); +int Pipe(int filedes[2]); +ssize_t Read(int fd, void *buf, size_t count); +ssize_t Write(int fd, const void *buf, size_t count); +int Fcntl(int fd, int cmd); +int Fcntl_l(int fd, int cmd, long arg); +int Fcntl_lock(int fd, int cmd, struct flock *l); +int Ftruncate(int fd, off_t length); +#if HAVE_FTRUNCATE64 +int Ftruncate64(int fd, off64_t length); +#endif /* HAVE_FTRUNCATE64 */ +int Flock(int fd, int operation); +int Ioctl(int d, int request, void *argp); +int Close(int fd); +int Fchown(int fd, uid_t owner, gid_t group); +int Fchmod(int fd, mode_t mode); +int Unlink(const char *pathname); +int Symlink(const char *oldpath, const char *newpath); +int Readlink(const char *path, char *buf, size_t bufsiz); +int Chown(const char *path, uid_t owner, gid_t group); +int Chmod(const char *path, mode_t mode); +int Poll(struct pollfd *ufds, unsigned int nfds, int timeout); +int Select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + struct timeval *timeout); +pid_t Fork(void); +pid_t Waitpid(pid_t pid, int *status, int options); +#ifndef HAVE_TYPE_SIGHANDLER +typedef RETSIGTYPE (*sighandler_t)(int); +#endif +sighandler_t Signal(int signum, sighandler_t handler); +int Sigaction(int signum, const struct sigaction *act, + struct sigaction *oldact); +int Sigprocmask(int how, const sigset_t *set, sigset_t *oset); +unsigned int Alarm(unsigned int seconds); +int Kill(pid_t pid, int sig); +int Link(const char *oldpath, const char *newpath); +int Execvp(const char *file, char *const argv[]); +int System(const char *string); +int Socketpair(int d, int type, int protocol, int sv[2]); +#if _WITH_SOCKET +int Socket(int domain, int type, int protocol); +int Bind(int sockfd, struct sockaddr *my_addr, int addrlen); +int Connect(int sockfd, const struct sockaddr *serv_addr, int addrlen); +int Listen(int s, int backlog); +int Accept(int s, struct sockaddr *addr, socklen_t *addrlen); +int Getsockname(int s, struct sockaddr *name, socklen_t *namelen); +int Getpeername(int s, struct sockaddr *name, socklen_t *namelen); +int Getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen); +int Setsockopt(int s, int level, int optname, const void *optval, int optlen); +int Recv(int s, void *buf, size_t len, int flags); +int Recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, + socklen_t *fromlen); +int Recvmsg(int s, struct msghdr *msg, int flags); +int Send(int s, const void *mesg, size_t len, int flags); +int Sendto(int s, const void *msg, size_t len, int flags, + const struct sockaddr *to, socklen_t tolen); +int Shutdown(int fd, int how); +#endif /* _WITH_SOCKET */ +unsigned int Sleep(unsigned int seconds); +void Usleep(unsigned long usec); +unsigned int Nanosleep(const struct timespec *req, struct timespec *rem); +int Pause(void); +struct hostent *Gethostbyname(const char *name); +int Getaddrinfo(const char *node, const char *service, + const struct addrinfo *hints, struct addrinfo **res); +struct hostent *Getipnodebyname(const char *name, int af, int flags, + int *error_num); +void *Malloc(size_t size); +void *Calloc(size_t nmemb, size_t size); +void *Realloc(void *ptr, size_t size); +int Tcgetattr(int fd, struct termios *termios_p); +int Tcsetattr(int fd, int optional_actions, struct termios *termios_p); +char *Ttyname(int fd); +int Isatty(int fd); +struct winsize; /* avoid warnings */ +int Openpty(int *ptyfd, int *ttyfd, char *ptyname, struct termios *termp, + struct winsize *winp); +char *Ptsname(int fd); +int Grantpt(int fd); +int Unlockpt(int fd); +int Gethostname(char *name, size_t len); +int Uname(struct utsname *buf); +int Atexit(void (*func)(void)); +void Exit(int status); +void Abort(void); +int Mkstemp(char *template); + +char *Readline(const char *prompt); +void Using_history(void); +int Read_history(const char *filename); +int Write_history(const char *filename); +int Append_history(int nelements, const char *filename); +int Read_history(const char *filename); +void Add_history(const char *string); + +#else /* !WITH_SYCLS */ + +#define Umask(m) umask(m) +#define Open(p,f,m) open(p,f,m) +#define Creat(p,m) creat(p,m) +#define Lseek(f,o,w) lseek(f,o,w) +#define Lseek64(f,o,w) lseek64(f,o,w) +#define Getpid() getpid() +#define Getppid() getppid() +#define Getpgrp() getpgrp() +#define Getpgid(p) getpgid(p) +#define Setpgid(p,g) setpgid(p,g) +#define Setpgrp() setpgrp() +#define Tcgetpgrp(f) tcgetpgrp(f) +#define Tcsetpgrp(f,p) tcsetpgrp(f,p) +#define Getsid(p) getsid(p) +#define Setsid() setsid() +#define Getuid() getuid() +#define Geteuid() geteuid() +#define Setuid(u) setuid(u) +#define Getgid() getgid() +#define Getegid() getegid() +#define Setgid(g) setgid(g) +#define Initgroups(u,g) initgroups(u,g) +#define Getgroups(s,l) getgroups(s,l) +#define Setgroups(s,l) setgroups(s,l) +#define Chdir(p) chdir(p) +#define Chroot(p) chroot(p) +#define Gettimeofday(tv,tz) gettimeofday(tv,tz) +#define Mknod(p,m,d) mknod(p,m,d) +#define Mkfifo(p,m) mkfifo(p,m) +#define Stat(f,b) stat(f,b) +#define Stat64(f,b) stat64(f,b) +#define Fstat(f,b) fstat(f,b) +#define Fstat64(f,b) fstat64(f,b) +#define Lstat(f,b) lstat(f,b) +#define Lstat64(f,b) lstat64(f,b) +#define Dup(o) dup(o) +#define Dup2(o,n) dup2(o,n) +#define Pipe(f) pipe(f) +#define Read(f,b,c) read(f,b,c) +#define Write(f,b,c) write(f,b,c) +#define Fcntl(f,c) fcntl(f,c) +#define Fcntl_l(f,c,a) fcntl(f,c,a) +#define Fcntl_lock(f,c,l) fcntl(f,c,l) +#define Ftruncate(f,l) ftruncate(f,l) +#define Ftruncate64(f,l) ftruncate64(f,l) +#define Flock(f,o) flock(f,o) +#define Ioctl(d,r,a) ioctl(d,r,a) +#define Close(f) close(f) +#define Fchown(f,o,g) fchown(f,o,g) +#define Fchmod(f,m) fchmod(f,m) +#define Unlink(p) unlink(p) +#define Symlink(op,np) symlink(op,np) +#define Readlink(p,b,s) readlink(p,b,s) +#define Chown(p,o,g) chown(p,o,g) +#define Chmod(p,m) chmod(p,m) +#define Poll(u, n, t) poll(u, n, t) +#define Select(n,r,w,e,t) select(n,r,w,e,t) +#define Fork() fork() +#define Waitpid(p,s,o) waitpid(p,s,o) +#define Signal(s,h) signal(s,h) +#define Sigaction(s,a,o) sigaction(s,a,o) +#define Sigprocmask(h,s,o) sigprocmask(h,s,o) +#define Alarm(s) alarm(s) +#define Kill(p,s) kill(p,s) +#define Link(o,n) link(o,n) +#define Execvp(f,a) execvp(f,a) +#define System(s) system(s) +#define Socketpair(d,t,p,s) socketpair(d,t,p,s) +#define Socket(d,t,p) socket(d,t,p) +#define Bind(s,m,a) bind(s,m,a) +#define Connect(s,a,l) connect(s,a,l) +#define Listen(s,b) listen(s,b) +#define Accept(s,a,l) accept(s,a,l) +#define Getsockname(s,n,l) getsockname(s,n,l) +#define Getpeername(s,n,l) getpeername(s,n,l) +#define Getsockopt(s,d,n,v,l) getsockopt(s,d,n,v,l) +#define Setsockopt(s,d,n,v,l) setsockopt(s,d,n,v,l) +#define Recv(s,b,l,f) recv(s,b,l,f) +#define Recvfrom(s,b,bl,f,fr,fl) recvfrom(s,b,bl,f,fr,fl) +#define Recvmsg(s,m,f) recvmsg(s,m,f) +#define Send(s,m,l,f) send(s,m,l,f) +#define Sendto(s,b,bl,f,t,tl) sendto(s,b,bl,f,t,tl) +#define Shutdown(f,h) shutdown(f,h) +#define Sleep(s) sleep(s) +#define Usleep(u) usleep(u) +#define Nanosleep(req,rem) nanosleep(req,rem) +#define Pause() pause() +#define Gethostbyname(n) gethostbyname(n) +#define Getaddrinfo(n,s,h,r) getaddrinfo(n,s,h,r) +#define Getipnodebyname(n,a,f,e) getipnodebyname(n,a,f,e) +#define Malloc(s) malloc(s) +#define Calloc(n,s) calloc(n,s) +#define Realloc(p,s) realloc(p,s) +#define Tcgetattr(f,t) tcgetattr(f,t) +#define Tcsetattr(f,o,t) tcsetattr(f,o,t) +#define Ttyname(f) ttyname(f) +#define Isatty(f) isatty(f) +#define Openpty(p,t,n,i,f) openpty(p,t,n,i,f) +#define Ptsname(f) ptsname(f) +#define Grantpt(f) grantpt(f) +#define Unlockpt(f) unlockpt(f) +#define Getpgid(p) getpgid(p) +#define Gethostname(n,l) gethostname(n,l) +#define Uname(b) uname(b) +#define Atexit(f) atexit(f) +#define Exit(s) exit(s) +#define Abort() abort() +#define Mkstemp(t) mkstemp(t) + +#define Readline(p) readline(p) +#define Using_history() using_history() +#define Read_history(f) read_history(f) +#define Write_history(f) write_history(f) +#define Append_history(n,f) append_history(n,f) +#define Read_history(f) read_history(f) +#define Add_history(s) add_history(s) + +#endif /* !WITH_SYCLS */ + +#endif /* !defined(__sycls_h_included) */ diff --git a/sysincludes.h b/sysincludes.h new file mode 100644 index 0000000..a2b9f8a --- /dev/null +++ b/sysincludes.h @@ -0,0 +1,161 @@ +/* $Id: sysincludes.h,v 1.23 2007/03/06 21:04:58 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __sysincludes_h_included +#define __sysincludes_h_included 1 + +#if HAVE_LIMITS_H +#include /* USHRT_MAX */ +#endif +#include /* HUGE_VAL */ +#include +#include /* for msg() */ +#include /* strerror(), strchr() */ +#if HAVE_STRINGS_H +#include /* strcasecmp(), bzero() for FD_ZERO */ +#endif +#include /* malloc(), free() */ +#include /* isdigit() */ +#include /* FILE */ +#include /* errno */ +#if HAVE_SYSLOG_H +#include /* openlog(), syslog(), closelog() */ +#endif +#include /* signal(), SIGPIPE, SIG_IGN */ +#include /* struct timeval, strftime() */ +#include /* struct timeb */ +#if HAVE_UNISTD_H +#include /* select(), read(), write(), stat(), fork() */ +#endif +#if HAVE_PWD_H +#include /* getpwnam() */ +#endif +#if HAVE_GRP_H +#include /* getgrnam() */ +#endif +#if HAVE_PTY_H +#include +#endif +#if HAVE_SYS_PARAM_H +#include /* Linux 2.4 NGROUPS */ +#endif +#if HAVE_SYS_TIME_H +#include /* select(); OpenBSD: struct timespec */ +#endif +#if HAVE_STDINT_H +#include /* uint8_t */ +#endif +#if HAVE_SYS_TYPES_H +#include /* pid_t, select(), socket(), connect(), open(), u_short */ +#endif +#if HAVE_SYS_POLL_H +#include /* poll() */ +#endif +#if HAVE_SYS_SOCKET_H +#include /* struct sockaddr, struct linger, socket(), connect() */ +#endif +#if HAVE_SYS_UIO_H +#include /* struct iovec */ +#endif +#if HAVE_SYS_STAT_H +#include /* struct stat, stat(), open() */ +#endif +#if HAVE_SYS_WAIT_H +#include /* WNOHANG */ +#endif +#if HAVE_FCNTL_H +#include /* open(), O_RDWR */ +#endif +#if HAVE_NETDB_H && (_WITH_IP4 || _WITH_IP6) +#include /* struct hostent, gethostbyname() */ +#endif +#if HAVE_SYS_UN_H && WITH_UNIX +#include /* struct sockaddr_un, unix domain sockets */ +#endif +#if HAVE_SYS_IOCTL_H +#include /* ioctl() */ +#endif +#if HAVE_SYS_SELECT_H +#include /* select(), fdset on AIX 4.1 */ +#endif +#if HAVE_SYS_FILE_H +#include /* LOCK_EX, on AIX directly included */ +#endif +#if _WITH_SOCKET +# if HAVE_NETINET_IN_H +#include /* struct sockaddr_in, htonl() */ +# endif +#endif /* _WITH_SOCKET */ +#if _WITH_SOCKET && (_WITH_IP4 || _WITH_IP6) +# if HAVE_NETINET_IN_SYSTM_H +#include /* Solaris, FreeBSD: n_long */ +# endif +# if HAVE_NETINET_IP_H +#include /* struct ip - past netinet/in.h on AIX! */ +# endif +# if HAVE_NETINET_TCP_H +#include /* TCP_RFC1323 */ +# endif +# if HAVE_NETINET_IP6_H && _WITH_IP6 +#include +# endif +# if HAVE_NETINET6_IN6_H && _WITH_IP6 +#include +# endif +#include /* Linux: inet_aton() */ +#if HAVE_ARPA_NAMESER_H +#include /* req for resolv.h (esp. on MacOSX) */ +#endif +#include +#if HAVE_RESOLV_H +#include /* _res */ +#endif +#endif /* _WITH_IP4 || _WITH_IP6 */ +/*#include */ +#if HAVE_NET_IF_H +#include +#endif /* HAVE_NET_IF_H */ +#if HAVE_LINUX_IF_TUN_H +#include +#endif + +#if HAVE_TERMIOS_H && WITH_TERMIOS +#include +#endif +#if HAVE_SYS_UTSNAME_H +#include /* uname(), struct utsname */ +#endif +#if HAVE_UTIL_H +#include /* NetBSD, OpenBSD openpty() */ +#endif +#if HAVE_LIBUTIL_H +#include /* FreeBSD openpty() */ +#endif +#if HAVE_SYS_STROPTS_H +#include /* SunOS I_PUSH ... */ +#endif +#if HAVE_REGEX_H +#include +#endif +#if HAVE_LINUX_FS_H +#include /* somewhere required for ext2_fs.h */ +#endif +#if HAVE_LINUX_EXT2_FS_H +#include /* Linux ext2 filesystem definitions */ +#endif +#if WITH_READLINE +# if HAVE_READLINE_READLINE_H +#include +# endif +# if HAVE_READLINE_HISTORY_H +#include +# endif +#endif /* WITH_READLINE */ +#if WITH_OPENSSL +#include +#include +#include +#endif + +#endif /* !defined(__sysincludes_h_included) */ diff --git a/sysutils.c b/sysutils.c new file mode 100644 index 0000000..c10e2ea --- /dev/null +++ b/sysutils.c @@ -0,0 +1,495 @@ +/* $Id: sysutils.c,v 1.44 2007/03/06 21:05:11 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* translate socket addresses into human readable form */ + +#include "config.h" +#include "xioconfig.h" + +#include "sysincludes.h" + +#include "compat.h" /* socklen_t */ +#include "mytypes.h" +#include "error.h" +#include "sycls.h" +#include "utils.h" +#include "sysutils.h" + + +#if WITH_UNIX +void socket_un_init(struct sockaddr_un *sa) { +#if HAVE_STRUCT_SOCKADDR_SALEN + sa->sun_len = sizeof(struct sockaddr_un); +#endif + sa->sun_family = AF_UNIX; + memset(sa->sun_path, '\0', sizeof(sa->sun_path)); +} +#endif /* WITH_UNIX */ + +#if WITH_IP4 +void socket_in_init(struct sockaddr_in *sa) { +#if HAVE_STRUCT_SOCKADDR_SALEN + sa->sin_len = sizeof(struct sockaddr_in); +#endif + sa->sin_family = AF_INET; + sa->sin_port = 0; + sa->sin_addr.s_addr = 0; + sa->sin_zero[0] = 0; + sa->sin_zero[1] = 0; + sa->sin_zero[2] = 0; + sa->sin_zero[3] = 0; + sa->sin_zero[4] = 0; + sa->sin_zero[5] = 0; + sa->sin_zero[6] = 0; + sa->sin_zero[7] = 0; +} +#endif /* WITH_IP4 */ + +#if WITH_IP6 +void socket_in6_init(struct sockaddr_in6 *sa) { +#if HAVE_STRUCT_SOCKADDR_SALEN + sa->sin6_len = sizeof(struct sockaddr_in6); +#endif + sa->sin6_family = AF_INET6; + sa->sin6_port = 0; + sa->sin6_flowinfo = 0; +#if HAVE_IP6_SOCKADDR==0 + sa->sin6_addr.s6_addr[0] = 0; + sa->sin6_addr.s6_addr[1] = 0; + sa->sin6_addr.s6_addr[2] = 0; + sa->sin6_addr.s6_addr[3] = 0; + sa->sin6_addr.s6_addr[4] = 0; + sa->sin6_addr.s6_addr[5] = 0; + sa->sin6_addr.s6_addr[6] = 0; + sa->sin6_addr.s6_addr[7] = 0; + sa->sin6_addr.s6_addr[8] = 0; + sa->sin6_addr.s6_addr[9] = 0; + sa->sin6_addr.s6_addr[10] = 0; + sa->sin6_addr.s6_addr[11] = 0; + sa->sin6_addr.s6_addr[12] = 0; + sa->sin6_addr.s6_addr[13] = 0; + sa->sin6_addr.s6_addr[14] = 0; + sa->sin6_addr.s6_addr[15] = 0; +#elif HAVE_IP6_SOCKADDR==1 + sa->sin6_addr.u6_addr.u6_addr32[0] = 0; + sa->sin6_addr.u6_addr.u6_addr32[1] = 0; + sa->sin6_addr.u6_addr.u6_addr32[2] = 0; + sa->sin6_addr.u6_addr.u6_addr32[3] = 0; +#elif HAVE_IP6_SOCKADDR==2 + sa->sin6_addr.u6_addr32[0] = 0; + sa->sin6_addr.u6_addr32[1] = 0; + sa->sin6_addr.u6_addr32[2] = 0; + sa->sin6_addr.u6_addr32[3] = 0; +#elif HAVE_IP6_SOCKADDR==3 + sa->sin6_addr.in6_u.u6_addr32[0] = 0; + sa->sin6_addr.in6_u.u6_addr32[1] = 0; + sa->sin6_addr.in6_u.u6_addr32[2] = 0; + sa->sin6_addr.in6_u.u6_addr32[3] = 0; +#elif HAVE_IP6_SOCKADDR==4 + sa->sin6_addr._S6_un._S6_u32[0] = 0; + sa->sin6_addr._S6_un._S6_u32[1] = 0; + sa->sin6_addr._S6_un._S6_u32[2] = 0; + sa->sin6_addr._S6_un._S6_u32[3] = 0; +#elif HAVE_IP6_SOCKADDR==5 + sa->sin6_addr.__u6_addr.__u6_addr32[0] = 0; + sa->sin6_addr.__u6_addr.__u6_addr32[1] = 0; + sa->sin6_addr.__u6_addr.__u6_addr32[2] = 0; + sa->sin6_addr.__u6_addr.__u6_addr32[3] = 0; +#endif +} +#endif /* WITH_IP6 */ + + +#if _WITH_SOCKET +/* initializes the socket address of the specified address family. Returns the + length of the specific socket address, or 0 on error. */ +socklen_t socket_init(int af, union sockaddr_union *sa) { + switch (af) { +#if WITH_UNIX + case AF_UNIX: socket_un_init(&sa->un); return sizeof(sa->un); +#endif +#if WITH_IP4 + case AF_INET: socket_in_init(&sa->ip4); return sizeof(sa->ip4); +#endif +#if WITH_IP6 + case AF_INET6: socket_in6_init(&sa->ip6); return sizeof(sa->ip6); +#endif + default: Error1("socket_init(): unknown address family %d", af); + memset(sa, 0, sizeof(union sockaddr_union)); + sa->soa.sa_family = af; + return 0; + } +} +#endif /* _WITH_SOCKET */ + +#if WITH_UNIX +#define XIOUNIXSOCKOVERHEAD (sizeof(struct sockaddr_un)-sizeof(((struct sockaddr_un*)0)->sun_path)) +#endif + +#if _WITH_SOCKET +char *sockaddr_info(const struct sockaddr *sa, socklen_t salen, char *buff, size_t blen) { + char ubuff[5*UNIX_PATH_MAX+3]; + char *lbuff = buff; + char *cp = lbuff; + int n; + + if ((n = snprintf(cp, blen, "AF=%d ", sa->sa_family)) < 0) { + Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen); + *buff = '\0'; + return buff; + } + cp += n, blen -= n; + + switch (sa->sa_family) { +#if WITH_UNIX + case 0: + case AF_UNIX: +#if WITH_ABSTRACT_UNIXSOCKET + if (salen > XIOUNIXSOCKOVERHEAD && + sa->sa_data[0] == '\0') { + char *nextc; +// nextc = +// sanitize_string((char *)&sa->sa_data+1, salen-XIOUNIXSOCKOVERHEAD-1, +// ubuff, XIOSAN_DEFAULT_BACKSLASH_OCT_3); + nextc = + sanitize_string((char *)&sa->sa_data, salen-XIOUNIXSOCKOVERHEAD, + ubuff, XIOSAN_DEFAULT_BACKSLASH_OCT_3); + *nextc = '\0'; +// snprintf(cp, blen, "\"\\0%s\"", ubuff); + snprintf(cp, blen, "\"%s\"", ubuff); + } else +#endif /* WITH_ABSTRACT_UNIXSOCKET */ + { + char *nextc; + nextc = + sanitize_string((char *)&sa->sa_data, + MIN(UNIX_PATH_MAX, strlen((char *)&sa->sa_data)), + ubuff, XIOSAN_DEFAULT_BACKSLASH_OCT_3); + *nextc = '\0'; + snprintf(cp, blen, "\"%s\"", ubuff); + } + break; +#endif +#if WITH_IP4 + case AF_INET: sockaddr_inet4_info((struct sockaddr_in *)sa, cp, blen); + break; +#endif +#if WITH_IP6 + case AF_INET6: sockaddr_inet6_info((struct sockaddr_in6 *)sa, cp, blen); + break; +#endif + default: + if ((snprintf(cp, blen, + "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + sa->sa_data[0], sa->sa_data[1], sa->sa_data[2], + sa->sa_data[3], sa->sa_data[4], sa->sa_data[5], + sa->sa_data[6], sa->sa_data[7], sa->sa_data[8], + sa->sa_data[9], sa->sa_data[10], sa->sa_data[11], + sa->sa_data[12], sa->sa_data[13])) < 0) { + Warn("sockaddr_info(): buffer too short"); + *buff = '\0'; + return buff; + } + } + return lbuff; +} +#endif /* _WITH_SOCKET */ + + +#if WITH_UNIX +char *sockaddr_unix_info(const struct sockaddr_un *sa, socklen_t salen, char *buff, size_t blen) { + blen = Min(blen, sizeof(sa->sun_path)); + strncpy(buff, sa->sun_path, blen); + if (strlen(buff) >= blen) { + buff[blen-1] = '\0'; + } + return buff; +} +#endif /* WITH_UNIX */ + +#if WITH_IP4 +/* addr in host byte order! */ +char *inet4addr_info(uint32_t addr, char *buff, size_t blen) { + if (snprintf(buff, blen, "%u.%u.%u.%u", + (unsigned int)(addr >> 24), (unsigned int)((addr >> 16) & 0xff), + (unsigned int)((addr >> 8) & 0xff), (unsigned int)(addr & 0xff)) < 0) { + Warn("inet4addr_info(): buffer too short"); + buff[blen-1] = '\0'; + } + return buff; +} +#endif /* WITH_IP4 */ + +#if WITH_IP4 +char *sockaddr_inet4_info(const struct sockaddr_in *sa, char *buff, size_t blen) { + if (snprintf(buff, blen, "%u.%u.%u.%u:%hu", + ((unsigned char *)&sa->sin_addr.s_addr)[0], + ((unsigned char *)&sa->sin_addr.s_addr)[1], + ((unsigned char *)&sa->sin_addr.s_addr)[2], + ((unsigned char *)&sa->sin_addr.s_addr)[3], + htons(sa->sin_port)) < 0) { + Warn("sockaddr_inet4_info(): buffer too short"); + buff[blen-1] = '\0'; + } + return buff; +} +#endif /* WITH_IP4 */ + +#if !HAVE_INET_NTOP +/* http://www.opengroup.org/onlinepubs/000095399/functions/inet_ntop.html */ +const char *inet_ntop(int pf, const void *binaddr, + char *addrtext, socklen_t textlen) { + size_t retlen; + switch (pf) { + case PF_INET: + if ((retlen = + snprintf(addrtext, textlen, "%u.%u.%u.%u", + ((unsigned char *)binaddr)[0], + ((unsigned char *)binaddr)[1], + ((unsigned char *)binaddr)[2], + ((unsigned char *)binaddr)[3])) + < 0) { + return NULL; /* errno is valid */ + } + break; + case PF_INET6: + if ((retlen = + snprintf(addrtext, textlen, "%x:%x:%x:%x:%x:%x:%x:%x", + ntohs(((uint16_t *)binaddr)[0]), + ntohs(((uint16_t *)binaddr)[1]), + ntohs(((uint16_t *)binaddr)[2]), + ntohs(((uint16_t *)binaddr)[3]), + ntohs(((uint16_t *)binaddr)[4]), + ntohs(((uint16_t *)binaddr)[5]), + ntohs(((uint16_t *)binaddr)[6]), + ntohs(((uint16_t *)binaddr)[7]) + )) + < 0) { + return NULL; /* errno is valid */ + } + break; + default: + errno = EAFNOSUPPORT; + return NULL; + } + addrtext[retlen] = '\0'; + return addrtext; +} +#endif /* !HAVE_INET_NTOP */ + +#if WITH_IP6 +/* convert the IP6 socket address to human readable form. buff should be at + least 50 chars long */ +char *sockaddr_inet6_info(const struct sockaddr_in6 *sa, char *buff, size_t blen) { + if (snprintf(buff, blen, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:%hu", +#if HAVE_IP6_SOCKADDR==0 + (sa->sin6_addr.s6_addr[0]<<8)+ + sa->sin6_addr.s6_addr[1], + (sa->sin6_addr.s6_addr[2]<<8)+ + sa->sin6_addr.s6_addr[3], + (sa->sin6_addr.s6_addr[4]<<8)+ + sa->sin6_addr.s6_addr[5], + (sa->sin6_addr.s6_addr[6]<<8)+ + sa->sin6_addr.s6_addr[7], + (sa->sin6_addr.s6_addr[8]<<8)+ + sa->sin6_addr.s6_addr[9], + (sa->sin6_addr.s6_addr[10]<<8)+ + sa->sin6_addr.s6_addr[11], + (sa->sin6_addr.s6_addr[12]<<8)+ + sa->sin6_addr.s6_addr[13], + (sa->sin6_addr.s6_addr[14]<<8)+ + sa->sin6_addr.s6_addr[15], +#elif HAVE_IP6_SOCKADDR==1 + ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[0]), + ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[1]), + ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[2]), + ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[3]), + ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[4]), + ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[5]), + ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[6]), + ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[7]), +#elif HAVE_IP6_SOCKADDR==2 + ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[0]), + ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[1]), + ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[2]), + ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[3]), + ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[4]), + ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[5]), + ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[6]), + ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[7]), +#elif HAVE_IP6_SOCKADDR==3 + ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[0]), + ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[1]), + ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[2]), + ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[3]), + ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[4]), + ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[5]), + ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[6]), + ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[7]), +#elif HAVE_IP6_SOCKADDR==4 + (sa->sin6_addr._S6_un._S6_u8[0]<<8)|(sa->sin6_addr._S6_un._S6_u8[1]&0xff), + (sa->sin6_addr._S6_un._S6_u8[2]<<8)|(sa->sin6_addr._S6_un._S6_u8[3]&0xff), + (sa->sin6_addr._S6_un._S6_u8[4]<<8)|(sa->sin6_addr._S6_un._S6_u8[5]&0xff), + (sa->sin6_addr._S6_un._S6_u8[6]<<8)|(sa->sin6_addr._S6_un._S6_u8[7]&0xff), + (sa->sin6_addr._S6_un._S6_u8[8]<<8)|(sa->sin6_addr._S6_un._S6_u8[9]&0xff), + (sa->sin6_addr._S6_un._S6_u8[10]<<8)|(sa->sin6_addr._S6_un._S6_u8[11]&0xff), + (sa->sin6_addr._S6_un._S6_u8[12]<<8)|(sa->sin6_addr._S6_un._S6_u8[13]&0xff), + (sa->sin6_addr._S6_un._S6_u8[14]<<8)|(sa->sin6_addr._S6_un._S6_u8[15]&0xff), +#elif HAVE_IP6_SOCKADDR==5 + ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[0]), + ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[1]), + ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[2]), + ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[3]), + ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[4]), + ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[5]), + ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[6]), + ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[7]), +#endif + ntohs(sa->sin6_port)) < 0) { + Warn("sockaddr_inet6_info(): buffer too short"); + buff[blen-1] = '\0'; + } + return buff; +} +#endif /* WITH_IP6 */ + +/* fill the list with the supplementary group ids of user. + caller passes size of list in ngroups, function returns number of groups in + ngroups. + function returns 0 if 0 or more groups were found, or 1 if the list is too + short. */ +int getusergroups(const char *user, gid_t *list, size_t *ngroups) { + struct group *grp; + size_t i = 0; + + setgrent(); + while (grp = getgrent()) { + char **gusr = grp->gr_mem; + while (*gusr) { + if (!strcmp(*gusr, user)) { + if (i == *ngroups) + return 1; + list[i++] = grp->gr_gid; + break; + } + ++gusr; + } + } + endgrent(); + *ngroups = i; + return 0; +} + +#if !HAVE_HSTRERROR +const char *hstrerror(int err) { + static const char *h_messages[] = { + "success", + "authoritative answer not found", + "non-authoritative, host not found, or serverfail", + "Host name lookup failure", /* "non recoverable error" */ + "valid name, no data record of requested type" }; + + assert(HOST_NOT_FOUND==1); + assert(TRY_AGAIN==2); + assert(NO_RECOVERY==3); + assert(NO_DATA==4); + if ((err < 0) || err > sizeof(h_messages)/sizeof(const char *)) { + return ""; + } + return h_messages[err]; +} +#endif /* !HAVE_HSTRERROR */ + + +#if WITH_TCP || WITH_UDP +/* returns port in network byte order */ +int parseport(const char *portname, int ipproto) { + struct servent *se; + char *extra; + int result; + + if (isdigit(portname[0]&0xff)) { + result = htons(strtoul(portname, &extra, 0)); + if (*extra != '\0') { + Error3("parseport(\"%s\", %d): extra trailing data \"%s\"", + portname, ipproto, extra); + } + return result; + } + + if ((se = getservbyname(portname, ipproto==IPPROTO_TCP?"tcp":"udp")) == NULL) { + Error2("cannot resolve service \"%s/%d\"", portname, ipproto); + return 0; + } + + return se->s_port; +} +#endif /* WITH_TCP || WITH_UDP */ + +#if WITH_IP4 || WITH_IP6 +/* check the systems interfaces for ifname and return its index + or -1 if no interface with this name was found */ +int ifindexbyname(const char *ifname) { + /* Linux: man 7 netdevice */ + /* FreeBSD: man 4 networking */ + /* Solaris: man 7 if_tcp */ + +#if defined(HAVE_STRUCT_IFREQ) && defined(SIOCGIFCONF) && defined(SIOCGIFINDEX) + /* currently we support Linux, FreeBSD; not Solaris */ + +#define IFBUFSIZ 1024 + int s; + struct ifreq ifr; + + if (ifname[0] == '\0') { + return -1; + } + if ((s = Socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) { + Error1("socket(PF_INET, SOCK_DGRAM, IPPROTO_IP): %s", strerror(errno)); + return -1; + } + + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + if (Ioctl(s, SIOCGIFINDEX, &ifr) < 0) { + Close(s); + Info3("ioctl(%d, SIOCGIFINDEX, {%s}): %s", + s, ifr.ifr_name, strerror(errno)); + return -1; + } + Close(s); +#if HAVE_STRUCT_IFREQ_IFR_INDEX + return ifr.ifr_index; +#elif HAVE_STRUCT_IFREQ_IFR_IFINDEX + return ifr.ifr_ifindex; +#endif /* HAVE_STRUCT_IFREQ_IFR_IFINDEX */ + +#else /* !defined(HAVE_ STRUCT_IFREQ) && defined(SIOCGIFCONF) && defined(SIOCGIFINDEX) */ + return -1; +#endif /* !defined(HAVE_ STRUCT_IFREQ) && defined(SIOCGIFCONF) && defined(SIOCGIFINDEX) */ +} + + +/* like ifindexbyname(), but allows an index number as input. + writes the resulting index to *ifindex and returns 0, + or returns -1 on error */ +int ifindex(const char *ifname, unsigned int *ifindex) { + char *endptr; + long int val; + + if (ifname[0] == '\0') { + return -1; + } + val = strtol(ifname, &endptr, 0); + if (endptr[0] == '\0') { + *ifindex = val; + return 0; + } + + if ((val = ifindexbyname(ifname)) < 0) { + return -1; + } + *ifindex = val; + return 0; +} +#endif /* WITH_IP4 || WITH_IP6 */ diff --git a/sysutils.h b/sysutils.h new file mode 100644 index 0000000..7e326b8 --- /dev/null +++ b/sysutils.h @@ -0,0 +1,98 @@ +/* $Id: sysutils.h,v 1.23 2007/03/06 21:05:37 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __sysutils_h_included +#define __sysutils_h_included 1 + +#if WITH_IP6 +/* not all OSes provide in6_addr that allows splitting to 16 or 32 bit junks of + the host address part of sockaddr_in6; here we help ourselves */ +union xioin6_u { + uint8_t u6_addr8[16]; + uint16_t u6_addr16[8]; + uint32_t u6_addr32[4]; +} ; +#endif /* WITH_IP6 */ + +union sockaddr_union { + struct sockaddr soa; +#if WITH_UNIX + struct sockaddr_un un; +#endif /* WITH_UNIX */ +#if WITH_IP4 + struct sockaddr_in ip4; +#endif /* WITH_IP4 */ +#if WITH_IP6 + struct sockaddr_in6 ip6; +#endif /* WITH_IP6 */ +} ; + +#if _WITH_IP4 +struct xiorange_ip4 { + struct in_addr netaddr; /* network byte order */ + struct in_addr netmask; /* network byte order */ +} ; +#endif /* _WITH_IP4 */ + +#if _WITH_IP6 +struct xiorange_ip6 { + struct in6_addr addr; + struct in6_addr mask; +} ; +#endif /* _WITH_IP4 */ + +#if _WITH_SOCKET +union xiorange_union { +#if _WITH_IP4 + struct xiorange_ip4 ip4; +#endif /* _WITH_IP4 */ +#if _WITH_IP6 + struct xiorange_ip6 ip6; +#endif /* _WITH_IP6 */ +} ; +#endif /* _WITH_SOCKET */ + +#if _WITH_SOCKET +extern socklen_t socket_init(int af, union sockaddr_union *sa); +#endif +#if WITH_UNIX +extern void socket_un_init(struct sockaddr_un *sa); +#endif /* WITH_UNIX */ +#if _WITH_IP4 +extern void socket_in_init(struct sockaddr_in *sa); +#endif /* _WITH_IP4 */ +#if _WITH_IP6 +extern void socket_in6_init(struct sockaddr_in6 *sa); +#endif /* _WITH_IP4 */ + +#if _WITH_SOCKET +extern char *sockaddr_info(const struct sockaddr *sa, socklen_t salen, char *buff, size_t blen); +#endif +#if WITH_UNIX +extern char *sockaddr_unix_info(const struct sockaddr_un *sa, socklen_t salen, char *buff, size_t blen); +#endif /* WITH_UNIX */ +#if WITH_IP4 +extern char *inet4addr_info(uint32_t addr, char *buff, size_t blen); +extern char *sockaddr_inet4_info(const struct sockaddr_in *sa, char *buff, size_t blen); +#endif /* WITH_IP4 */ +#if WITH_IP6 +extern char *sockaddr_inet6_info(const struct sockaddr_in6 *sa, char *buff, size_t blen); +#endif /* WITH_IP6 */ +#if !HAVE_INET_NTOP +extern const char *inet_ntop(int pf, const void *binaddr, + char *addrtext, socklen_t textlen); +#endif + +extern int getusergroups(const char *user, gid_t *list, size_t *ngroups); + +#if !HAVE_HSTRERROR +extern const char *hstrerror(int err); +#endif + +extern int parseport(const char *portname, int proto); + +extern int ifindexbyname(const char *ifname); +extern int ifindex(const char *ifname, unsigned int *ifindex); + +#endif /* !defined(__sysutils_h_included) */ diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..c1e6e5c --- /dev/null +++ b/test.sh @@ -0,0 +1,7790 @@ +#! /bin/bash +# $Id: test.sh,v 1.134 2007/03/06 21:06:20 gerhard Exp $ +# Copyright Gerhard Rieger 2001-2007 +# Published under the GNU General Public License V.2, see file COPYING + +# perform lots of tests on socat + +# this script uses functions; you need a shell that supports them + +# you can pass general options to socat via $OPTS + +#set -vx + +withroot=0 # perform privileged tests even if not run by root +#PATH=$PATH:/opt/freeware/bin +#PATH=$PATH:/usr/local/ssl/bin +#OPENSSL_RAND="-rand /dev/egd-pool" +#SOCAT_EGD="egd=/dev/egd-pool" +MISCDELAY=1 +[ -z "$SOCAT" ] && SOCAT="./socat" +[ -z "$PROCAN" ] && PROCAN="./procan" +[ -z "$FILAN" ] && FILAN="./filan" +opts="-t0.1 $OPTS" +export SOCAT_OPTS="$opts" +#debug="1" +debug= +TESTS="$@" +INTERFACE=eth0; # not used for function tests +MCINTERFACE=lo # !!! Linux only +#LOCALHOST=192.168.58.1 +#LOCALHOST=localhost +LOCALHOST=127.0.0.1 +LOCALHOST6=[::1] +PROTO=$((192+RANDOM/1024)) +PORT=12002 +SOURCEPORT=2002 +CAT=cat +OD_C="od -c" +# time in microseconds to wait in some situations +MICROS=100000 +if ! type usleep >/dev/null 2>&1; then + usleep () { + local n="$1" + # older bashes do not accept $1 here: + sleep $(((n+999999)/1000000)) + } +fi +#USLEEP=usleep +F_n="%3d" # format string for test numbers +LANG=C +LANGUAGE=C # knoppix +UNAME=`uname` +case "$UNAME" in +HP-UX|OSF1) + echo "$SOCAT -u stdin stdout" >cat.sh + chmod a+x cat.sh + CAT=./cat.sh + ;; +*) + CAT=cat + ;; +esac + +case "$UNAME" in +#HP-UX) +# # on HP-UX, the default options (below) hang some tests (former 14, 15) +# PTYOPTS= +# PTYOPTS2= +# ;; +*) + PTYOPTS="echo=0,opost=0" + PTYOPTS2="raw,echo=0" + ;; +esac + +# non-root users might miss ifconfig in their path +case "$UNAME" in +AIX) IFCONFIG=/usr/sbin/ifconfig ;; +FreeBSD) IFCONFIG=/sbin/ifconfig ;; +HP-UX) IFCONFIG=/usr/sbin/ifconfig ;; +Linux) IFCONFIG=/sbin/ifconfig ;; +NetBSD)IFCONFIG=/sbin/ifconfig ;; +OpenBSD)IFCONFIG=/sbin/ifconfig ;; +OSF1) IFCONFIG=/sbin/ifconfig ;; +SunOS) IFCONFIG=/sbin/ifconfig ;; +#*) IFCONFIG=/sbin/ifconfig ;; +esac + +# for some tests we need a second local IPv4 address +case "$UNAME" in +Linux) + BROADCASTIF=eth0 + SECONDADDR=127.0.0.2 + BCADDR=127.255.255.255 + BCIFADDR=$($IFCONFIG $BROADCASTIF |grep 'inet ' |awk '{print($2);}' |cut -d: -f2) ;; +FreeBSD|NetBSD|OpenBSD) + MAINIF=$($IFCONFIG -a |grep '^[a-z]' |head -1 |cut -d: -f1) + BROADCASTIF="$MAINIF" + SECONDADDR=$($IFCONFIG $BROADCASTIF |grep 'inet ' |awk '{print($2);}') + BCIFADDR="$SECONDADDR" + BCADDR=$($IFCONFIG $BROADCASTIF |grep 'broadcast ' |sed 's/.*broadcast/broadcast/' |awk '{print($2);}') ;; +HP-UX) + MAINIF=lan0 # might use "netstat -ni" for this + BROADCASTIF="$MAINIF" + SECONDADDR=$($IFCONFIG $MAINIF |tail -n 1 |awk '{print($2);}') + BCADDR=$($IFCONFIG $BROADCASTIF |grep 'broadcast ' |sed 's/.*broadcast/broadcast/' |awk '{print($2);}') ;; +SunOS) + #BROADCASTIF=hme0 + BROADCASTIF=eri0 + SECONDADDR=$($IFCONFIG $BROADCASTIF |grep 'inet ' |awk '{print($2);}') + BCIFADDR="$SECONDADDR" + BCADDR=$($IFCONFIG $BROADCASTIF |grep 'broadcast ' |sed 's/.*broadcast/broadcast/' |awk '{print($2);}') ;; +#AIX|FreeBSD|Solaris) +*) + SECONDADDR=$(expr "$($IFCONFIG -a |grep 'inet ' |fgrep -v ' 127.0.0.1 '| head -n 1)" : '.*inet \([0-9.]*\) .*') + ;; +esac + +# for some tests we need a second local IPv6 address +case "$UNAME" in +*) + SECONDIP6ADDR=$(expr "$($IFCONFIG -a |grep 'inet6 ' |fgrep -v ' ::1/128 '| head -n 1)" : '.*inet \([0-9.]*\) .*') + ;; +esac +if [ -z "$SECONDIP6ADDR" ]; then + case "$TESTS" in + *%root2%*) $IFCONFIG eth0 ::2/128 + esac +fi + +TRUE=$(which true) +#E=-e # Linux +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 + exit 1 +fi +ECHO="echo $E" +PRINTF="printf" + +case "$TERM" in +vt100|vt320|linux|xterm|cons25|dtterm|aixterm|sun-color) + # there are different behaviours of printf (and echo) + # on some systems, echo behaves different than printf... + if [ $($PRINTF "\0101") = "A" ]; then + RED="\0033[31m" + GREEN="\0033[32m" + YELLOW="\0033[33m" + if [ "$UNAME" = SunOS ]; then + NORMAL="\0033[30m" + else + NORMAL="\0033[39m" + fi + else + RED="\033[31m" + GREEN="\033[32m" + YELLOW="\033[33m" + if [ "$UNAME" = SunOS ]; then + NORMAL="\033[30m" + else + NORMAL="\033[39m" + fi + fi + OK="${GREEN}OK${NORMAL}" + FAILED="${RED}FAILED${NORMAL}" + NO_RESULT="${YELLOW}NO RESULT${NORMAL}" + ;; +*) OK="OK" + FAILED="FAILED" + NO_RESULT="NO RESULT" + ;; +esac + + +if [ -x /usr/xpg4/bin/id ]; then + # SunOS has rather useless tools in its default path + PATH="/usr/xpg4/bin:$PATH" +fi + +[ -z "$TESTS" ] && TESTS="consistency functions filan" +# use '%' as separation char +TESTS="%$(echo "$TESTS" |tr ' ' '%')%" + +[ -z "$USER" ] && USER="$LOGNAME" # HP-UX +if [ -z "$TMPDIR" ]; then + if [ -z "$TMP" ]; then + TMP=/tmp + fi + TMPDIR="$TMP" +fi +TD="$TMPDIR/$USER/$$"; td="$TD" +rm -rf "$TD" || (echo "cannot rm $TD" >&2; exit 1) +mkdir -p "$TD" +#trap "rm -r $TD" 0 3 + +echo "using temp directory $TD" + +case "$TESTS" in +*%consistency%*) +# test if addresses are sorted alphabetically: +$ECHO "testing if address array is sorted...\c" +TF="$TD/socat-q" +IFS="$($ECHO ' \n\t')" +$SOCAT -? |sed '1,/address-head:/ d' |egrep 'groups=' |while IFS="$IFS:" read x y; do echo "$x"; done >"$TF" +$SOCAT -? |sed '1,/address-head:/ d' |egrep 'groups=' |while IFS="$IFS:" read x y; do echo "$x"; done |LC_ALL=C sort |diff "$TF" - >"$TF-diff" +if [ -s "$TF-diff" ]; then + $ECHO "\n*** address array is not sorted. Wrong entries:" >&2 + cat "$TD/socat-q-diff" >&2 +else + echo " ok" +fi +#/bin/rm "$TF" +#/bin/rm "$TF-diff" +esac + +case "$TESTS" in +*%consistency%*) +# test if address options array ("optionnames") is sorted alphabetically: +$ECHO "testing if address options are sorted...\c" +TF="$TD/socat-qq" +$SOCAT -??? |sed '1,/opt:/ d' |egrep 'groups=' |awk '{print($1);}' >"$TF" +$SOCAT -??? |sed '1,/opt:/ d' |egrep 'groups=' |awk '{print($1);}' |LC_ALL=C sort |diff "$TF" - >"$TF-diff" +if [ -s "$TF-diff" ]; then + $ECHO "\n*** option array is not sorted. Wrong entries:" >&2 + cat "$TD/socat-qq-diff" >&2 +else + echo " ok" +fi +/bin/rm "$TF" +/bin/rm "$TF-diff" +esac + +#============================================================================== +case "$TESTS" in +*%options%*) + +# inquire which options are available +OPTS_ANY=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*ANY' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_BLK=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*BLK' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_CHILD=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*CHILD' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_CHR=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*CHR' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_DEVICE=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*DEVICE' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_EXEC=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*EXEC' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_FD=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*FD' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_FIFO=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*FIFO' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_FORK=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*FORK' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_LISTEN=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*LISTEN' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_NAMED=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*NAMED' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_OPEN=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*OPEN[^S]' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_PARENT=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*PARENT' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_READLINE=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*READLINE' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_RETRY=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*RETRY' |awk '{print($1);}' |grep -v forever|xargs echo |tr ' ' ',') +OPTS_RANGE=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*RANGE' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_FILE=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*REG' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_UNIX=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*UNIX' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_SOCKET=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*SOCKET' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_TERMIOS=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*TERMIOS' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_IP4=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*IP4' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_IP6=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*IP6' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_TCP=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*TCP' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_UDP=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*UDP' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_SOCKS4=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*SOCKS4' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_PROCESS=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*PROCESS' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_OPENSSL=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*OPENSSL' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_PTY=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*PTY' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_HTTP=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*HTTP' |awk '{print($1);}' |xargs echo |tr ' ' ',') +OPTS_APPL=$($SOCAT -?? |sed '1,/opt:/ d' |egrep 'groups=([A-Z]+,)*APPL' |awk '{print($1);}' |xargs echo |tr ' ' ',') + +# find user ids to setown to; non-root only can setown to itself +if [ $(id -u) = 0 ]; then + # up to now, it is not a big problem when these do not exist + _UID=nobody + _GID=staff +else + _UID=$(id -u) + _GID=$(id -g) +fi + +# some options require values; here we try to replace these bare options with +# valid forms. +filloptionvalues() { + local OPTS=",$1," + # + case "$OPTS" in + *,umask,*) OPTS=$(echo "$OPTS" |sed "s/,umask,/,umask=0026,/g");; + esac + case "$OPTS" in + *,user,*) OPTS=$(echo "$OPTS" |sed "s/,user,/,user=$_UID,/g");; + esac + case "$OPTS" in + *,user-early,*) OPTS=$(echo "$OPTS" |sed "s/,user-early,/,user-early=$_UID,/g");; + esac + case "$OPTS" in + *,user-late,*) OPTS=$(echo "$OPTS" |sed "s/,user-late,/,user-late=$_UID,/g");; + esac + case "$OPTS" in + *,owner,*) OPTS=$(echo "$OPTS" |sed "s/,owner,/,owner=$_UID,/g");; + esac + case "$OPTS" in + *,uid,*) OPTS=$(echo "$OPTS" |sed "s/,uid,/,uid=$_UID,/g");; + esac + case "$OPTS" in + *,uid-l,*) OPTS=$(echo "$OPTS" |sed "s/,uid-l,/,uid-l=$_UID,/g");; + esac + case "$OPTS" in + *,setuid,*) OPTS=$(echo "$OPTS" |sed "s/,setuid,/,setuid=$_UID,/g");; + esac + case "$OPTS" in + *,group,*) OPTS=$(echo "$OPTS" |sed "s/,group,/,group=$_GID,/g");; + esac + case "$OPTS" in + *,group-early,*) OPTS=$(echo "$OPTS" |sed "s/,group-early,/,group-early=$_GID,/g");; + esac + case "$OPTS" in + *,group-late,*) OPTS=$(echo "$OPTS" |sed "s/,group-late,/,group-late=$_GID,/g");; + esac + case "$OPTS" in + *,gid,*) OPTS=$(echo "$OPTS" |sed "s/,gid,/,gid=$_GID,/g");; + esac + case "$OPTS" in + *,gid-l,*) OPTS=$(echo "$OPTS" |sed "s/,gid-l,/,gid-l=$_GID,/g");; + esac + case "$OPTS" in + *,setgid,*) OPTS=$(echo "$OPTS" |sed "s/,setgid,/,setgid=$_GID,/g");; + esac + case "$OPTS" in + *,mode,*) OPTS=$(echo "$OPTS" |sed "s/,mode,/,mode=0700,/g");; + esac + case "$OPTS" in + *,perm,*) OPTS=$(echo "$OPTS" |sed "s/,perm,/,perm=0700,/g");; + esac + case "$OPTS" in + *,perm-early,*) OPTS=$(echo "$OPTS" |sed "s/,perm-early,/,perm-early=0700,/g");; + esac + case "$OPTS" in + *,perm-late,*) OPTS=$(echo "$OPTS" |sed "s/,perm-late,/,perm-late=0700,/g");; + esac + case "$OPTS" in + *,path,*) OPTS=$(echo "$OPTS" |sed "s/,path,/,path=.,/g");; + esac + # SOCKET + case "$OPTS" in + *,bind,*) OPTS=$(echo "$OPTS" |sed "s/,bind,/,bind=:,/g");; + esac + case "$OPTS" in + *,linger,*) OPTS=$(echo "$OPTS" |sed "s/,linger,/,linger=2,/g");; + esac + case "$OPTS" in + *,rcvtimeo,*) OPTS=$(echo "$OPTS" |sed "s/,rcvtimeo,/,rcvtimeo=1,/g");; + esac + case "$OPTS" in + *,sndtimeo,*) OPTS=$(echo "$OPTS" |sed "s/,sndtimeo,/,sndtimeo=1,/g");; + esac + case "$OPTS" in + *,connect-timeout,*) OPTS=$(echo "$OPTS" |sed "s/,connect-timeout,/,connect-timeout=1,/g");; + esac + # IP + case "$OPTS" in + *,ipoptions,*) OPTS=$(echo "$OPTS" |sed "s|,ipoptions,|,ipoptions=x01,|g");; + esac + case "$OPTS" in + *,pf,*) OPTS=$(echo "$OPTS" |sed "s|,pf,|,pf=ip4,|g");; + esac + case "$OPTS" in + *,range,*) OPTS=$(echo "$OPTS" |sed "s|,range,|,range=127.0.0.1/32,|g");; + esac + case "$OPTS" in + *,if,*) OPTS=$(echo "$OPTS" |sed "s/,if,/,if=$INTERFACE,/g");; + esac + # PTY + case "$OPTS" in + *,pty-intervall,*) OPTS=$(echo "$OPTS" |sed "s/,pty-intervall,/,pty-intervall=$INTERFACE,/g");; + esac + # RETRY + case "$OPTS" in + *,intervall,*) OPTS=$(echo "$OPTS" |sed "s/,intervall,/,intervall=1,/g");; + esac + # READLINE + case "$OPTS" in + *,history,*) OPTS=$(echo "$OPTS" |sed "s/,history,/,history=.history,/g");; + esac + case "$OPTS" in + *,noecho,*) OPTS=$(echo "$OPTS" |sed "s/,noecho,/,noecho=password,/g");; + esac + case "$OPTS" in + *,prompt,*) OPTS=$(echo "$OPTS" |sed "s/,prompt,/,prompt=CMD,/g");; + esac + # IPAPP + case "$OPTS" in + *,sp,*) OPTS=$(echo "$OPTS" |sed "s/,sp,/,sp=$SOURCEPORT,/g");; + esac + # OPENSSL + case "$OPTS" in + *,ciphers,*) OPTS=$(echo "$OPTS" |sed "s/,ciphers,/,ciphers=NULL,/g");; + esac + case "$OPTS" in + *,method,*) OPTS=$(echo "$OPTS" |sed "s/,method,/,method=SSLv3,/g");; + esac + case "$OPTS" in + *,cafile,*) OPTS=$(echo "$OPTS" |sed "s/,cafile,/,cafile=/tmp/hugo,/g");; + esac + case "$OPTS" in + *,capath,*) OPTS=$(echo "$OPTS" |sed "s/,capath,/,capath=/tmp/hugo,/g");; + esac + case "$OPTS" in + *,cert,*) OPTS=$(echo "$OPTS" |sed "s/,cert,/,cert=/tmp/hugo,/g");; + esac + case "$OPTS" in + *,key,*) OPTS=$(echo "$OPTS" |sed "s/,key,/,key=/tmp/hugo,/g");; + esac + case "$OPTS" in + *,dh,*) OPTS=$(echo "$OPTS" |sed "s/,dh,/,dh=/tmp/hugo,/g");; + esac + case "$OPTS" in + *,egd,*) OPTS=$(echo "$OPTS" |sed "s/,egd,/,egd=/tmp/hugo,/g");; + esac + # PROXY + case "$OPTS" in + *,proxyauth,*) OPTS=$(echo "$OPTS" |sed "s/,proxyauth,/,proxyauth=user:pass,/g");; + esac + case "$OPTS" in + *,proxyport,*) OPTS=$(echo "$OPTS" |sed "s/,proxyport,/,proxyport=3128,/g");; + esac + case "$OPTS" in + *,link,*) OPTS=$(echo "$OPTS" |sed "s/,link,/,link=testlink,/g");; + esac + # TCP-WRAPPERS + case "$OPTS" in + *,allow-table,*) OPTS=$(echo "$OPTS" |sed "s|,allow-table,|,allow-table=/tmp/hugo,|g");; + esac + case "$OPTS" in + *,deny-table,*) OPTS=$(echo "$OPTS" |sed "s|,deny-table,|,deny-table=/tmp/hugo,|g");; + esac + case "$OPTS" in + *,tcpwrap-dir,*) OPTS=$(echo "$OPTS" |sed "s|,tcpwrap-dir,|,tcpwrap-dir=/tmp,|g");; + esac + echo $OPTS >&2 + expr "$OPTS" : ',\(.*\),' +} +# OPTS_FIFO: nothing yet + +# OPTS_CHR: nothing yet + +# OPTS_BLK: nothing yet + +# OPTS_REG: nothing yet + +OPTS_SOCKET=",$OPTS_SOCKET," +OPTS_SOCKET=$(expr "$OPTS_SOCKET" : ',\(.*\),') + +N=1 +#------------------------------------------------------------------------------ + +#method=open +#METHOD=$(echo "$method" |tr a-z A-Z) +#TEST="$METHOD on file accepts all its options" +# echo "### $TEST" +#TF=$TD/file$N +#DA="$(date)" +#OPTGROUPS=$($SOCAT -? |fgrep " $method:" |sed 's/.*=//') +#for g in $(echo $OPTGROUPS |tr ',' ' '); do +# eval "OPTG=\$OPTS_$(echo $g |tr a-z- A-Z_)"; +# OPTS="$OPTS,$OPTG"; +#done +##echo $OPTS +# +#for o in $(filloptionvalues $OPTS|tr ',' ' '); do +# echo testing if $METHOD accepts option $o +# touch $TF +# $SOCAT $opts -!!$method:$TF,$o /dev/null,ignoreof &2 & + pid=$! + sleep 1 + #waittcp4port $PORT + for o in $(filloptionvalues $OPTS|tr ',' ' '); do + echo "testing if $ADDR accepts option $o" +# echo $SOCAT $opts /dev/null $addr:$LOCALHOST:$PORT,$o + $SOCAT $opts /dev/null $addr:$LOCALHOST:$PORT,$o + done + kill $pid +done +kill $pid 2>/dev/null +opts= + PORT=$((PORT+1)) +fi + +#------------------------------------------------------------------------------ + +# test proxy connect + +#set -vx +if true; then +#if false; then +#opts="-s -d -d -d -d" +pid=$! +for addr in proxy; do + ADDR=$(echo "$addr" |tr a-z A-Z) + TEST="$ADDR accepts all its options" + echo "### $TEST" + OPTGROUPS=$($SOCAT -? |fgrep " $addr:" |sed 's/.*=//') +# echo OPTGROUPS=$OPTGROUPS + OPTS= + for g in $(echo $OPTGROUPS |tr ',' ' '); do + eval "OPTG=\$OPTS_$(echo $g |tr a-z A-Z)"; + OPTS="$OPTS,$OPTG"; + done + echo $OPTS + # prepare dummy server + $SOCAT tcp-l:$PORT,reuseaddr,crlf exec:"/bin/bash proxyecho.sh" || echo "cannot start proxyecho.sh" >&2 & + pid=$! + sleep 1 + for o in $(filloptionvalues $OPTS|tr ',' ' '); do + echo "testing if $ADDR accepts option $o" +# echo $SOCAT $opts /dev/null $addr:$LOCALHOST:127.0.0.1:$PORT,$o + $SOCAT $opts /dev/null $addr:$LOCALHOST:127.0.0.1:$((PORT+1)),proxyport=$PORT,$o + done + kill $pid 2>/dev/null +done +kill $pid 2>/dev/null +opts= +PORT=$((PORT+2)) +fi + +#------------------------------------------------------------------------------ + +# test tcp4 + +#set -vx +if true; then +#if false; then +#opts="-s -d -d -d -d" +$SOCAT $opts tcp4-listen:$PORT,reuseaddr,fork,$o echo /dev/null +opts= +PORT=$((PORT+1)) +fi + +#------------------------------------------------------------------------------ + +# test udp4-connect + +#set -vx +if true; then +#if false; then +#opts="-s -d -d -d -d" +$SOCAT $opts udp4-listen:$PORT,fork,$o echo /dev/null +opts= +PORT=$((PORT+1)) +fi + +#------------------------------------------------------------------------------ + +# test tcp4-listen + +#set -vx +if true; then +#if false; then +#opts="-s -d -d -d -d" +for addr in tcp4-listen; do + ADDR=$(echo "$addr" |tr a-z A-Z) + TEST="$ADDR accepts all its options" + echo "### $TEST" + OPTGROUPS=$($SOCAT -? |fgrep " $addr:" |sed 's/.*=//') + OPTS= + for g in $(echo $OPTGROUPS |tr ',' ' '); do + eval "OPTG=\$OPTS_$(echo $g |tr a-z A-Z)"; + OPTS="$OPTS,$OPTG"; + done + echo $OPTS + for o in $(filloptionvalues $OPTS|tr ',' ' '); do + echo "testing if $ADDR accepts option $o" + $SOCAT $opts $ADDR:$PORT,reuseaddr,$o echo /dev/null + kill $pid 2>/dev/null + done +done +opts= +PORT=$((PORT+1)) +fi + +#------------------------------------------------------------------------------ + +# test udp4-listen + +#set -vx +if true; then +#if false; then +#opts="-s -d -d -d -d" +for addr in udp4-listen; do + ADDR=$(echo "$addr" |tr a-z A-Z) + TEST="$ADDR accepts all its options" + echo "### $TEST" + OPTGROUPS=$($SOCAT -? |fgrep " $addr:" |sed 's/.*=//') + OPTS= + for g in $(echo $OPTGROUPS |tr ',' ' '); do + eval "OPTG=\$OPTS_$(echo $g |tr a-z A-Z)"; + OPTS="$OPTS,$OPTG"; + done + echo $OPTS + for o in $(filloptionvalues $OPTS|tr ',' ' '); do + echo "testing if $ADDR accepts option $o" + $SOCAT $opts $ADDR:$PORT,reuseaddr,$o echo /dev/null + kill $pid 2>/dev/null + done +done +opts= +PORT=$((PORT+1)) +fi + +#------------------------------------------------------------------------------ + +# test udp4-sendto + +#set -vx +if true; then +#if false; then +#opts="-s -d -d -d -d" +$SOCAT $opts udp4-recv:$PORT,fork,$o echo /dev/null +opts= +PORT=$((PORT+1)) +fi + +#------------------------------------------------------------------------------ + +# test udp4-datagram + +#set -vx +if true; then +#if false; then +#opts="-s -d -d -d -d" +#$SOCAT $opts udp4-recvfrom:$PORT,fork,$o echo /dev/null +opts= +PORT=$((PORT+1)) +fi + +#------------------------------------------------------------------------------ + +# test udp4-recv + +#set -vx +if true; then +#if false; then +#opts="-s -d -d -d -d" +for addr in udp4-recv; do + ADDR=$(echo "$addr" |tr a-z A-Z) + TEST="$ADDR accepts all its options" + echo "### $TEST" + OPTGROUPS=$($SOCAT -? |fgrep " $addr:" |sed 's/.*=//') + OPTS= + for g in $(echo $OPTGROUPS |tr ',' ' '); do + eval "OPTG=\$OPTS_$(echo $g |tr a-z A-Z)"; + OPTS="$OPTS,$OPTG"; + done + echo $OPTS + for o in $(filloptionvalues $OPTS|tr ',' ' '); do + echo "testing if $ADDR accepts option $o" + $SOCAT $opts $ADDR:$PORT,reuseaddr,$o echo /dev/null + kill $pid 2>/dev/null + done +done +opts= +PORT=$((PORT+1)) +fi + +#------------------------------------------------------------------------------ + +# test udp4-recvfrom + +#set -vx +if true; then +#if false; then +#opts="-s -d -d -d -d" +for addr in udp4-recvfrom; do + ADDR=$(echo "$addr" |tr a-z A-Z) + TEST="$ADDR accepts all its options" + echo "### $TEST" + OPTGROUPS=$($SOCAT -? |fgrep " $addr:" |sed 's/.*=//') + OPTS= + for g in $(echo $OPTGROUPS |tr ',' ' '); do + eval "OPTG=\$OPTS_$(echo $g |tr a-z A-Z)"; + OPTS="$OPTS,$OPTG"; + done + echo $OPTS + for o in $(filloptionvalues $OPTS|tr ',' ' '); do + echo "testing if $ADDR accepts option $o" + $SOCAT $opts $ADDR:$PORT,reuseaddr,$o echo /dev/null + kill $pid 2>/dev/null + done +done +opts= +PORT=$((PORT+1)) +fi + +#------------------------------------------------------------------------------ + +# test ip4-sendto + +#set -vx +if true; then +#if false; then +#opts="-s -d -d -d -d" +$SOCAT $opts ip4-recv:$PORT,fork,$o echo /dev/null +opts= +PORT=$((PORT+1)) +fi + +#------------------------------------------------------------------------------ + +# test ip4-recv + +#set -vx +if true; then +#if false; then +#opts="-s -d -d -d -d" +for addr in ip4-recv; do + ADDR=$(echo "$addr" |tr a-z A-Z) + TEST="$ADDR accepts all its options" + echo "### $TEST" + OPTGROUPS=$($SOCAT -? |fgrep " $addr:" |sed 's/.*=//') + OPTS= + for g in $(echo $OPTGROUPS |tr ',' ' '); do + eval "OPTG=\$OPTS_$(echo $g |tr a-z A-Z)"; + OPTS="$OPTS,$OPTG"; + done + echo $OPTS + for o in $(filloptionvalues $OPTS|tr ',' ' '); do + echo "testing if $ADDR accepts option $o" + $SOCAT $opts $ADDR:$PORT,reuseaddr,$o echo /dev/null + kill $pid 2>/dev/null + done +done +opts= +PORT=$((PORT+1)) +fi + +#------------------------------------------------------------------------------ + +# test ip4-recvfrom + +#set -vx +if true; then +#if false; then +#opts="-s -d -d -d -d" +for addr in ip4-recvfrom; do + ADDR=$(echo "$addr" |tr a-z A-Z) + TEST="$ADDR accepts all its options" + echo "### $TEST" + OPTGROUPS=$($SOCAT -? |fgrep " $addr:" |sed 's/.*=//') + OPTS= + for g in $(echo $OPTGROUPS |tr ',' ' '); do + eval "OPTG=\$OPTS_$(echo $g |tr a-z A-Z)"; + OPTS="$OPTS,$OPTG"; + done + echo $OPTS + for o in $(filloptionvalues $OPTS|tr ',' ' '); do + echo "testing if $ADDR accepts option $o" + $SOCAT $opts $ADDR:$PORT,reuseaddr,$o echo /dev/null + kill $pid 2>/dev/null + done +done +opts= +PORT=$((PORT+1)) +fi + +#------------------------------------------------------------------------------ + +# test READLINE + +if true; then +#if false; then +#opts="-s -d -d -d -d" +for addr in readline; do + ADDR=$(echo "$addr" |tr a-z A-Z) + TEST="$ADDR accepts all its options" + echo "### $TEST" + TS=$TD/script$N + OPTGROUPS=$($SOCAT -? |fgrep " $addr " |sed 's/.*=//') + OPTS= + for g in $(echo $OPTGROUPS |tr ',' ' '); do + eval "OPTG=\$OPTS_$(echo $g |tr a-z A-Z)"; + OPTS="$OPTS,$OPTG"; + done + #echo $OPTS + for o in $(filloptionvalues $OPTS|tr ',' ' '); do +# for o in bs0; do + echo "testing if $ADDR accepts option $o" + echo "$SOCAT $opts readline,$o /dev/null" >$TS + chmod u+x $TS + $SOCAT /dev/null,ignoreeof exec:$TS,pty + #stty sane + done + #reset 1>&0 2>&0 +done +opts= +fi + +#------------------------------------------------------------------------------ + +# unnamed pipe +#if false; then +if true; then +for addr in pipe; do + ADDR=$(echo "$addr" |tr a-z A-Z) + TEST="unnamed $ADDR accepts all its options" + echo "### $TEST" + OPTGROUPS=$($SOCAT -? |egrep " $addr[^:]" |sed 's/.*=//') + OPTS= + for g in $(echo $OPTGROUPS |tr ',' ' '); do + eval "OPTG=\$OPTS_$(echo $g |tr a-z A-Z)"; + OPTS="$OPTS,$OPTG"; + done + #echo $OPTS + + for o in $(filloptionvalues $OPTS|tr ',' ' '); do + echo testing if unnamed $ADDR accepts option $o + $SOCAT $opts $addr,$o /dev/null $TF + done +done +fi + +#------------------------------------------------------------------------------ + +# test OPEN address + +#! test it on pipe, device, new file + +N=1 +#if false; then +if true; then +for addr in open; do + ADDR=$(echo "$addr" |tr a-z A-Z) + TEST="$ADDR on file accepts all its options" + echo "### $TEST" + TF=$TD/file$N + OPTGROUPS=$($SOCAT -? |fgrep " $addr:" |sed 's/.*=//') + OPTS= + for g in $(echo $OPTGROUPS |tr ',' ' '); do + eval "OPTG=\$OPTS_$(echo $g |tr a-z A-Z)"; + OPTS="$OPTS,$OPTG"; + done + #echo $OPTS + for o in $(filloptionvalues $OPTS|tr ',' ' '); do + echo testing if $ADDR on file accepts option $o + touch $TF + $SOCAT $opts -!!$addr:$TF,$o /dev/null,ignoreof /dev/null + rm -f $TF + done + + if [ $(id -u) -eq 0 ]; then + TEST="$ADDR on existing device accepts all its options" + echo "### $TEST" + TF=$TD/null + OPTGROUPS=$($SOCAT -? |fgrep " $addr:" |sed 's/.*=//') + OPTGROUPS=$(echo $OPTGROUPS |sed -e 's/,REG,/,/g' -e 's/,OPEN,/,/g') + OPTS= + for g in $(echo $OPTGROUPS |tr ',' ' '); do + eval "OPTG=\$OPTS_$(echo $g |tr a-z A-Z)"; + OPTS="$OPTS,$OPTG"; + done + #echo $OPTS + for o in $(filloptionvalues $OPTS|tr ',' ' '); do + echo testing if $ADDR on existing device accepts option $o + rm -f $TF; mknod $TF c 1 3 + $SOCAT $opts -!!$addr:$TF,$o /dev/null,ignoreof "$tf" 2>"$te" +#set -vx + (echo "$da"; sleep $T) |$SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te" & + export rc1=$! + #sleep 5 && kill $rc1 2>/dev/null & +# rc2=$! + wait $rc1 +# kill $rc2 2>/dev/null +#set +vx + if [ "$?" != 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$SOCAT $opts $arg1 $arg2" + cat "$te" + numFAIL=$((numFAIL+1)) + elif echo "$da" |diff - "$tf" >"$tdiff" 2>&1; then + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) + else + $PRINTF "$FAILED:\n" + echo "$SOCAT $opts $arg1 $arg2" + cat "$te" + echo diff: + cat "$tdiff" + numFAIL=$((numFAIL+1)) + fi +} + +# test if call to od and throughput of data works - with graceful shutdown and +# flush of od buffers +testod () { + local num="$1" + local title="$2" + local arg1="$3"; [ -z "$arg1" ] && arg1="-" + local arg2="$4"; [ -z "$arg2" ] && arg2="echo" + local opts="$5" + local T="$6"; [ -z "$T" ] && T=0 + local tf="$td/test$N.stdout" + local te="$td/test$N.stderr" + local tdiff="$td/test$N.diff" + local dain="$(date)" + local daout="$(echo "$dain" |od -c)" + $PRINTF "test $F_n %s... " $num "$title" + (echo "$dain"; sleep $T) |$SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te" + if [ "$?" != 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$SOCAT $opts $arg1 $arg2" + cat "$te" + numFAIL=$((numFAIL+1)) + elif echo "$daout" |diff - "$tf" >"$tdiff" 2>&1; then + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) + else + $PRINTF "$FAILED: diff:\n" + echo "$SOCAT $opts $arg1 $arg2" + cat "$te" + cat "$tdiff" + numFAIL=$((numFAIL+1)) + fi +} + +# test if the socat executable has these address types compiled in +# print the first missing address type +testaddrs () { + local a A; + for a in $@; do + A=$(echo "$a" |tr 'a-z-' 'A-Z_') + if $SOCAT -V |grep "#define WITH_$A 1\$" >/dev/null; then + shift + continue + fi + echo "$a" + return 1 + done + return 0 +} + +# test if the socat executable has these options compiled in +# print the first missing option +testoptions () { + local a A; + for a in $@; do + A=$(echo "$a" |tr 'a-z' 'A-Z') + if $SOCAT -??? |grep "[^a-z0-9-]$a[^a-z0-9-]" >/dev/null; then + shift + continue + fi + echo "$a" + return 1 + done + return 0 +} + +unset HAVENOT_IP4 +# check if an IP4 loopback interface exists +runsip4 () { + [ -n "$HAVENOT_IP4" ] && return $HAVENOT_IP4 + local l + case "$UNAME" in + AIX) l=$($IFCONFIG lo0 |fgrep 'inet 127.0.0.1 ') ;; + FreeBSD) l=$($IFCONFIG lo0 |fgrep 'inet 127.0.0.1 ') ;; + HP-UX) l=$($IFCONFIG lo0 |fgrep 'inet 127.0.0.1 ') ;; + Linux) l=$($IFCONFIG |fgrep 'inet addr:127.0.0.1 ') ;; + NetBSD)l=$($IFCONFIG -a |fgrep 'inet 127.0.0.1 ');; + OpenBSD)l=$($IFCONFIG -a |fgrep 'inet 127.0.0.1 ');; + OSF1) l=$($IFCONFIG -a |grep ' inet ') ;; + SunOS) l=$($IFCONFIG -a |grep 'inet ') ;; +# *) l=$($IFCONFIG -a |grep ' ::1[^:0-9A-Fa-f]') ;; + esac + [ -z "$l" ] && return 1 + # existence of interface might not suffice, check for routeability: + case "$UNAME" in + Darwin) ping -c 1 127.0.0.1; l="$?" ;; + Linux) ping -c 1 127.0.0.1; l="$?" ;; + *) if [ -n "$l" ]; then l=0; else l=1; fi ;; + esac + HAVENOT_IP4=$l + return $l; +} + +unset HAVENOT_IP6 +# check if an IP6 loopback interface exists +runsip6 () { + [ -n "$HAVENOT_IP6" ] && return $HAVENOT_IP6 + local l + case "$UNAME" in + AIX) l=$(/usr/sbin/ifconfig lo0 |grep 'inet6 ::1/0') ;; + HP-UX) l=$(/usr/sbin/ifconfig lo0 |grep ' inet6 ') ;; + Linux) l=$(/sbin/ifconfig |grep 'inet6 addr: ::1/') ;; + NetBSD)l=$(/sbin/ifconfig -a |grep 'inet6 ::1 ');; + OSF1) l=$(/sbin/ifconfig -a |grep ' inet6 ') ;; + SunOS) l=$(/sbin/ifconfig -a |grep 'inet6 ') ;; + *) l=$(/sbin/ifconfig -a |grep ' ::1[^:0-9A-Fa-f]') ;; + esac + [ -z "$l" ] && return 1 + # existence of interface might not suffice, check for routeability: + case "$UNAME" in + Darwin) ping -c 1 ::1; l="$?" ;; + Linux) ping6 -c 1 ::1; l="$?" ;; + *) if [ -n "$l" ]; then l=0; else l=1; fi ;; + esac + HAVENOT_IP6=$l + return $l; +} + +# wait until an IP4 protocol is ready +waitip4proto () { + local proto="$1" + local logic="$2" # 0..wait until free; 1..wait until listening + local timeout="$3" + local l + [ "$logic" ] || logic=1 + [ "$timeout" ] || timeout=5 + while [ $timeout -gt 0 ]; do + case "$UNAME" in + Linux) l=$(netstat -n -w -l |grep '^raw .* .*[0-9*]:'$proto' [ ]*0\.0\.0\.0:\*') ;; +# FreeBSD) l=$(netstat -an |grep '^raw4[6 ] .*[0-9*]\.'$proto' .* \*\.\*') ;; +# NetBSD) l=$(netstat -an |grep '^raw .*[0-9*]\.'$proto' [ ]* \*\.\*') ;; +# OpenBSD) l=$(netstat -an |grep '^raw .*[0-9*]\.'$proto' [ ]* \*\.\*') ;; +# Darwin) case "$(uname -r)" in +# [1-5]*) l=$(netstat -an |grep '^raw.* .*[0-9*]\.'$proto' .* \*\.\*') ;; +# *) l=$(netstat -an |grep '^raw4.* .*[0-9*]\.'$proto' .* \*\.\* .*') ;; +# esac ;; + AIX) # does not seem to show raw sockets in netstat + sleep 1; return 0 ;; +# SunOS) l=$(netstat -an -f inet -P raw |grep '.*[1-9*]\.'$proto' [ ]*Idle') ;; +# HP-UX) l=$(netstat -an |grep '^raw 0 0 .*[0-9*]\.'$proto' .* \*\.\* ') ;; +# OSF1) l=$(/usr/sbin/netstat -an |grep '^raw 0 0 .*[0-9*]\.'$proto' [ ]*\*\.\*') ;; + *) #l=$(netstat -an |grep -i 'raw .*[0-9*][:.]'$proto' ') ;; + sleep 1; return 0 ;; + esac + [ \( \( $logic -ne 0 \) -a -n "$l" \) -o \ + \( \( $logic -eq 0 \) -a -z "$l" \) ] && return 0 + sleep 1 + timeout=$((timeout-1)) + done + + $ECHO "!protocol $proto timed out! \c" >&2 + return 1 +} + +# we need this misleading function name for canonical reasons +waitip4port () { + waitip4proto "$1" "$2" "$3" +} + +# wait until an IP6 protocol is ready +waitip6proto () { + local proto="$1" + local logic="$2" # 0..wait until free; 1..wait until listening + local timeout="$3" + local l + [ "$logic" ] || logic=1 + [ "$timeout" ] || timeout=5 + while [ $timeout -gt 0 ]; do + case "$UNAME" in + Linux) l=$(netstat -n -w -l |grep '^raw .* .*:[0-9*]*:'$proto' [ ]*:::\*') ;; +# FreeBSD) l=$(netstat -an |grep '^raw4[6 ] .*[0-9*]\.'$proto' .* \*\.\*') ;; +# NetBSD) l=$(netstat -an |grep '^raw .*[0-9*]\.'$proto' [ ]* \*\.\*') ;; +# OpenBSD) l=$(netstat -an |grep '^raw .*[0-9*]\.'$proto' [ ]* \*\.\*') ;; +# Darwin) case "$(uname -r)" in +# [1-5]*) l=$(netstat -an |grep '^raw.* .*[0-9*]\.'$proto' .* \*\.\*') ;; +# *) l=$(netstat -an |grep '^raw4.* .*[0-9*]\.'$proto' .* \*\.\* .*') ;; +# esac ;; + AIX) # does not seem to show raw sockets in netstat + sleep 1; return 0 ;; +# SunOS) l=$(netstat -an -f inet -P raw |grep '.*[1-9*]\.'$proto' [ ]*Idle') ;; +# HP-UX) l=$(netstat -an |grep '^raw 0 0 .*[0-9*]\.'$proto' .* \*\.\* ') ;; +# OSF1) l=$(/usr/sbin/netstat -an |grep '^raw 0 0 .*[0-9*]\.'$proto' [ ]*\*\.\*') ;; + *) #l=$(netstat -an |grep -i 'raw .*[0-9*][:.]'$proto' ') ;; + sleep 1; return 0 ;; + esac + [ \( \( $logic -ne 0 \) -a -n "$l" \) -o \ + \( \( $logic -eq 0 \) -a -z "$l" \) ] && return 0 + sleep 1 + timeout=$((timeout-1)) + done + + $ECHO "!protocol $proto timed out! \c" >&2 + return 1 +} + +# we need this misleading function name for canonical reasons +waitip6port () { + waitip6proto "$1" "$2" "$3" +} + +# wait until a TCP4 listen port is ready +waittcp4port () { + local port="$1" + local logic="$2" # 0..wait until free; 1..wait until listening + local timeout="$3" + local l + [ "$logic" ] || logic=1 + [ "$timeout" ] || timeout=5 + while [ $timeout -gt 0 ]; do + case "$UNAME" in + Linux) l=$(netstat -n -t -l |grep '^tcp .* .*[0-9*]:'$port' .* LISTEN') ;; + FreeBSD) l=$(netstat -an |grep '^tcp4.* .*[0-9*]\.'$port' .* \*\.\* .* LISTEN') ;; + NetBSD) l=$(netstat -an |grep '^tcp .* .*[0-9*]\.'$port' [ ]* \*\.\* [ ]* LISTEN.*') ;; + Darwin) case "$(uname -r)" in + [1-5]*) l=$(netstat -an |grep '^tcp.* .*[0-9*]\.'$port' .* \*\.\* .* LISTEN') ;; + *) l=$(netstat -an |grep '^tcp4.* .*[0-9*]\.'$port' .* \*\.\* .* LISTEN') ;; + esac ;; + AIX) l=$(netstat -an |grep '^tcp[^6] 0 0 .*[*0-9]\.'$port' .* LISTEN$') ;; + SunOS) l=$(netstat -an -f inet -P tcp |grep '.*[1-9*]\.'$port' .*\* 0 .* LISTEN') ;; + HP-UX) l=$(netstat -an |grep '^tcp 0 0 .*[0-9*]\.'$port' .* LISTEN$') ;; + OSF1) l=$(/usr/sbin/netstat -an |grep '^tcp 0 0 .*[0-9*]\.'$port' [ ]*\*\.\* [ ]*LISTEN') ;; + CYGWIN*) l=$(netstat -an -p TCP |grep '^ TCP [0-9.]*:'$port' .* LISTENING') ;; + *) l=$(netstat -an |grep -i 'tcp .*[0-9*][:.]'$port' .* listen') ;; + esac + [ \( \( $logic -ne 0 \) -a -n "$l" \) -o \ + \( \( $logic -eq 0 \) -a -z "$l" \) ] && return 0 + sleep 1 + timeout=$((timeout-1)) + done + + $ECHO "!port $port timed out! \c" >&2 + return 1 +} + +# wait until a UDP4 port is ready +waitudp4port () { + local port="$1" + local logic="$2" # 0..wait until free; 1..wait until listening + local timeout="$3" + local l + [ "$logic" ] || logic=1 + [ "$timeout" ] || timeout=5 + while [ $timeout -gt 0 ]; do + case "$UNAME" in + Linux) l=$(netstat -n -u -l |grep '^udp .* .*[0-9*]:'$port' [ ]*0\.0\.0\.0:\*') ;; + FreeBSD) l=$(netstat -an |grep '^udp4[6 ] .*[0-9*]\.'$port' .* \*\.\*') ;; + NetBSD) l=$(netstat -an |grep '^udp .*[0-9*]\.'$port' [ ]* \*\.\*') ;; + OpenBSD) l=$(netstat -an |grep '^udp .*[0-9*]\.'$port' [ ]* \*\.\*') ;; + Darwin) case "$(uname -r)" in + [1-5]*) l=$(netstat -an |grep '^udp.* .*[0-9*]\.'$port' .* \*\.\*') ;; + *) l=$(netstat -an |grep '^udp4.* .*[0-9*]\.'$port' .* \*\.\* .*') ;; + esac ;; + AIX) l=$(netstat -an |grep '^udp[4 ] 0 0 .*[*0-9]\.'$port' .* \*\.\*[ ]*$') ;; + SunOS) l=$(netstat -an -f inet -P udp |grep '.*[1-9*]\.'$port' [ ]*Idle') ;; + HP-UX) l=$(netstat -an |grep '^udp 0 0 .*[0-9*]\.'$port' .* \*\.\* ') ;; + OSF1) l=$(/usr/sbin/netstat -an |grep '^udp 0 0 .*[0-9*]\.'$port' [ ]*\*\.\*') ;; + *) l=$(netstat -an |grep -i 'udp .*[0-9*][:.]'$port' ') ;; + esac + [ \( \( $logic -ne 0 \) -a -n "$l" \) -o \ + \( \( $logic -eq 0 \) -a -z "$l" \) ] && return 0 + sleep 1 + timeout=$((timeout-1)) + done + + $ECHO "!port $port timed out! \c" >&2 + return 1 +} + +# wait until a tcp6 listen port is ready +waittcp6port () { + local port="$1" + local logic="$2" # 0..wait until free; 1..wait until listening + local timeout="$3" + local l + [ "$logic" ] || logic=1 + [ "$timeout" ] || timeout=5 + while [ $timeout -gt 0 ]; do + case "$UNAME" in + Linux) l=$(netstat -an |grep '^tcp[6 ] .* [0-9a-f:]*:'$port' .* LISTEN') ;; + FreeBSD) l=$(netstat -an |grep -i 'tcp[46][6 ] .*[0-9*][:.]'$port' .* listen') ;; + NetBSD) l=$(netstat -an |grep '^tcp6 .*[0-9*]\.'$port' [ ]* \*\.\*') ;; + OpenBSD) l=$(netstat -an |grep -i 'tcp6 .*[0-9*][:.]'$port' .* listen') ;; + AIX) l=$(netstat -an |grep '^tcp[6 ] 0 0 .*[*0-9]\.'$port' .* LISTEN$') ;; + SunOS) l=$(netstat -an -f inet6 -P tcp |grep '.*[1-9*]\.'$port' .*\* [ ]* 0 .* LISTEN') ;; + #OSF1) l=$(/usr/sbin/netstat -an |grep '^tcp6 0 0 .*[0-9*]\.'$port' [ ]*\*\.\* [ ]*LISTEN') /*?*/;; + *) l=$(netstat -an |grep -i 'tcp6 .*:'$port' .* listen') ;; + esac + [ \( \( $logic -ne 0 \) -a -n "$l" \) -o \ + \( \( $logic -eq 0 \) -a -z "$l" \) ] && return 0 + sleep 1 + timeout=$((timeout-1)) + done + + $ECHO "!port $port timed out! \c" >&2 + return 1 +} + +# wait until a UDP6 port is ready +waitudp6port () { + local port="$1" + local logic="$2" # 0..wait until free; 1..wait until listening + local timeout="$3" + local l + [ "$logic" ] || logic=1 + [ "$timeout" ] || timeout=5 + while [ $timeout -gt 0 ]; do + case "$UNAME" in + Linux) l=$(netstat -an |grep '^udp[6 ] .* .*[0-9*:]:'$port' [ ]*:::\*') ;; + FreeBSD) l=$(netstat -an |egrep '^udp(6|46) .*[0-9*]\.'$port' .* \*\.\*') ;; + NetBSD) l=$(netstat -an |grep '^udp6 .* \*\.'$port' [ ]* \*\.\*') ;; + OpenBSD) l=$(netstat -an |grep '^udp6 .*[0-9*]\.'$port' [ ]* \*\.\*') ;; + #Darwin) l=$(netstat -an |grep '^udp6.* .*[0-9*]\.'$port' .* \*\.\* ') ;; + AIX) l=$(netstat -an |grep '^udp[6 ] 0 0 .*[*0-9]\.'$port' .* \*\.\*[ ]*$') ;; + SunOS) l=$(netstat -an -f inet6 -P udp |grep '.*[1-9*]\.'$port' [ ]*Idle') ;; + #HP-UX) l=$(netstat -an |grep '^udp 0 0 .*[0-9*]\.'$port' ') ;; + #OSF1) l=$(/usr/sbin/netstat -an |grep '^udp6 0 0 .*[0-9*]\.'$port' [ ]*\*\.\*') ;; + *) l=$(netstat -an |grep -i 'udp .*[0-9*][:.]'$port' ') ;; + esac + [ \( \( $logic -ne 0 \) -a -n "$l" \) -o \ + \( \( $logic -eq 0 \) -a -z "$l" \) ] && return 0 + sleep 1 + timeout=$((timeout-1)) + done + + $ECHO "!port $port timed out! \c" >&2 + return 1 +} + +# wait until a filesystem entry exists +waitfile () { + local crit=-e + case "X$1" in X-*) crit="$1"; shift ;; esac + local file="$1" + local logic="$2" # 0..wait until gone; 1..wait until exists (default) + local timeout="$3" + [ "$logic" ] || logic=1 + [ "$timeout" ] || timeout=5 + while [ $timeout -gt 0 ]; do + if [ \( \( $logic -ne 0 \) -a $crit "$file" \) -o \ + \( \( $logic -eq 0 \) -a ! $crit "$file" \) ]; then + return 0 + fi + sleep 1 + timeout=$((timeout-1)) + done + + echo "file $file timed out" >&2 + return 1 +} + +# generate a test certificate and key +gentestcert () { + local name="$1" + if [ -f $name.key -a -f $name.crt -a -f $name.pem ]; then return; fi + openssl genrsa $OPENSSL_RAND -out $name.key 768 >/dev/null 2>&1 + openssl req -new -config testcert.conf -key $name.key -x509 -out $name.crt >/dev/null 2>&1 + cat $name.key $name.crt >$name.pem +} + +# generate a test DSA key and certificate +gentestdsacert () { + local name="$1" + if [ -f $name.key -a -f $name.crt -a -f $name.pem ]; then return; fi + openssl dsaparam -out $name-dsa.pem 512 >/dev/null 2>&1 + openssl dhparam -dsaparam -out $name-dh.pem 512 >/dev/null 2>&1 + openssl req -newkey dsa:$name-dsa.pem -keyout $name.key -nodes -x509 -config testcert.conf -out $name.crt >/dev/null 2>&1 + cat $name-dsa.pem $name-dh.pem $name.key $name.crt >$name.pem +} + + +NAME=UNISTDIO +case "$TESTS " in +*%functions%*|*%stdio%*|*%$NAME%*) +TEST="$NAME: unidirectional throughput from stdin to stdout" +testecho "$N" "$TEST" "stdin" "stdout" "$opts -u" +esac +N=$((N+1)) + + +NAME=UNPIPESTDIO +case "$TESTS" in +*%functions%*|*%stdio%*|*%$NAME%*) +TEST="$NAME: stdio with simple echo via internal pipe" +testecho "$N" "$TEST" "stdio" "pipe" "$opts" +esac +N=$((N+1)) + + +NAME=UNPIPESHORT +case "$TESTS" in +*%functions%*|*%stdio%*|*%$NAME%*) +TEST="$NAME: short form of stdio ('-') with simple echo via internal pipe" +testecho "$N" "$TEST" "-" "pipe" "$opts" +esac +N=$((N+1)) + + +NAME=DUALSTDIO +case "$TESTS" in +*%functions%*|*%stdio%*|*%$NAME%*) +TEST="$NAME: splitted form of stdio ('stdin!!stdout') with simple echo via internal pipe" +testecho "$N" "$TEST" "stdin!!stdout" "pipe" "$opts" +esac +N=$((N+1)) + + +NAME=DUALSHORTSTDIO +case "$TESTS" in +*%functions%*|*%stdio%*|*%$NAME%*) +TEST="$NAME: short splitted form of stdio ('-!!-') with simple echo via internal pipe" +testecho "$N" "$TEST" "-!!-" "pipe" "$opts" +esac +N=$((N+1)) + + +NAME=DUALFDS +case "$TESTS" in +*%functions%*|*%fd%*|*%$NAME%*) +TEST="$NAME: file descriptors with simple echo via internal pipe" +testecho "$N" "$TEST" "0!!1" "pipe" "$opts" +esac +N=$((N+1)) + + +NAME=NAMEDPIPE +case "$TESTS" in +*%functions%*|*%pipe%*|*%$NAME%*) +TEST="$NAME: simple echo via named pipe" +# with MacOS, this test hangs if nonblock is not used. Is an OS bug. +tp="$td/pipe$N" +# note: the nonblock is required by MacOS 10.1(?), otherwise it hangs (OS bug?) +testecho "$N" "$TEST" "" "pipe:$tp,nonblock" "$opts" +esac +N=$((N+1)) + + +NAME=DUALPIPE +case "$TESTS" in +*%functions%*|*%pipe%*|*%$NAME%*) +TEST="$NAME: simple echo via named pipe, specified twice" +tp="$td/pipe$N" +testecho "$N" "$TEST" "" "pipe:$tp,nonblock!!pipe:$tp" "$opts" +esac +N=$((N+1)) + + +NAME=FILE +case "$TESTS" in +*%functions%*|*%file%*|*%ignoreeof%*|*%$NAME%*) +TEST="$NAME: simple echo via file" +tf="$td/file$N" +testecho "$N" "$TEST" "" "$tf,ignoreeof!!$tf" "$opts" +esac +N=$((N+1)) + + +NAME=EXECSOCKET +case "$TESTS" in +*%functions%*|*%exec%*|*%$NAME%*) +TEST="$NAME: simple echo via exec of cat with socketpair" +testecho "$N" "$TEST" "" "exec:$CAT" "$opts" +esac +N=$((N+1)) + + +NAME=SYSTEMSOCKET +case "$TESTS" in +*%functions%*|*%system%*|*%$NAME%*) +TEST="$NAME: simple echo via system() of cat with socketpair" +testecho "$N" "$TEST" "" "system:$CAT" "$opts" +esac +N=$((N+1)) + + +NAME=EXECPIPES +case "$TESTS" in +*%functions%*|*%pipe%*|*%$NAME%*) +TEST="$NAME: simple echo via exec of cat with pipes" +testecho "$N" "$TEST" "" "exec:$CAT,pipes" "$opts" +esac +N=$((N+1)) + + +NAME=SYSTEMPIPES +case "$TESTS" in +*%functions%*|*%pipes%*|*%$NAME%*) +TEST="$NAME: simple echo via system() of cat with pipes" +testecho "$N" "$TEST" "" "system:$CAT,pipes" "$opts" +esac +N=$((N+1)) + + +NAME=EXECPTY +case "$TESTS" in +*%functions%*|*%exec%*|*%pty%*|*%$NAME%*) +TEST="$NAME: simple echo via exec of cat with pseudo terminal" +if ! testaddrs pty >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +testecho "$N" "$TEST" "" "exec:$CAT,pty,$PTYOPTS" "$opts" +fi +esac +N=$((N+1)) + + +NAME=SYSTEMPTY +case "$TESTS" in +*%functions%*|*%system%*|*%pty%*|*%$NAME%*) +TEST="$NAME: simple echo via system() of cat with pseudo terminal" +if ! testaddrs pty >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +testecho "$N" "$TEST" "" "system:$CAT,pty,$PTYOPTS" "$opts" +fi +esac +N=$((N+1)) + + +NAME=SYSTEMPIPESFDS +case "$TESTS" in +*%functions%*|*%system%*|*%$NAME%*) +TEST="$NAME: simple echo via system() of cat with pipes, non stdio" +testecho "$N" "$TEST" "" "system:$CAT>&9 <&8,pipes,fdin=8,fdout=9" "$opts" +esac +N=$((N+1)) + + +NAME=DUALSYSTEMFDS +case "$TESTS" in +*%functions%*|*%system%*|*%$NAME%*) +TEST="$NAME: echo via dual system() of cat" +testecho "$N" "$TEST" "system:$CAT>&6,fdout=6!!system:$CAT<&7,fdin=7" "" "$opts" +esac +N=$((N+1)) + + +NAME=EXECSOCKETFLUSH +case "$TESTS" in +*%functions%*|*%exec%*|*%$NAME%*) +TEST="$NAME: call to od via exec with socketpair" +testod "$N" "$TEST" "" "exec:$OD_C" "$opts" +esac +N=$((N+1)) + + +NAME=SYSTEMSOCKETFLUSH +case "$TESTS" in +*%functions%*|*%system%*|*%$NAME%*) +TEST="$NAME: call to od via system() with socketpair" +testod "$N" "$TEST" "" "system:$OD_C" "$opts" +esac +N=$((N+1)) + + +NAME=EXECPIPESFLUSH +case "$TESTS" in +*%functions%*|*%exec%*|*%$NAME%*) +TEST="$NAME: call to od via exec with pipes" +testod "$N" "$TEST" "" "exec:$OD_C,pipes" "$opts" +esac +N=$((N+1)) + + +## LATER: +#NAME=SYSTEMPIPESFLUSH +#case "$TESTS" in +#*%functions%*|*%system%*|*%$NAME%*) +#TEST="$NAME: call to od via system() with pipes" +#testod "$N" "$TEST" "" "system:$OD_C,pipes" "$opts" +#esac +#N=$((N+1)) + + +## LATER: +#NAME=EXECPTYFLUSH +#case "$TESTS" in +#*%functions%*|*%exec%*|*%pty%*|*%$NAME%*) +#TEST="$NAME: call to od via exec with pseudo terminal" +#if ! testaddrs pty >/dev/null; then +# $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N +# numCANT=$((numCANT+1)) +#else +#testod "$N" "$TEST" "" "exec:$OD_C,pty,$PTYOPTS" "$opts" +#fi +#esac +#N=$((N+1)) + + +## LATER: +#NAME=SYSTEMPTYFLUSH +#case "$TESTS" in +#*%functions%*|*%system%*|*%pty%*|*%$NAME%*) +#TEST="$NAME: call to od via system() with pseudo terminal" +#if ! testaddrs pty >/dev/null; then +# $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N +# numCANT=$((numCANT+1)) +#else +#testod "$N" "$TEST" "" "system:$OD_C,pty,$PTYOPTS" "$opts" +#fi +#esac +#N=$((N+1)) + + +## LATER: +#NAME=SYSTEMPIPESFDSFLUSH +#case "$TESTS" in +#*%functions%*|*%system%*|*%$NAME%*) +#TEST="$NAME: call to od via system() with pipes, non stdio" +#testod "$N" "$TEST" "" "system:$OD_C>&9 <&8,pipes,fdin=8,fdout=9" "$opts" +#esac +#N=$((N+1)) + + +## LATER: +#NAME=DUALSYSTEMFDSFLUSH +#case "$TESTS" in +#*%functions%*|*%system%*|*%$NAME%*) +#TEST="$NAME: call to od via dual system()" +#testecho "$N" "$TEST" "system:$OD_C>&6,fdout=6!!system:$CAT<&7,fdin=7" "" "$opts" +#esac +#N=$((N+1)) + + +case "$UNAME" in +Linux) IPPROTO=254 ;; +Darwin) IPPROTO=255 ;; +*) IPPROTO=254 ;; # just a guess +esac + +NAME=RAWIP4SELF +case "$TESTS" in +*%functions%*|*%ip4%*|*%rawip%*|*%root%*|*%$NAME%*) +TEST="$NAME: simple echo via self receiving raw IPv4 protocol" +if ! feat=$(testaddrs ip4) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}IP4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! feat=$(testaddrs rawip) >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}RAWIP not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else + testecho "$N" "$TEST" "" "ip4:127.0.0.1:$IPPROTO" "$opts" +fi +esac +N=$((N+1)) + +NAME=RAWIPX4SELF +case "$TESTS" in +*%functions%*|*%ip4%*|*%rawip%*|*%root%*|*%$NAME%*) +TEST="$NAME: simple echo via self receiving raw IP protocol, v4 by target" +if ! feat=$(testaddrs ip4) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}IP4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! feat=$(testaddrs rawip) >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}RAWIP not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else + testecho "$N" "$TEST" "" "ip:127.0.0.1:$IPPROTO" "$opts" +fi +esac +N=$((N+1)) + +NAME=RAWIP6SELF +case "$TESTS" in +*%functions%*|*%ip6%*|*%rawip%*|*%root%*|*%$NAME%*) +TEST="$NAME: simple echo via self receiving raw IPv6 protocol" +if ! feat=$(testaddrs ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! feat=$(testaddrs rawip) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}RAWIP not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else + testecho "$N" "$TEST" "" "ip6:[::1]:$IPPROTO" "$opts" +fi +esac +N=$((N+1)) + +NAME=RAWIPX6SELF +case "$TESTS" in +*%functions%*|*%ip%*|*%ip6%*|*%rawip%*|*%rawip6%*|*%root%*|*%$NAME%*) +TEST="$NAME: simple echo via self receiving raw IP protocol, v6 by target" +if ! feat=$(testaddrs ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! feat=$(testaddrs rawip) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}RAWIP not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else + testecho "$N" "$TEST" "" "ip:[::1]:$IPPROTO" "$opts" +fi +esac +N=$((N+1)) + + +NAME=TCPSELF +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: echo via self connection of TCP IPv4 socket" +if [ "$UNAME" != Linux ]; then + #printf "test $F_n $TEST... ${YELLOW}only on Linux${NORMAL}\n" $N + $PRINTF "test $F_n $TEST... ${YELLOW}only on Linux$NORMAL\n" $N + numCANT=$((numCANT+1)) +else + #ts="127.0.0.1:$tsl" + testecho "$N" "$TEST" "" "tcp:127.100.0.1:$PORT,sp=$PORT,bind=127.100.0.1,reuseaddr" "$opts" +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=UDPSELF +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: echo via self connection of UDP IPv4 socket" +if [ "$UNAME" != Linux ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}only on Linux$NORMAL\n" $N + numCANT=$((numCANT+1)) +else + testecho "$N" "$TEST" "" "udp:127.100.0.1:$PORT,sp=$PORT,bind=127.100.0.1" "$opts" +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=UDP6SELF +case "$TESTS" in +*%functions%*|*%udp%*|*%udp6%*|*%ip6%*|*%$NAME%*) +TEST="$NAME: echo via self connection of UDP IPv6 socket" +if [ "$UNAME" != Linux ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}only on Linux${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs udp ip6 >/dev/null || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}UDP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else + tf="$td/file$N" + testecho "$N" "$TEST" "" "udp6:[::1]:$PORT,sp=$PORT,bind=[::1]" "$opts" +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=DUALUDPSELF +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: echo via two unidirectional UDP IPv4 sockets" +tf="$td/file$N" +p1=$PORT +p2=$((PORT+1)) +testecho "$N" "$TEST" "" "udp:127.0.0.1:$p2,sp=$p1!!udp:127.0.0.1:$p1,sp=$p2" "$opts" +esac +PORT=$((PORT+2)) +N=$((N+1)) + + +#function testdual { +# local +#} + + +NAME=UNIXSOCKET +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: echo via connection to UNIX domain socket" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +ts="$td/test$N.socket" +tdiff="$td/test$N.diff" +da=$(date) +CMD1="$SOCAT $opts UNIX-LISTEN:$ts PIPE" +CMD2="$SOCAT $opts -!!- UNIX:$ts" +printf "test $F_n $TEST... " $N +$CMD1 $tf 2>"${te}1" & +bg=$! # background process id +waitfile "$ts" +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "$te" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: diff:\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $bg 2>/dev/null +esac +N=$((N+1)) + + +NAME=TCP4 +case "$TESTS" in +*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%$NAME%*) +TEST="$NAME: echo via connection to TCP V4 socket" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +tsl=$PORT +ts="127.0.0.1:$tsl" +da=$(date) +CMD1="$SOCAT $opts TCP4-LISTEN:$tsl,reuseaddr PIPE" +CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts" +printf "test $F_n $TEST... " $N +$CMD1 >"$tf" 2>"${te}1" & +waittcp4port $tsl 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "$te" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi ;; +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=TCP6 +case "$TESTS" in +*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%$NAME%*) +TEST="$NAME: echo via connection to TCP V6 socket" +if ! testaddrs tcp ip6 >/dev/null || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +tsl=$PORT +ts="[::1]:$tsl" +da=$(date) +CMD1="$SOCAT $opts TCP6-listen:$tsl,reuseaddr PIPE" +CMD2="$SOCAT $opts stdin!!stdout TCP6:$ts" +printf "test $F_n $TEST... " $N +$CMD1 >"$tf" 2>"${te}1" & +pid=$! # background process id +waittcp6port $tsl 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "$te" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: diff:\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=TCPX4 +case "$TESTS" in +*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%$NAME%*) +TEST="$NAME: echo via connection to TCP socket, v4 by target" +if ! testaddrs tcp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs ip6 >/dev/null || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +tsl=$PORT +ts="127.0.0.1:$tsl" +da=$(date) +CMD1="$SOCAT $opts TCP-listen:$tsl,pf=ip4,reuseaddr PIPE" +CMD2="$SOCAT $opts stdin!!stdout TCP:$ts" +printf "test $F_n $TEST... " $N +$CMD1 >"$tf" 2>"${te}1" & +pid=$! # background process id +waittcp4port $tsl 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "$te" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: diff:\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=TCPX6 +case "$TESTS" in +*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%$NAME%*) +TEST="$NAME: echo via connection to TCP socket, v6 by target" +if ! testaddrs tcp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs ip6 >/dev/null || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +tsl=$PORT +ts="[::1]:$tsl" +da=$(date) +CMD1="$SOCAT $opts TCP-listen:$tsl,pf=ip6,reuseaddr PIPE" +CMD2="$SOCAT $opts stdin!!stdout TCP:$ts" +printf "test $F_n $TEST... " $N +$CMD1 >"$tf" 2>"${te}1" & +pid=$! # background process id +waittcp6port $tsl 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "$te" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: diff:\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=IPV6ONLY0 +case "$TESTS" in +*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%$NAME%*) +TEST="$NAME: option ipv6-v6only=0 listens on IPv4" +if ! testaddrs tcp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs ip6 >/dev/null || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! feat=$(testoptions ipv6-v6only); then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +tsl=$PORT +ts="127.0.0.1:$tsl" +da=$(date) +CMD1="$SOCAT $opts TCP6-listen:$tsl,ipv6-v6only=0,reuseaddr PIPE" +CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts" +printf "test $F_n $TEST... " $N +$CMD1 >"$tf" 2>"${te}1" & +pid=$! # background process id +waittcp6port $tsl 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: diff:\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=IPV6ONLY1 +case "$TESTS" in +*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%$NAME%*) +TEST="$NAME: option ipv6-v6only=1 does not listen on IPv4" +if ! testaddrs tcp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs ip6 >/dev/null || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! feat=$(testoptions ipv6-v6only); then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +tsl=$PORT +ts="127.0.0.1:$tsl" +da=$(date) +CMD1="$SOCAT $opts TCP6-listen:$tsl,ipv6-v6only=1,reuseaddr PIPE" +CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts" +printf "test $F_n $TEST... " $N +$CMD1 >"$tf" 2>"${te}1" & +pid=$! # background process id +waittcp6port $tsl 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +if [ $? -eq 0 ]; then + $PRINTF "$FAILED:\n" + cat "${te}1" "${te}2" + numFAIL=$((numFAIL+1)) +elif echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED:\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=ENV_LISTEN_4 +case "$TESTS" in +*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%$NAME%*) +TEST="$NAME: env SOCAT_DEFAULT_LISTEN_IP for IPv4 preference on listen" +if ! testaddrs tcp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs ip6 >/dev/null || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! feat=$(testoptions ipv6-v6only); then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +tsl=$PORT +ts="127.0.0.1:$tsl" +da=$(date) +CMD1="$SOCAT $opts TCP-listen:$tsl,reuseaddr PIPE" +CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts" +printf "test $F_n $TEST... " $N +SOCAT_DEFAULT_LISTEN_IP=4 $CMD1 >"$tf" 2>"${te}1" & +pid=$! # background process id +waittcp4port $tsl 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: diff:\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=ENV_LISTEN_6 +case "$TESTS" in +*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%$NAME%*) +TEST="$NAME: env SOCAT_DEFAULT_LISTEN_IP for IPv6 preference on listen" +if ! testaddrs tcp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs ip6 >/dev/null || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +tsl=$PORT +ts="[::1]:$tsl" +da=$(date) +CMD1="$SOCAT $opts TCP-listen:$tsl,reuseaddr PIPE" +CMD2="$SOCAT $opts stdin!!stdout TCP6:$ts" +printf "test $F_n $TEST... " $N +SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 >"$tf" 2>"${te}1" & +pid=$! # background process id +waittcp6port $tsl 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: diff:\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=LISTEN_OPTION_4 +case "$TESTS" in +*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%$NAME%*) +TEST="$NAME: option -4 for IPv4 preference on listen" +if ! testaddrs tcp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs ip6 >/dev/null || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! feat=$(testoptions ipv6-v6only); then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +tsl=$PORT +ts="127.0.0.1:$tsl" +da=$(date) +CMD1="$SOCAT $opts -4 TCP-listen:$tsl,reuseaddr PIPE" +CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts" +printf "test $F_n $TEST... " $N +SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 >"$tf" 2>"${te}1" & +pid=$! # background process id +waittcp4port $tsl 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: diff:\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=LISTEN_OPTION_6 +case "$TESTS" in +*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%$NAME%*) +TEST="$NAME: option -6 for IPv6 preference on listen" +if ! testaddrs tcp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs ip6 >/dev/null || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +tsl=$PORT +ts="[::1]:$tsl" +da=$(date) +CMD1="$SOCAT $opts -6 TCP-listen:$tsl,reuseaddr PIPE" +CMD2="$SOCAT $opts stdin!!stdout TCP6:$ts" +printf "test $F_n $TEST... " $N +SOCAT_DEFAULT_LISTEN_IP=4 $CMD1 >"$tf" 2>"${te}1" & +pid=$! # background process id +waittcp6port $tsl 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: diff:\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +wait +fi # feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=LISTEN_PF_IP4 +case "$TESTS" in +*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%$NAME%*) +TEST="$NAME: pf=4 overrides option -6 on listen" +if ! testaddrs tcp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs ip6 >/dev/null || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! feat=$(testoptions ipv6-v6only); then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +tsl=$PORT +ts="127.0.0.1:$tsl" +da=$(date) +CMD1="$SOCAT $opts -6 TCP-listen:$tsl,pf=ip4,reuseaddr PIPE" +CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts" +printf "test $F_n $TEST... " $N +SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 >"$tf" 2>"${te}1" & +pid=$! # background process id +waittcp4port $tsl 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: diff:\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=LISTEN_PF_IP6 +case "$TESTS" in +*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%$NAME%*) +TEST="$NAME: pf=6 overrides option -4 on listen" +if ! testaddrs tcp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs ip6 >/dev/null || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +tsl=$PORT +ts="[::1]:$tsl" +da=$(date) +CMD1="$SOCAT $opts -4 TCP-listen:$tsl,pf=ip6,reuseaddr PIPE" +CMD2="$SOCAT $opts stdin!!stdout TCP6:$ts" +printf "test $F_n $TEST... " $N +SOCAT_DEFAULT_LISTEN_IP=4 $CMD1 >"$tf" 2>"${te}1" & +pid=$! # background process id +waittcp6port $tsl 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: diff:\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=UDP4STREAM +case "$TESTS" in +*%functions%*|*%ip4%*|*%ipapp%*|*%udp%*|*%$NAME%*) +TEST="$NAME: echo via connection to UDP V4 socket" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +tsl=$PORT +ts="$LOCALHOST:$tsl" +da=$(date) +CMD1="$SOCAT $opts UDP4-LISTEN:$tsl,reuseaddr PIPE" +CMD2="$SOCAT $opts - UDP4:$ts" +printf "test $F_n $TEST... " $N +$CMD1 >"$tf" 2>"${te}1" & +pid1=$! +waitudp4port $tsl 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +rc2=$? +kill $pid1 2>/dev/null; wait +if [ $rc2 -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + echo "$CMD1 &" + cat "${te}1" + echo "$CMD2" + cat "${te}2" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi ;; +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=UDP6STREAM +case "$TESTS" in +*%functions%*|*%ip6%*|*%ipapp%*|*%udp%*|*%$NAME%*) +TEST="$NAME: echo via connection to UDP V6 socket" +if ! feat=$(testaddrs udp ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}UDP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +tsl=$PORT +ts="$LOCALHOST6:$tsl" +da=$(date) +CMD1="$SOCAT $opts UDP6-LISTEN:$tsl,reuseaddr PIPE" +CMD2="$SOCAT $opts - UDP6:$ts" +printf "test $F_n $TEST... " $N +$CMD1 >"$tf" 2>"${te}1" & +pid1=$! +waitudp6port $tsl 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +rc2=$? +kill $pid1 2>/dev/null; wait +if [ $rc2 -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +fi ;; # ! testaddrs +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=GOPENFILE +case "$TESTS" in +*%functions%*|*%gopen%*|*%file%*|*%ignoreeof%*|*%$NAME%*) +TEST="$NAME: file opening with gopen" +tf1="$td/test$N.1.stdout" +tf2="$td/test$N.2.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da=$(date) +echo "$da" >$tf1 +CMD="$SOCAT $opts $tf1!!/dev/null /dev/null,ignoreeof!!-" +printf "test $F_n $TEST... " $N +$CMD >"$tf2" 2>"$te" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD" + cat "$te" + numFAIL=$((numFAIL+1)) +elif ! diff "$tf1" "$tf2" >"$tdiff"; then + $PRINTF "$FAILED: diff:\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +esac +N=$((N+1)) + + +NAME=GOPENPIPE +case "$TESTS" in +*%functions%*|*%gopen%*|*%pipe%*|*%ignoreeof%*|*%$NAME%*) +TEST="$NAME: pipe opening with gopen for reading" +tp="$td/pipe$N" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da=$(date) +CMD="$SOCAT $opts $tp!!/dev/null /dev/null,ignoreeof!!$tf" +printf "test $F_n $TEST... " $N +#mknod $tp p # no mknod p on FreeBSD +mkfifo $tp +$CMD >$tf 2>"$te" & +#($CMD >$tf 2>"$te" || rm -f "$tp") 2>/dev/null & +bg=$! # background process id +usleep $MICROS +if [ ! -p "$tp" ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD" + cat "$te" + numFAIL=$((numFAIL+1)) +else +#echo "$da" >"$tp" # might hang forever +echo "$da" >"$tp" & export pid=$!; (sleep 1; kill $pid 2>/dev/null) & +# Solaris needs more time: +sleep 1 +kill "$bg" 2>/dev/null +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + if [ -s "$te" ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD" + cat "$te" + else + $PRINTF "$FAILED: diff:\n" + cat "$tdiff" + fi + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +fi +wait +esac +N=$((N+1)) + + +NAME=GOPENUNIXSTREAM +case "$TESTS" in +*%functions%*|*%gopen%*|*%unix%*|*%listen%*|*%$NAME%*) +TEST="$NAME: GOPEN on UNIX stream socket" +ts="$td/test$N.socket" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da1="test$N $(date) $RANDOM" +#establish a listening unix socket in background +SRV="$SOCAT $opts -lpserver UNIX-LISTEN:\"$ts\" PIPE" +#make a connection +CMD="$SOCAT $opts - $ts" +$PRINTF "test $F_n $TEST... " $N +eval "$SRV 2>${te}s &" +pids=$! +waitfile "$ts" +echo "$da1" |eval "$CMD" >"${tf}1" 2>"${te}1" +if [ $? -ne 0 ]; then + kill "$pids" 2>/dev/null + $PRINTF "$FAILED:\n" + echo "$SRV &" + cat "${te}s" + echo "$CMD" + cat "${te}1" + numFAIL=$((numFAIL+1)) +elif ! echo "$da1" |diff - "${tf}1" >"$tdiff"; then + kill "$pids" 2>/dev/null + $PRINTF "$FAILED:\n" + echo "$SRV &" + cat "${te}s" + echo "$CMD" + cat "${te}1" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi # !(rc -ne 0) +wait +esac +N=$((N+1)) + + +NAME=GOPENUNIXDGRAM +case "$TESTS" in +*%functions%*|*%gopen%*|*%unix%*|*%dgram%*|*%$NAME%*) +TEST="$NAME: GOPEN on UNIX datagram socket" +ts="$td/test$N.socket" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da1="test$N $(date) $RANDOM" +#establish a receiving unix socket in background +SRV="$SOCAT $opts -u -lpserver UNIX-RECV:\"$ts\" file:\"$tf\",create" +#make a connection +CMD="$SOCAT $opts -u - $ts" +$PRINTF "test $F_n $TEST... " $N +eval "$SRV 2>${te}s &" +pids=$! +waitfile "$ts" +echo "$da1" |eval "$CMD" 2>"${te}1" +waitfile -s "$tf" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED:\n" + echo "$SRV &" + cat "${te}s" + echo "$CMD" + cat "${te}1" + numFAIL=$((numFAIL+1)) +elif ! echo "$da1" |diff - "${tf}" >"$tdiff"; then + $PRINTF "$FAILED:\n" + echo "$SRV &" + cat "${te}s" + echo "$CMD" + cat "${te}1" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi # !(rc -ne 0) +kill "$pids" 2>/dev/null +wait +esac +N=$((N+1)) + + +#set -vx +NAME=IGNOREEOF +case "$TESTS" in +*%functions%*|*%ignoreeof%*|*%$NAME%*) +TEST="$NAME: ignoreeof on file" +ti="$td/test$N.file" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="$(date) $RANDOM" +CMD="$SOCAT $opts -u file:\"$ti\",ignoreeof -" +printf "test $F_n $TEST... " $N +touch "$ti" +$CMD >"$tf" 2>"$te" & +bg=$! +sleep 1 +echo "$da" >>"$ti" +sleep 1 +kill $bg 2>/dev/null +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + if [ -s "$te" ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD" + cat "$te" + else + $PRINTF "$FAILED: diff:\n" + cat "$tdiff" + fi + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +wait +esac +N=$((N+1)) +#set +vx + + +NAME=EXECIGNOREEOF +case "$TESTS" in +*%functions%*|*%ignoreeof%*|*%$NAME%*) +TEST="$NAME: exec against address with ignoreeof" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +CMD="$SOCAT $opts -lf /dev/null EXEC:$TRUE /dev/null,ignoreeof" +printf "test $F_n $TEST... " $N +$CMD >"$tf" 2>"$te" +if [ -s "$te" ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD" + cat "$te" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +esac +N=$((N+1)) + + +NAME=FAKEPTY +case "$TESTS" in +*%functions%*|*%pty%*|*%$NAME%*) +TEST="$NAME: generation of pty for other processes" +if ! testaddrs pty >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tt="$td/pty$N" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da=$(date) +CMD1="$SOCAT $opts pty,link=$tt pipe" +CMD2="$SOCAT $opts - $tt,$PTYOPTS2" +printf "test $F_n $TEST... " $N +$CMD1 2>"${te}1" & +pid=$! # background process id +waitfile "$tt" +# this hangs on HP-UX, so we use a timeout +(echo "$da"; sleep 1) |$CMD2 >$tf 2>"${te}2" & +rc2=$! +#sleep 5 && kill $rc2 2>/dev/null & +wait $rc2 +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + sleep 1 + echo "$CMD2" + cat "${te}1" + cat "${te}2" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +wait +fi +esac +N=$((N+1)) + + +NAME=O_TRUNC +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: option o-trunc" +ff="$td/test$N.file" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da=$(date) +CMD="$SOCAT -u $opts - open:$ff,append,o-trunc" +printf "test $F_n $TEST... " $N +rm -f $ff; $ECHO "prefix-\c" >$ff +if ! echo "$da" |$CMD >$tf 2>"$te" || + ! echo "$da" |diff - $ff >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD" + cat "$te" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +esac +N=$((N+1)) + + +NAME=FTRUNCATE +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: option ftruncate" +ff="$td/test$N.file" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da=$(date) +CMD="$SOCAT -u $opts - open:$ff,append,ftruncate=0" +printf "test $F_n $TEST... " $N +rm -f $ff; $ECHO "prefix-\c" >$ff +if ! echo "$da" |$CMD >$tf 2>"$te" || + ! echo "$da" |diff - $ff >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD" + cat "$te" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +esac +N=$((N+1)) + + +NAME=RIGHTTOLEFT +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: unidirectional throughput from stdin to stdout, right to left" +testecho "$N" "$TEST" "stdout" "stdin" "$opts -U" +esac +N=$((N+1)) + + +NAME=CHILDDEFAULT +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: child process default properties" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +CMD="$SOCAT $opts -u exec:$PROCAN -" +printf "test $F_n $TEST... " $N +$CMD >$tf 2>$te +MYPID=`expr "\`grep "process id =" $tf\`" : '[^0-9]*\([0-9]*\).*'` +MYPPID=`expr "\`grep "process parent id =" $tf\`" : '[^0-9]*\([0-9]*\).*'` +MYPGID=`expr "\`grep "process group id =" $tf\`" : '[^0-9]*\([0-9]*\).*'` +MYSID=`expr "\`grep "process session id =" $tf\`" : '[^0-9]*\([0-9]*\).*'` +#echo "PID=$MYPID, PPID=$MYPPID, PGID=$MYPGID, SID=$MYSID" +if [ "$MYPID" = "$MYPPID" -o "$MYPID" = "$MYPGID" -o "$MYPID" = "$MYSID" -o \ + "$MYPPID" = "$MYPGID" -o "$MYPPID" = "$MYSID" -o "$MYPGID" = "$MYSID" ]; +then + $PRINTF "$FAILED:\n" + echo "$CMD" + cat "$te" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + numOK=$((numOK+1)) +fi +esac +N=$((N+1)) + + +NAME=CHILDSETSID +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: child process with setsid" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +CMD="$SOCAT $opts -u exec:$PROCAN,setsid -" +printf "test $F_n $TEST... " $N +$CMD >$tf 2>$te +MYPID=`grep "process id =" $tf |(expr "\`cat\`" : '[^0-9]*\([0-9]*\).*')` +MYPPID=`grep "process parent id =" $tf |(expr "\`cat\`" : '[^0-9]*\([0-9]*\).*')` +MYPGID=`grep "process group id =" $tf |(expr "\`cat\`" : '[^0-9]*\([0-9]*\).*')` +MYSID=`grep "process session id =" $tf |(expr "\`cat\`" : '[^0-9]*\([0-9]*\).*')` +#$ECHO "\nPID=$MYPID, PPID=$MYPPID, PGID=$MYPGID, SID=$MYSID" +# PID, PGID, and SID must be the same +if [ "$MYPID" = "$MYPPID" -o \ + "$MYPID" != "$MYPGID" -o "$MYPID" != "$MYSID" ]; +then + $PRINTF "$FAILED\n" + echo "$CMD" + cat "$te" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + numOK=$((numOK+1)) +fi +esac +N=$((N+1)) + + +NAME=MAINSETSID +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: main process with setsid" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +CMD="$SOCAT $opts -U -,setsid exec:$PROCAN" +printf "test $F_n $TEST... " $N +$CMD >$tf 2>$te +MYPID=`grep "process id =" $tf |(expr "\`cat\`" : '[^0-9]*\([0-9]*\).*')` +MYPPID=`grep "process parent id =" $tf |(expr "\`cat\`" : '[^0-9]*\([0-9]*\).*')` +MYPGID=`grep "process group id =" $tf |(expr "\`cat\`" : '[^0-9]*\([0-9]*\).*')` +MYSID=`grep "process session id =" $tf |(expr "\`cat\`" : '[^0-9]*\([0-9]*\).*')` +#$ECHO "\nPID=$MYPID, PPID=$MYPPID, PGID=$MYPGID, SID=$MYSID" +# PPID, PGID, and SID must be the same +if [ "$MYPID" = "$MYPPID" -o \ + "$MYPPID" != "$MYPGID" -o "$MYPPID" != "$MYSID" ]; +then + $PRINTF "$FAILED\n" + echo "$CMD" + cat "$te" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + numOK=$((numOK+1)) +fi +esac +N=$((N+1)) + + +NAME=OPENSSL_TCP4 +case "$TESTS" in +*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*) +TEST="$NAME: openssl connect" +if ! testaddrs openssl >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! type openssl >/dev/null 2>&1; then + $PRINTF "test $F_n $TEST... ${YELLOW}openssl executable not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs tcp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +gentestcert testsrv +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da=$(date) +CMD2="$SOCAT $opts exec:'openssl s_server -accept "$PORT" -quiet -cert testsrv.pem' pipe" +#! CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT" +CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD" +printf "test $F_n $TEST... " $N +eval "$CMD2 2>\"${te}1\" &" +pid=$! # background process id +waittcp4port $PORT +echo "$da" |$CMD >$tf 2>"${te}2" +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD2 &" + echo "$CMD" + cat "${te}1" + cat "${te}2" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +wait +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=OPENSSLLISTEN_TCP4 +case "$TESTS" in +*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*) +TEST="$NAME: openssl listen" +if ! testaddrs openssl >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +gentestcert testsrv +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da=$(date) +CMD2="$SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip4,reuseaddr,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 pipe" +CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD" +printf "test $F_n $TEST... " $N +eval "$CMD2 2>\"${te}1\" &" +pid=$! # background process id +waittcp4port $PORT +echo "$da" |$CMD >$tf 2>"${te}2" +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD2 &" + echo "$CMD" + cat "${te}1" + cat "${te}2" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +wait +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=OPENSSLLISTEN_TCP6 +case "$TESTS" in +*%functions%*|*%openssl%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%$NAME%*) +TEST="$NAME: openssl listen" +if ! testaddrs openssl >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs listen tcp ip6 >/dev/null || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +gentestcert testsrv +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da=$(date) +CMD2="$SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip6,reuseaddr,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 pipe" +CMD="$SOCAT $opts - openssl:$LOCALHOST6:$PORT,verify=0,$SOCAT_EGD" +printf "test $F_n $TEST... " $N +eval "$CMD2 2>\"${te}1\" &" +pid=$! # background process id +waittcp6port $PORT +echo "$da" |$CMD >$tf 2>"${te}2" +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD2 &" + echo "$CMD" + cat "${te}1" + cat "${te}2" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +wait +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=OPENSSL_SERVERAUTH +case "$TESTS" in +*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*) +TEST="$NAME: openssl server authentication" +if ! testaddrs openssl >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +gentestcert testsrv +gentestcert testcli +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da=$(date) +CMD2="$SOCAT $opts OPENSSL-LISTEN:$PORT,reuseaddr,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 pipe" +CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT,verify=1,cafile=testsrv.crt,$SOCAT_EGD" +printf "test $F_n $TEST... " $N +eval "$CMD2 2>\"${te}1\" &" +pid=$! # background process id +waittcp4port $PORT +echo "$da" |$CMD >$tf 2>"${te}2" +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD2 &" + echo "$CMD" + cat "${te}1" + cat "${te}2" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +wait +fi # feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=OPENSSL_CLIENTAUTH +case "$TESTS" in +*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*) +TEST="$NAME: openssl client authentication" +if ! testaddrs openssl >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +gentestcert testsrv +gentestcert testcli +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da=$(date) +CMD2="$SOCAT $opts OPENSSL-LISTEN:$PORT,reuseaddr,verify=1,cert=testsrv.crt,key=testsrv.key,cafile=testcli.crt,$SOCAT_EGD pipe" +CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT,verify=0,cert=testcli.crt,key=testcli.key,$SOCAT_EGD" +printf "test $F_n $TEST... " $N +eval "$CMD2 2>\"${te}1\" &" +pid=$! # background process id +waittcp4port $PORT +echo "$da" |$CMD >$tf 2>"${te}2" +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD2 &" + echo "$CMD" + cat "${te}1" + cat "${te}2" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +wait +fi # feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=OPENSSL_FIPS_BOTHAUTH +case "$TESTS" in +*%functions%*|*%openssl%*|*%fips%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*) +TEST="$NAME: OpenSSL+FIPS client and server authentication" +if ! testaddrs openssl >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testoptions fips >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL/FIPS not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +OPENSSL_FIPS=1 gentestcert testsrvfips +OPENSSL_FIPS=1 gentestcert testclifips +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da=$(date) +CMD2="$SOCAT $opts OPENSSL-LISTEN:$PORT,reuseaddr,fips,$SOCAT_EGD,cert=testsrvfips.crt,key=testsrvfips.key,cafile=testclifips.crt pipe" +CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT,fips,verify=1,cert=testclifips.crt,key=testclifips.key,cafile=testsrvfips.crt,$SOCAT_EGD" +printf "test $F_n $TEST... " $N +eval "$CMD2 2>\"${te}1\" &" +pid=$! # background process id +waittcp4port $PORT +echo "$da" |$CMD >$tf 2>"${te}2" +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD2 &" + echo "$CMD" + cat "${te}1" + cat "${te}2" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +wait +fi # feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=SOCKS4CONNECT_TCP4 +case "$TESTS" in +*%functions%*|*%socks%*|*%socks4%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*) +TEST="$NAME: socks4 connect over TCP/IPv4" +if ! testaddrs socks4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}SOCKS4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="$(date)" da="$da$($ECHO '\r')" +# we have a normal tcp echo listening - so the socks header must appear in answer +CMD2="$SOCAT tcp4-l:$PORT,reuseaddr exec:\"./socks4echo.sh\"" +CMD="$SOCAT $opts - socks4:$LOCALHOST:32.98.76.54:32109,pf=ip4,socksport=$PORT",socksuser="nobody" +printf "test $F_n $TEST... " $N +eval "$CMD2 2>\"${te}1\" &" +pid=$! # background process id +waittcp4port $PORT 1 +echo "$da" |$CMD >$tf 2>"${te}2" +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD2 &" + echo "$CMD" + cat "${te}1" + cat "${te}2" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +wait +fi # feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=SOCKS4CONNECT_TCP6 +case "$TESTS" in +*%functions%*|*%socks%*|*%socks4%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%$NAME%*) +TEST="$NAME: socks4 connect over TCP/IPv6" +if ! testaddrs socks4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}SOCKS4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs listen tcp ip6 >/dev/null || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="$(date)" da="$da$($ECHO '\r')" +# we have a normal tcp echo listening - so the socks header must appear in answer +CMD2="$SOCAT tcp6-l:$PORT,reuseaddr exec:\"./socks4echo.sh\"" +CMD="$SOCAT $opts - socks4:$LOCALHOST6:32.98.76.54:32109,socksport=$PORT",socksuser="nobody" +printf "test $F_n $TEST... " $N +eval "$CMD2 2>\"${te}1\" &" +pid=$! # background process id +waittcp6port $PORT 1 +echo "$da" |$CMD >$tf 2>"${te}2" +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD2 &" + echo "$CMD" + cat "${te}1" + cat "${te}2" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +wait +fi # feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=SOCKS4ACONNECT_TCP4 +case "$TESTS" in +*%functions%*|*%socks%*|*%socks4a%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*) +TEST="$NAME: socks4a connect over TCP/IPv4" +if ! testaddrs socks4a >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}SOCKS4A not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="$(date)" da="$da$($ECHO '\r')" +# we have a normal tcp echo listening - so the socks header must appear in answer +CMD2="$SOCAT tcp4-l:$PORT,reuseaddr exec:\"./socks4a-echo.sh\"" +CMD="$SOCAT $opts - socks4a:$LOCALHOST:localhost:32109,pf=ip4,socksport=$PORT",socksuser="nobody" +printf "test $F_n $TEST... " $N +eval "$CMD2 2>\"${te}1\" &" +pid=$! # background process id +waittcp4port $PORT 1 +echo "$da" |$CMD >$tf 2>"${te}2" +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD2 &" + echo "$CMD" + cat "${te}1" + cat "${te}2" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +wait +fi # feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=SOCKS4ACONNECT_TCP6 +case "$TESTS" in +*%functions%*|*%socks%*|*%socks4a%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%$NAME%*) +TEST="$NAME: socks4a connect over TCP/IPv6" +if ! testaddrs socks4a >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}SOCKS4A not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs listen tcp ip6 >/dev/null || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="$(date)" da="$da$($ECHO '\r')" +# we have a normal tcp echo listening - so the socks header must appear in answer +CMD2="$SOCAT tcp6-l:$PORT,reuseaddr exec:\"./socks4a-echo.sh\"" +CMD="$SOCAT $opts - socks4a:$LOCALHOST6:localhost:32109,socksport=$PORT",socksuser="nobody" +printf "test $F_n $TEST... " $N +eval "$CMD2 2>\"${te}1\" &" +pid=$! # background process id +waittcp6port $PORT 1 +echo "$da" |$CMD >$tf 2>"${te}2" +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD2 &" + echo "$CMD" + cat "${te}1" + cat "${te}2" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +wait +fi # feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=PROXYCONNECT_TCP4 +case "$TESTS" in +*%functions%*|*%proxyconnect%*|*%proxy%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*) +TEST="$NAME: proxy connect over TCP/IPv4" +if ! testaddrs proxy >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}PROXY not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +ts="$td/test$N.sh" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="$(date)" da="$da$($ECHO '\r')" +#CMD2="$SOCAT tcp4-l:$PORT,crlf system:\"read; read; $ECHO \\\"HTTP/1.0 200 OK\n\\\"; cat\"" +CMD2="$SOCAT tcp4-l:$PORT,reuseaddr,crlf exec:\"/bin/bash proxyecho.sh\"" +CMD="$SOCAT $opts - proxy:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT" +printf "test $F_n $TEST... " $N +eval "$CMD2 2>\"${te}2\" &" +pid=$! # background process id +waittcp4port $PORT 1 +echo "$da" |$CMD >"$tf" 2>"${te}1" +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD2 &" + echo "$CMD" + cat "${te}1" + cat "${te}2" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +wait +fi # feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=PROXYCONNECT_TCP6 +case "$TESTS" in +*%functions%*|*%proxyconnect%*|*%proxy%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%$NAME%*) +TEST="$NAME: proxy connect over TCP/IPv6" +if ! testaddrs proxy >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}PROXY not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs listen tcp ip6 >/dev/null || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +ts="$td/test$N.sh" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="$(date)" da="$da$($ECHO '\r')" +#CMD2="$SOCAT tcp6-l:$PORT,crlf system:\"read; read; $ECHO \\\"HTTP/1.0 200 OK\n\\\"; cat\"" +CMD2="$SOCAT tcp6-l:$PORT,reuseaddr,crlf exec:\"/bin/bash proxyecho.sh\"" +CMD="$SOCAT $opts - proxy:$LOCALHOST6:127.0.0.1:1000,proxyport=$PORT" +printf "test $F_n $TEST... " $N +eval "$CMD2 2>\"${te}2\" &" +pid=$! # background process id +waittcp6port $PORT 1 +echo "$da" |$CMD >"$tf" 2>"${te}1" +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD2 &" + echo "$CMD" + cat "${te}1" + cat "${te}2" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +wait +fi # feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=TCP4NOFORK +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: echo via connection to TCP V4 socket with nofork'ed exec" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +tsl=$PORT +ts="127.0.0.1:$tsl" +da=$(date) +CMD1="$SOCAT $opts TCP4-LISTEN:$tsl,reuseaddr exec:$CAT,nofork" +CMD2="$SOCAT $opts stdin!!stdout TCP4:$ts" +printf "test $F_n $TEST... " $N +#$CMD1 >"$tf" 2>"${te}1" & +$CMD1 >/dev/null 2>"${te}1" & +waittcp4port $tsl +#usleep $MICROS +echo "$da" |$CMD2 >"$tf" 2>>"${te}2" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=EXECCATNOFORK +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: simple echo via exec of cat with nofork" +testecho "$N" "$TEST" "" "exec:$CAT,nofork" "$opts" +esac +N=$((N+1)) + + +NAME=SYSTEMCATNOFORK +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: simple echo via system() of cat with nofork" +testecho "$N" "$TEST" "" "system:$CAT,nofork" "$opts" +esac +N=$((N+1)) + + +NAME=NOFORKSETSID +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: simple echo via exec() of cat with nofork and setsid" +testecho "$N" "$TEST" "" "system:$CAT,nofork,setsid" "$opts" +esac +N=$((N+1)) + +#============================================================================== +#TEST="$NAME: echo via 'connection' to UDP V4 socket" +#tf="$td/file$N" +#tsl=65534 +#ts="127.0.0.1:$tsl" +#da=$(date) +#$SOCAT UDP-listen:$tsl PIPE & +#sleep 2 +#echo "$da" |$SOCAT stdin!!stdout UDP:$ts >"$tf" +#if [ $? -eq 0 ] && echo "$da" |diff "$tf" -; then +# $ECHO "... test $N succeeded" +# numOK=$((numOK+1)) +#else +# $ECHO "*** test $N $FAILED" +# numFAIL=$((numFAIL+1)) +#fi +#N=$((N+1)) +#============================================================================== +# TEST 4 - simple echo via new file +#N=4 +#tf="$td/file$N" +#tp="$td/pipe$N" +#da=$(date) +#rm -f "$tf.tmp" +#echo "$da" |$SOCAT - FILE:$tf.tmp,ignoreeof >"$tf" +#if [ $? -eq 0 ] && echo "$da" |diff "$tf" -; then +# $ECHO "... test $N succeeded" +# numOK=$((numOK+1)) +#else +# $ECHO "*** test $N $FAILED" +# numFAIL=$((numFAIL+1)) +#fi + +#============================================================================== + +NAME=TOTALTIMEOUT +case "$TESTS" in +*%functions%*|*%timeout%*|*%$NAME%*) +TEST="$NAME: socat inactivity timeout" +if ! true; then + : +else +#set -vx +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="$(date)" da="$da$($ECHO '\r')" +CMD2="$SOCAT $opts -T 1 tcp4-listen:$PORT,reuseaddr pipe" +CMD="$SOCAT $opts - tcp4-connect:$LOCALHOST:$PORT" +printf "test $F_n $TEST... " $N +eval "$CMD2 2>${te}1 &" +pid=$! # background process id +waittcp4port $PORT 1 +(echo "$da"; sleep 2; echo X) |$CMD >"$tf" 2>"${te}2" +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD2 &" + echo "$CMD" + cat "${te}1" + cat "${te}2" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +wait +#set +vx +fi # feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=IGNOREEOF+TOTALTIMEOUT +case "$TESTS" in +*%functions%*|*%timeout%*|*%ignoreeof%*|*%$NAME%*) +TEST="$NAME: ignoreeof and inactivity timeout" +if ! true; then + : +else +#set -vx +ti="$td/test$N.file" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="$(date) $RANDOM" +CMD="$SOCAT $opts -T 2 -u file:\"$ti\",ignoreeof -" +printf "test $F_n $TEST... " $N +touch "$ti" +$CMD >"$tf" 2>"$te" & +bg=$! # background process id +sleep 1 +echo "$da" >>"$ti" +sleep 4 +echo X >>"$ti" +sleep 1 +kill $bg 2>/dev/null +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD &" + cat "$te" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "$te"; fi + numOK=$((numOK+1)) +fi +wait +fi # feats +esac +N=$((N+1)) + + +NAME=PROXY2SPACES +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: proxy connect accepts status with multiple spaces" +if ! testaddrs proxy >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}PROXY not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +ts="$td/test$N.sh" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="$(date)" da="$da$($ECHO '\r')" +#CMD2="$SOCAT tcp-l:$PORT,crlf system:\"read; read; $ECHO \\\"HTTP/1.0 200 OK\n\\\"; cat\"" +CMD2="$SOCAT tcp4-l:$PORT,reuseaddr,crlf exec:\"/bin/bash proxyecho.sh -w 2\"" +CMD="$SOCAT $opts - proxy:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT" +printf "test $F_n $TEST... " $N +eval "$CMD2 2>\"${te}1\" &" +pid=$! # background process id +waittcp4port $PORT 1 +echo "$da" |$CMD >"$tf" 2>"${te}2" +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD2 &" + echo "$CMD" + cat "${te}1" + cat "${te}2" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +wait +fi # feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=BUG-UNISTDIO +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: for bug with address options on both stdin/out in unidirectional mode" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +ff="$td/file$N" +printf "test $F_n $TEST... " $N +>"$ff" +#$SOCAT $opts -u /dev/null -,setlk <"$ff" 2>"$te" +CMD="$SOCAT $opts -u /dev/null -,setlk" +$CMD <"$ff" 2>"$te" +if [ "$?" -eq 0 ]; then + $PRINTF "$OK\n" + numOK=$((numOK+1)) +else + if [ "$UNAME" = "Linux" ]; then + $PRINTF "$FAILED\n" + echo "$CMD" + cat "$te" + numFAIL=$((numFAIL+1)) + else + $PRINTF "${YELLOW}failed (don't care)${NORMAL}\n" + numCANT=$((numCANT+1)) + fi +fi +esac +N=$((N+1)) + + +NAME=SINGLEEXECOUTSOCKETPAIR +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: inheritance of stdout to single exec with socketpair" +testecho "$N" "$TEST" "-!!exec:cat" "" "$opts" 1 +esac +N=$((N+1)) + +NAME=SINGLEEXECOUTPIPE +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: inheritance of stdout to single exec with pipe" +testecho "$N" "$TEST" "-!!exec:cat,pipes" "" "$opts" 1 +esac +N=$((N+1)) + +NAME=SINGLEEXECOUTPTY +case "$TESTS" in +*%functions%*|*%pty%*|*%$NAME%*) +TEST="$NAME: inheritance of stdout to single exec with pty" +if ! testaddrs pty >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +testecho "$N" "$TEST" "-!!exec:cat,pty,raw" "" "$opts" 1 +fi +esac +N=$((N+1)) + +NAME=SINGLEEXECINSOCKETPAIR +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: inheritance of stdin to single exec with socketpair" +testecho "$N" "$TEST" "exec:cat!!-" "" "$opts" +esac +N=$((N+1)) + +NAME=SINGLEEXECINPIPE +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: inheritance of stdin to single exec with pipe" +testecho "$N" "$TEST" "exec:cat,pipes!!-" "" "$opts" +esac +N=$((N+1)) + +NAME=SINGLEEXECINPTYDELAY +case "$TESTS" in +*%functions%*|*%pty%*|*%$NAME%*) +TEST="$NAME: inheritance of stdin to single exec with pty, with delay" +if ! testaddrs pty >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +testecho "$N" "$TEST" "exec:cat,pty,raw!!-" "" "$opts" $MISCDELAY +fi +esac +N=$((N+1)) + +NAME=SINGLEEXECINPTY +case "$TESTS" in +*%functions%*|*%pty%*|*%$NAME%*) +TEST="$NAME: inheritance of stdin to single exec with pty" +if ! testaddrs pty >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +testecho "$N" "$TEST" "exec:cat,pty,raw!!-" "" "$opts" +fi +esac +N=$((N+1)) + + +NAME=READLINE +#set -vx +case "$TESTS" in +*%functions%*|*%pty%*|*%$NAME%*) +TEST="$NAME: readline with password and sigint" +if ! feat=$(testaddrs readline pty); then + $PRINTF "test $F_n $TEST... ${YELLOW}$(echo $feat| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +SAVEMICS=$MICROS +#MICROS=2000000 +ts="$td/test$N.sh" +to="$td/test$N.stdout" +tpi="$td/test$N.inpipe" +tpo="$td/test$N.outpipe" +te="$td/test$N.stderr" +tr="$td/test$N.ref" +tdiff="$td/test$N.diff" +da="$(date)" da="$da$($ECHO '\r')" +# the feature that we really want to test is in the readline.sh script: +CMD="$SOCAT $opts open:$tpi,nonblock!!open:$tpo exec:\"./readline.sh -nh ./readline-test.sh\",pty,ctty,setsid,raw,echo=0,isig" +#echo "$CMD" >"$ts" +#chmod a+x "$ts" +printf "test $F_n $TEST... " $N +rm -f "$tpi" "$tpo" +mkfifo "$tpi" +touch "$tpo" +# +# during development of this test, the following command line succeeded: +# (sleep 1; $ECHO "user\n\c"; sleep 1; $ECHO "password\c"; sleep 1; $ECHO "\n\c"; sleep 1; $ECHO "test 1\n\c"; sleep 1; $ECHO "\003\c"; sleep 1; $ECHO "test 2\n\c"; sleep 1; $ECHO "exit\n\c"; sleep 1) |$SOCAT -d -d -d -d -lf/tmp/gerhard/debug1 -v -x - exec:'./readline.sh ./readline-test.sh',pty,ctty,setsid,raw,echo=0,isig +# +PATH=${SOCAT%socat}:$PATH eval "$CMD 2>$te &" +pid=$! # background process id +usleep $MICROS + +( +usleep $((3*MICROS)) +$ECHO "user\n\c" +usleep $MICROS +$ECHO "password\c" +usleep $MICROS +$ECHO "\n\c" +usleep $MICROS +$ECHO "test 1\n\c" +usleep $MICROS +$ECHO "\003\c" +usleep $MICROS +$ECHO "test 2\n\c" +usleep $MICROS +$ECHO "exit\n\c" +usleep $MICROS +) >"$tpi" + +#cat >$tr < prog> test 1 +#executing test 1 +#prog> ./readline-test.sh got SIGINT +# test 2 +#executing test 2 +#prog> prog> exit +#EOF +cat >$tr < test 1 +executing test 1 +prog> ./readline-test.sh got SIGINT +test 2 +executing test 2 +prog> exit +EOF + +#0 if ! sed 's/.*\r//g' "$tpo" |diff -q "$tr" - >/dev/null 2>&1; then +#0 if ! sed 's/.*'"$($ECHO '\r\c')"'//dev/null 2>&1; then +if ! tr "$($ECHO '\r \c')" "% " <$tpo |sed 's/%$//g' |sed 's/.*%//g' |diff "$tr" - >"$tdiff" 2>&1; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD" + cat "$te" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +#kill $pid 2>/dev/null +MICROS=$SAVEMICS +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=GENDERCHANGER +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: TCP4 \"gender changer\"" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da=$(date) +# this is the server in the protected network that we want to reach +CMD1="$SOCAT -lpserver $opts tcp4-l:$PORT,reuseaddr,bind=$LOCALHOST echo" +# this is the double client in the protected network +CMD2="$SOCAT -lp2client $opts tcp4:$LOCALHOST:$((PORT+1)),retry=10,intervall=1 tcp4:$LOCALHOST:$PORT" +# this is the double server in the outside network +CMD3="$SOCAT -lp2server $opts tcp4-l:$((PORT+2)),reuseaddr,bind=$LOCALHOST tcp4-l:$((PORT+1)),reuseaddr,bind=$LOCALHOST" +# this is the outside client that wants to use the protected server +CMD4="$SOCAT -lpclient $opts -t1 - tcp4:$LOCALHOST:$((PORT+2))" +printf "test $F_n $TEST... " $N +eval "$CMD1 2>${te}1 &" +pid1=$! +eval "$CMD2 2>${te}2 &" +pid2=$! +eval "$CMD3 2>${te}3 &" +pid3=$! +waittcp4port $PORT 1 && +waittcp4port $((PORT+2)) 1 +sleep 1 +echo "$da" |$CMD4 >$tf 2>"${te}4" +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2 &" + echo "$CMD3 &" + echo "$CMD4" + cat "${te}1" "${te}2" "${te}3" "${te}4" + echo "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2" "${te}3" "${te}4"; fi + numOK=$((numOK+1)) +fi +kill $pid1 $pid2 $pid3 $pid4 2>/dev/null +wait +esac +PORT=$((PORT+3)) +N=$((N+1)) + + +#! +#PORT=10000 +#! +NAME=OUTBOUNDIN +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: gender changer via SSL through HTTP proxy, oneshot" +if ! feat=$(testaddrs openssl proxy); then + $PRINTF "test $F_n $TEST... ${YELLOW}$(echo $feat |tr 'a-z' 'A-Z') not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +gentestcert testsrv +gentestcert testcli +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da=$(date) +# this is the server in the protected network that we want to reach +CMD1="$SOCAT $opts -lpserver tcp4-l:$PORT,reuseaddr,bind=$LOCALHOST echo" +# this is the proxy in the protected network that provides a way out +CMD2="$SOCAT $opts -lpproxy tcp4-l:$((PORT+1)),reuseaddr,bind=$LOCALHOST,fork exec:./proxy.sh" +# this is our proxy connect wrapper in the protected network +CMD3="$SOCAT $opts -lpwrapper tcp4-l:$((PORT+2)),reuseaddr,bind=$LOCALHOST,fork proxy:$LOCALHOST:$LOCALHOST:$((PORT+3)),pf=ip4,proxyport=$((PORT+1)),resolve" +# this is our double client in the protected network using SSL +#CMD4="$SOCAT $opts -lp2client ssl:$LOCALHOST:$((PORT+2)),pf=ip4,retry=10,intervall=1,cert=testcli.pem,cafile=testsrv.crt,$SOCAT_EGD tcp4:$LOCALHOST:$PORT" +CMD4="$SOCAT $opts -lp2client ssl:$LOCALHOST:$((PORT+2)),pf=ip4,cert=testcli.pem,cafile=testsrv.crt,$SOCAT_EGD tcp4:$LOCALHOST:$PORT" +# this is the double server in the outside network +CMD5="$SOCAT $opts -lp2server -t1 tcp4-l:$((PORT+4)),reuseaddr,bind=$LOCALHOST ssl-l:$((PORT+3)),pf=ip4,reuseaddr,bind=$LOCALHOST,$SOCAT_EGD,cert=testsrv.pem,cafile=testcli.crt" +# this is the outside client that wants to use the protected server +CMD6="$SOCAT $opts -lpclient -t5 - tcp4:$LOCALHOST:$((PORT+4))" +printf "test $F_n $TEST... " $N +eval "$CMD1 2>${te}1 &" +pid1=$! +eval "$CMD2 2>${te}2 &" +pid2=$! +eval "$CMD3 2>${te}3 &" +pid3=$! +waittcp4port $PORT 1 || $PRINTF "$FAILED: port $PORT\n" >&2 &2 &2 ${te}5 &" +pid5=$! +waittcp4port $((PORT+4)) 1 || $PRINTF "$FAILED: port $((PORT+4))\n" >&2 $tf 2>"${te}6" & +pid6=$! +waittcp4port $((PORT+3)) 1 || $PRINTF "$FAILED: port $((PORT+3))\n" >&2 ${te}4 &" +pid4=$! +wait $pid6 +if ! (echo "$da"; sleep 2) |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + cat "${te}1" + echo "$CMD2 &" + cat "${te}2" + echo "$CMD3 &" + cat "${te}3" + echo "$CMD5 &" + cat "${te}5" + echo "$CMD6" + cat "${te}6" + echo "$CMD4 &" + cat "${te}4" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2" "${te}3" "${te}4" "${te}5" "${te}6"; fi + numOK=$((numOK+1)) +fi +kill $pid1 $pid2 $pid3 $pid4 $pid5 2>/dev/null +wait +fi # feats +esac +PORT=$((PORT+5)) +N=$((N+1)) + + +#! +PORT=$((RANDOM+16184)) +#! +NAME=INTRANETRIPPER +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: gender changer via SSL through HTTP proxy, daemons" +if ! feat=$(testaddrs openssl proxy); then + $PRINTF "test $F_n $TEST... ${YELLOW}$(echo $feat| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +gentestcert testsrv +gentestcert testcli +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da1="test$N.1 $(date) $RANDOM" +da2="test$N.2 $(date) $RANDOM" +da3="test$N.3 $(date) $RANDOM" +# this is the server in the protected network that we want to reach +CMD1="$SOCAT $opts -lpserver -t1 tcp4-l:$PORT,reuseaddr,bind=$LOCALHOST,fork echo" +# this is the proxy in the protected network that provides a way out +CMD2="$SOCAT $opts -lpproxy -t1 tcp4-l:$((PORT+1)),reuseaddr,bind=$LOCALHOST,fork exec:./proxy.sh" +# this is our proxy connect wrapper in the protected network +CMD3="$SOCAT $opts -lpwrapper -t3 tcp4-l:$((PORT+2)),reuseaddr,bind=$LOCALHOST,fork proxy:$LOCALHOST:$LOCALHOST:$((PORT+3)),pf=ip4,proxyport=$((PORT+1)),resolve" +# this is our double client in the protected network using SSL +CMD4="$SOCAT $opts -lp2client -t3 ssl:$LOCALHOST:$((PORT+2)),retry=10,intervall=1,cert=testcli.pem,cafile=testsrv.crt,verify,fork,$SOCAT_EGD tcp4:$LOCALHOST:$PORT" +# this is the double server in the outside network +CMD5="$SOCAT $opts -lp2server -t4 tcp4-l:$((PORT+4)),reuseaddr,bind=$LOCALHOST,fork ssl-l:$((PORT+3)),pf=ip4,reuseaddr,bind=$LOCALHOST,$SOCAT_EGD,cert=testsrv.pem,cafile=testcli.crt,retry=10" +# this is the outside client that wants to use the protected server +CMD6="$SOCAT $opts -lpclient -t5 - tcp4:$LOCALHOST:$((PORT+4)),retry=3" +printf "test $F_n $TEST... " $N +# start the intranet infrastructure +eval "$CMD1 2>\"${te}1\" &" +pid1=$! +eval "$CMD2 2>\"${te}2\" &" +pid2=$! +waittcp4port $PORT 1 || $PRINTF "$FAILED: port $PORT\n" >&2 &2 \"${te}3\" &" +pid3=$! +eval "$CMD4 2>\"${te}4\" &" +pid4=$! +waittcp4port $((PORT+2)) 1 || $PRINTF "$FAILED: port $((PORT+2))\n" >&2 \"${te}5\" &" +pid5=$! +waittcp4port $((PORT+4)) 1 || $PRINTF "$FAILED: port $((PORT+4))\n" >&2 ${tf}_1 2>"${te}6_1" & +pid6_1=$! +echo "$da2" |$CMD6 >${tf}_2 2>"${te}6_2" & +pid6_2=$! +echo "$da3" |$CMD6 >${tf}_3 2>"${te}6_3" & +pid6_3=$! +wait $pid6_1 $pid6_2 $pid6_3 +# +(echo "$da1"; sleep 2) |diff - "${tf}_1" >"${tdiff}1" +(echo "$da2"; sleep 2) |diff - "${tf}_2" >"${tdiff}2" +(echo "$da3"; sleep 2) |diff - "${tf}_3" >"${tdiff}3" +if test -s "${tdiff}1" -o -s "${tdiff}2" -o -s "${tdiff}3"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + cat "${te}1" + echo "$CMD2 &" + cat "${te}2" + echo "$CMD3 &" + cat "${te}3" + echo "$CMD4 &" + cat "${te}4" + echo "$CMD5 &" + cat "${te}5" + echo "$CMD6 &" + cat "${te}6_1" + cat "${tdiff}1" + echo "$CMD6 &" + cat "${te}6_2" + cat "${tdiff}2" + echo "$CMD6 &" + cat "${te}6_3" + cat "${tdiff}3" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2" "${te}3" "${te}4" "${te}5" ${te}6*; fi + numOK=$((numOK+1)) +fi +kill $pid1 $pid2 $pid3 $pid4 $pid5 2>/dev/null +wait +fi +esac +PORT=$((PORT+5)) +N=$((N+1)) + + +# let us test the security features with -s, retry, and fork +# method: first test without security feature if it works +# then try with security feature, must fail + +# test the security features of a server address +testserversec () { + local num="$1" + local title="$2" + local opts="$3" + local arg1="$4" # the server address + local secopt0="$5" # option without security for server, mostly empty + local secopt1="$6" # the security option for server, to be tested + local arg2="$7" # the client address + local ipvers="$8" # IP version, for check of listen port + local proto="$9" # protocol, for check of listen port + local port="${10}" # start client when this port is listening + local expect="${11}" # expected behaviour of client: 0..empty output; -1..error + local T="${12}"; [ -z "$T" ] && T=0 + local tf="$td/test$N.stdout" + local te="$td/test$N.stderr" + local tdiff1="$td/test$N.diff1" + local tdiff2="$td/test$N.diff2" + local da="$(date)" + local stat result + + $PRINTF "test $F_n %s... " $num "$title" +#set -vx + # first: without security + # start server + $SOCAT $opts "$arg1,$secopt0" echo 2>"${te}1" & + spid=$! + if [ "$port" ] && ! wait${proto}${ipvers}port $port 1; then + kill $spid 2>/dev/null + $PRINTF "$NO_RESULT (ph.1 server not working):\n" + echo "$SOCAT $opts \"$arg1,$secopt0\" echo &" + cat "${te}1" + numCANT=$((numCANT+1)) + wait; return + fi + # now use client + (echo "$da"; sleep $T) |$SOCAT $opts - "$arg2" >"$tf" 2>"${te}2" + stat="$?" + kill $spid 2>/dev/null + #killall $SOCAT 2>/dev/null + if [ "$stat" != 0 ]; then + $PRINTF "$NO_RESULT (ph.1 function fails): $SOCAT:\n" + echo "$SOCAT $opts \"$arg1,$secopt0\" echo &" + cat "${te}1" + echo "$SOCAT $opts - \"$arg2\"" + cat "${te}2" + numCANT=$((numCANT+1)) + wait; return + elif echo "$da" |diff - "$tf" >"$tdiff1" 2>&1; then + : # function without security is ok, go on + else + $PRINTF "$NO_RESULT (ph.1 function fails): diff:\n" + echo "$SOCAT $opts $arg1,$secopt0 echo &" + cat "${te}1" + echo "$SOCAT $opts - $arg2" + cat "${te}2" + cat "$tdiff1" + numCANT=$((numCANT+1)) + wait; return + fi + + # then: with security + if [ "$port" ] && ! wait${proto}${ipvers}port $port 0; then + $PRINTF "$NO_RESULT (ph.1 port remains in use)\n" + numCANT=$((numCANT+1)) + wait; return + fi + wait + +#set -vx + # assemble address w/ security option; on dual, take read part: + case "$arg1" in + *!!*) arg="${arg1%!!*},$secopt1!!${arg1#*!!}" ;; + *) arg="$arg1,$secopt1" ;; + esac + # start server + CMD3="$SOCAT $opts $arg echo" + $CMD3 2>"${te}3" & + spid=$! + if [ "$port" ] && ! wait${proto}${ipvers}port $port 1; then + kill $spid 2>/dev/null + $PRINTF "$NO_RESULT (ph.2 server not working)\n" + wait + echo "$CMD3" + cat "${te}3" + numCANT=$((numCANT+1)) + return + fi + # now use client + (echo "$da"; sleep $T) |$SOCAT $opts - "$arg2" >"$tf" 2>"${te}4" + stat=$? + kill $spid 2>/dev/null +#set +vx + #killall $SOCAT 2>/dev/null + if [ "$stat" != 0 ]; then + result=-1; # socat had error + elif [ ! -s "$tf" ]; then + result=0; # empty output + elif echo "$da" |diff - "$tf" >"$tdiff2" 2>&1; then + result=1; # output is copy of input + else + result=2; # output differs from input + fi + if [ X$result != X$expect ]; then + case X$result in + X-1) $PRINTF "$NO_RESULT (ph.2 client error): $SOCAT:\n" + echo "$SOCAT $opts $arg echo" + cat "${te}3" + echo "$SOCAT $opts - $arg2" + cat "${te}4" + numCANT=$((numCANT+1)) ;; + X0) $PRINTF "$NO_RESULT (ph.2 diff failed): diff:\n" + echo "$SOCAT $opts $arg echo" + cat "${te}3" + echo "$SOCAT $opts - $arg2" + cat "${te}4" + cat "$tdiff2" + numCANT=$((numCANT+1)) ;; + X1) $PRINTF "$FAILED: SECURITY BROKEN\n" + echo "$SOCAT $opts $arg echo" + cat "${te}3" + echo "$SOCAT $opts - $arg2" + cat "${te}4" + cat "$tdiff2" + numFAIL=$((numFAIL+1)) ;; + X2) $PRINTF "$FAILED: diff:\n" + echo "$SOCAT $opts $arg echo" + cat "${te}3" + echo "$SOCAT $opts - $arg2" + cat "${te}4" + cat "$tdiff2" + numFAIL=$((numFAIL+1)) ;; + esac + else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) + fi + wait +#set +vx +} + + +NAME=TCP4RANGEBITS +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%range%*|*%$NAME%*) +TEST="$NAME: security of TCP4-L with RANGE option" +testserversec "$N" "$TEST" "$opts -s" "tcp4-l:$PORT,reuseaddr,fork,retry=1" "" "range=$SECONDADDR/32" "tcp4:127.0.0.1:$PORT" 4 tcp $PORT 0 +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=TCP4RANGEMASK +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%range%*|*%$NAME%*) +TEST="$NAME: security of TCP4-L with RANGE option" +if [ "$UNAME" != Linux ]; then + # we need access to more loopback addresses + $PRINTF "test $F_n $TEST... ${YELLOW}only on Linux${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +testserversec "$N" "$TEST" "$opts -s" "tcp4-l:$PORT,reuseaddr,fork,retry=1" "" "range=127.0.0.0:255.255.0.0" "tcp4:127.1.0.0:$PORT" 4 tcp $PORT 0 +fi ;; # Linux +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=TCP4SOURCEPORT +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%sourceport%*|*%$NAME%*) +TEST="$NAME: security of TCP4-L with SOURCEPORT option" +testserversec "$N" "$TEST" "$opts -s" "tcp4-l:$PORT,reuseaddr,fork,retry=1" "" "sp=$PORT" "tcp4:127.0.0.1:$PORT" 4 tcp $PORT 0 +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=TCP4LOWPORT +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%lowport%*|*%$NAME%*) +TEST="$NAME: security of TCP4-L with LOWPORT option" +testserversec "$N" "$TEST" "$opts -s" "tcp4-l:$PORT,reuseaddr,fork,retry=1" "" "lowport" "tcp4:127.0.0.1:$PORT" 4 tcp $PORT 0 +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=TCP4WRAPPERS_ADDR +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%tcpwrap%*|*%$NAME%*) +TEST="$NAME: security of TCP4-L with TCPWRAP option" +if ! feat=$(testaddrs tcp ip4 libwrap) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +ha="$td/hosts.allow" +hd="$td/hosts.deny" +$ECHO "socat: $SECONDADDR" >"$ha" +$ECHO "ALL: ALL" >"$hd" +testserversec "$N" "$TEST" "$opts -s" "tcp4-l:$PORT,reuseaddr,fork,retry=1" "" "hosts-allow=$ha,hosts-deny=$hd" "tcp4:127.0.0.1:$PORT" 4 tcp $PORT 0 +fi ;; # feat +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=TCP4WRAPPERS_NAME +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%tcpwrap%*|*%$NAME%*) +TEST="$NAME: security of TCP4-L with TCPWRAP option" +if ! feat=$(testaddrs tcp ip4 libwrap) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +ha="$td/hosts.allow" +hd="$td/hosts.deny" +$ECHO "socat: $LOCALHOST" >"$ha" +$ECHO "ALL: ALL" >"$hd" +testserversec "$N" "$TEST" "$opts -s" "tcp4-l:$PORT,reuseaddr,fork,retry=1" "" "hosts-allow=$ha,hosts-deny=$hd" "tcp4:$SECONDADDR:$PORT" 4 tcp $PORT 0 +fi ;; # feat +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=TCP6RANGE +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%range%*|*%$NAME%*) +TEST="$NAME: security of TCP6-L with RANGE option" +if ! feat=$(testaddrs tcp ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +testserversec "$N" "$TEST" "$opts -s" "tcp6-l:$PORT,reuseaddr,fork,retry=1" "" "range=[::2/128]" "tcp6:[::1]:$PORT" 6 tcp $PORT 0 +fi # feat +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=TCP6SOURCEPORT +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%sourceport%*|*%$NAME%*) +TEST="$NAME: security of TCP6-L with SOURCEPORT option" +if ! feat=$(testaddrs tcp ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +testserversec "$N" "$TEST" "$opts -s" "tcp6-l:$PORT,reuseaddr,fork,retry=1" "" "sp=$PORT" "tcp6:[::1]:$PORT" 6 tcp $PORT 0 +fi # ! feat +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=TCP6LOWPORT +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%lowport%*|*%$NAME%*) +TEST="$NAME: security of TCP6-L with LOWPORT option" +if ! feat=$(testaddrs tcp ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +testserversec "$N" "$TEST" "$opts -s" "tcp6-l:$PORT,reuseaddr,fork,retry=1" "" "lowport" "tcp6:[::1]:$PORT" 6 tcp $PORT 0 +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=TCP6TCPWRAP +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%tcpwrap%*|*%$NAME%*) +TEST="$NAME: security of TCP6-L with TCPWRAP option" +if ! feat=$(testaddrs tcp ip6 libwrap) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +ha="$td/hosts.allow" +hd="$td/hosts.deny" +$ECHO "socat: [::2]" >"$ha" +$ECHO "ALL: ALL" >"$hd" +testserversec "$N" "$TEST" "$opts -s" "tcp6-l:$PORT,reuseaddr,fork,retry=1" "" "hosts-allow=$ha,hosts-deny=$hd" "tcp6:[::1]:$PORT" 6 tcp $PORT 0 +fi # ! feat +;; +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=UDP4RANGE +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%range%*|*%$NAME%*) +TEST="$NAME: security of UDP4-L with RANGE option" +#testserversec "$N" "$TEST" "$opts -s" "udp4-l:$PORT,reuseaddr,fork" "" "range=$SECONDADDR/32" "udp4:127.0.0.1:$PORT" 4 udp $PORT 0 +testserversec "$N" "$TEST" "$opts -s" "udp4-l:$PORT,reuseaddr" "" "range=$SECONDADDR/32" "udp4:127.0.0.1:$PORT" 4 udp $PORT 0 +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=UDP4SOURCEPORT +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%sourceport%*|*%$NAME%*) +TEST="$NAME: security of UDP4-L with SOURCEPORT option" +testserversec "$N" "$TEST" "$opts -s" "udp4-l:$PORT,reuseaddr" "" "sp=$PORT" "udp4:127.0.0.1:$PORT" 4 udp $PORT 0 +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=UDP4LOWPORT +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%lowport%*|*%$NAME%*) +TEST="$NAME: security of UDP4-L with LOWPORT option" +testserversec "$N" "$TEST" "$opts -s" "udp4-l:$PORT,reuseaddr" "" "lowport" "udp4:127.0.0.1:$PORT" 4 udp $PORT 0 +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=UDP4TCPWRAP +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%tcpwrap%*|*%$NAME%*) +TEST="$NAME: security of UDP4-L with TCPWRAP option" +if ! feat=$(testaddrs udp ip4 libwrap) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +ha="$td/hosts.allow" +hd="$td/hosts.deny" +$ECHO "socat: $SECONDADDR" >"$ha" +$ECHO "ALL: ALL" >"$hd" +testserversec "$N" "$TEST" "$opts -s" "udp4-l:$PORT,reuseaddr,retry=1" "" "tcpwrap-etc=$td" "udp4:127.0.0.1:$PORT" 4 udp $PORT 0 +fi ;; # feat +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=UDP6RANGE +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%range%*|*%$NAME%*) +TEST="$NAME: security of UDP6-L with RANGE option" +if ! feat=$(testaddrs tcp ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +#testserversec "$N" "$TEST" "$opts -s" "udp6-l:$PORT,reuseaddr,fork" "" "range=[::2/128]" "udp6:[::1]:$PORT" 6 udp $PORT 0 +testserversec "$N" "$TEST" "$opts -s" "udp6-l:$PORT,reuseaddr" "" "range=[::2/128]" "udp6:[::1]:$PORT" 6 udp $PORT 0 +fi # ! feat +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=UDP6SOURCEPORT +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%sourceport%*|*%$NAME%*) +TEST="$NAME: security of UDP6-L with SOURCEPORT option" +if ! feat=$(testaddrs udp ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}UDP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +testserversec "$N" "$TEST" "$opts -s" "udp6-l:$PORT,reuseaddr" "" "sp=$PORT" "udp6:[::1]:$PORT" 6 udp $PORT 0 +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=UDP6LOWPORT +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%lowport%*|*%$NAME%*) +TEST="$NAME: security of UDP6-L with LOWPORT option" +if ! feat=$(testaddrs udp ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}UDP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +testserversec "$N" "$TEST" "$opts -s" "udp6-l:$PORT,reuseaddr" "" "lowport" "udp6:[::1]:$PORT" 6 udp $PORT 0 +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=UDP6TCPWRAP +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%tcpwrap%*|*%$NAME%*) +TEST="$NAME: security of UDP6-L with TCPWRAP option" +if ! feat=$(testaddrs tcp ip6 libwrap) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +ha="$td/hosts.allow" +hd="$td/hosts.deny" +$ECHO "socat: [::2]" >"$ha" +$ECHO "ALL: ALL" >"$hd" +testserversec "$N" "$TEST" "$opts -s" "udp6-l:$PORT,reuseaddr" "" "lowport" "udp6:[::1]:$PORT" 6 udp $PORT 0 +fi ;; # feat +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=OPENSSLTCP4_RANGE +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%openssl%*|*%range%*|*%$NAME%*) +TEST="$NAME: security of SSL-L over TCP/IPv4 with RANGE option" +if ! testaddrs openssl >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +gentestcert testsrv +testserversec "$N" "$TEST" "$opts -s" "ssl-l:$PORT,pf=ip4,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "range=$SECONDADDR/32" "ssl:127.0.0.1:$PORT,cafile=testsrv.crt,$SOCAT_EGD" 4 tcp $PORT -1 +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=OPENSSLTCP4_SOURCEPORT +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%openssl%*|*%sourceport%*|*%$NAME%*) +TEST="$NAME: security of SSL-L with SOURCEPORT option" +if ! testaddrs openssl >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +gentestcert testsrv +testserversec "$N" "$TEST" "$opts -s" "ssl-l:$PORT,pf=ip4,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "sp=$PORT" "ssl:127.0.0.1:$PORT,cafile=testsrv.crt,$SOCAT_EGD" 4 tcp $PORT -1 +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=OPENSSLTCP4_LOWPORT +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%openssl%*|*%lowport%*|*%$NAME%*) +TEST="$NAME: security of SSL-L with LOWPORT option" +if ! testaddrs openssl >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +gentestcert testsrv +testserversec "$N" "$TEST" "$opts -s" "ssl-l:$PORT,pf=ip4,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "lowport" "ssl:127.0.0.1:$PORT,cafile=testsrv.crt,$SOCAT_EGD" 4 tcp $PORT -1 +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=OPENSSLTCP4_TCPWRAP +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%openssl%*|*%tcpwrap%*|*%$NAME%*) +TEST="$NAME: security of SSL-L with TCPWRAP option" +if ! feat=$(testaddrs ip4 tcp libwrap openssl); then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +gentestcert testsrv +ha="$td/hosts.allow" +hd="$td/hosts.deny" +$ECHO "socat: $SECONDADDR" >"$ha" +$ECHO "ALL: ALL" >"$hd" +testserversec "$N" "$TEST" "$opts -s" "ssl-l:$PORT,pf=ip4,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "tcpwrap-etc=$td" "ssl:127.0.0.1:$PORT,cafile=testsrv.crt,$SOCAT_EGD" 4 tcp $PORT -1 +fi ;; # feat +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=OPENSSLCERTSERVER +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%openssl%*|*%$NAME%*) +TEST="$NAME: security of SSL-L with client certificate" +if ! testaddrs openssl >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +gentestcert testsrv +gentestcert testcli +testserversec "$N" "$TEST" "$opts -s" "ssl-l:$PORT,pf=ip4,reuseaddr,fork,retry=1,$SOCAT_EGD,verify,cert=testsrv.crt,key=testsrv.key" "cafile=testcli.crt" "cafile=testsrv.crt" "ssl:127.0.0.1:$PORT,cafile=testsrv.crt,cert=testcli.pem,$SOCAT_EGD" 4 tcp $PORT -1 +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=OPENSSLCERTCLIENT +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%openssl%*|*%$NAME%*) +TEST="$NAME: security of SSL with server certificate" +if ! testaddrs openssl >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +gentestcert testsrv +gentestcert testcli +testserversec "$N" "$TEST" "$opts -s -lu -d" "ssl:$LOCALHOST:$PORT,pf=ip4,fork,retry=2,verify,cert=testcli.pem,$SOCAT_EGD" "cafile=testsrv.crt" "cafile=testcli.crt" "ssl-l:$PORT,pf=ip4,reuseaddr,$SOCAT_EGD,cafile=testcli.crt,cert=testsrv.crt,key=testsrv.key" 4 tcp "" -1 +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=OPENSSLTCP6_RANGE +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%openssl%*|*%range%*|*%$NAME%*) +TEST="$NAME: security of SSL-L over TCP/IPv6 with RANGE option" +if ! testaddrs openssl >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! feat=$(testaddrs tcp ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +gentestcert testsrv +testserversec "$N" "$TEST" "$opts -s" "ssl-l:$PORT,pf=ip6,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "range=[::2/128]" "ssl:[::1]:$PORT,cafile=testsrv.crt,$SOCAT_EGD" 6 tcp $PORT -1 +fi # ! feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=OPENSSLTCP6_SOURCEPORT +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%openssl%*|*%sourceport%*|*%$NAME%*) +TEST="$NAME: security of SSL-L over TCP/IPv6 with SOURCEPORT option" +if ! testaddrs openssl >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! feat=$(testaddrs tcp ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +gentestcert testsrv +testserversec "$N" "$TEST" "$opts -s" "ssl-l:$PORT,pf=ip6,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "sp=$PORT" "ssl:[::1]:$PORT,cafile=testsrv.crt,$SOCAT_EGD" 6 tcp $PORT -1 +fi # ! feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=OPENSSLTCP6_LOWPORT +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%openssl%*|*%lowport%*|*%$NAME%*) +TEST="$NAME: security of SSL-L over TCP/IPv6 with LOWPORT option" +if ! testaddrs openssl >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! feat=$(testaddrs tcp ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +gentestcert testsrv +testserversec "$N" "$TEST" "$opts -s" "ssl-l:$PORT,pf=ip6,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "lowport" "ssl:[::1]:$PORT,cafile=testsrv.crt,$SOCAT_EGD" 6 tcp $PORT -1 +fi # ! feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=OPENSSLTCP6_TCPWRAP +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%openssl%*|*%tcpwrap%*|*%$NAME%*) +TEST="$NAME: security of SSL-L over TCP/IPv6 with TCPWRAP option" +if ! feat=$(testaddrs ip6 tcp libwrap openssl) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +gentestcert testsrv +ha="$td/hosts.allow" +hd="$td/hosts.deny" +$ECHO "socat: [::2]" >"$ha" +$ECHO "ALL: ALL" >"$hd" +testserversec "$N" "$TEST" "$opts -s" "ssl-l:$PORT,pf=ip6,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "tcpwrap-etc=$td" "ssl:[::1]:$PORT,cafile=testsrv.crt,$SOCAT_EGD" 6 tcp $PORT -1 +fi # ! feat +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=OPENSSL_FIPS_SECURITY +case "$TESTS" in +*%functions%*|*%security%*|*%openssl%*|*%fips%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*) +TEST="$NAME: OpenSSL restrictions by FIPS" +if ! testaddrs openssl >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testaddrs listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! testoptions fips >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL/FIPS not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +gentestcert testsrv +gentestcert testcli +# openssl client accepts a "normal" certificate only when not in fips mode +testserversec "$N" "$TEST" "$opts -s" "ssl:$LOCALHOST:$PORT,fork,retry=2,verify,cafile=testsrv.crt" "" "fips" "ssl-l:$PORT,pf=ip4,reuseaddr,cert=testsrv.crt,key=testsrv.key" 4 tcp "" -1 +fi ;; # testaddrs +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=UNIEXECEOF +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: give exec'd write-only process a chance to flush (-u)" +testod "$N" "$TEST" "" exec:'od -c' "$opts -u" +esac +N=$((N+1)) + + +NAME=REVEXECEOF +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: give exec'd write-only process a chance to flush (-U)" +testod "$N" "$TEST" exec:'od -c' "-" "$opts -U" +esac +N=$((N+1)) + + +NAME=FILANDIR +case "$TESTS" in +*%filan%*|*%$NAME%*) +TEST="$NAME: check type printed for directories" +te="$td/test$N.stderr" +printf "test $F_n $TEST... " $N +type=$($FILAN -f . 2>$te |tail -n 1 |awk '{print($2);}') +if [ "$type" = "dir" ]; then + $PRINTF "$OK\n" + numOK=$((numOK+1)) +else + $PRINTF "$FAILED\n" + cat "$te" + numFAIL=$((numFAIL+1)) +fi +esac +N=$((N+1)) + + +NAME=FILANSOCKET +case "$TESTS" in +*%filan%*|*%$NAME%*) +TEST="$NAME: capability to analyze named unix socket" +ts="$td/test$N.socket" +te1="$td/test$N.stderr1" # socat +te2="$td/test$N.stderr2" # filan +printf "test $F_n $TEST... " $N +$SOCAT unix-l:"$ts" /dev/null "$te1" & +spid=$! +waitfile "$ts" 1 +type=$($FILAN -f "$ts" 2>$te2 |tail -n 1 |awk '{print($2);}') +if [ "$type" = "socket" ]; then + $PRINTF "$OK\n" + numOK=$((numOK+1)) +else + $PRINTF "$FAILED\n" + cat "$te1" + cat "$te2" + numFAIL=$((numFAIL+1)) +fi +kill $spid 2>/dev/null +wait +;; +esac +N=$((N+1)) + + +testptywaitslave () { + local N="$1" + local TEST="$2" + local PTYTYPE="$3" # ptmx or openpty + local opts="$4" + +tp="$td/test$N.pty" +ts="$td/test$N.socket" +tf="$td/test$N.file" +tdiff="$td/test$N.diff" +te1="$td/test$N.stderr1" +te2="$td/test$N.stderr2" +te3="$td/test$N.stderr3" +te4="$td/test$N.stderr4" +da="test$N.1 $(date) $RANDOM" +printf "test $F_n $TEST... " $N +# first generate a pty, then a socket +($SOCAT $opts -lpsocat1 pty,$PTYTYPE,pty-wait-slave,link="$tp" unix-listen:"$ts" 2>"$te1"; rm -f "$tp") 2>/dev/null & +pid=$! +waitfile "$tp" +# if pty was non-blocking, the socket is active, and socat1 will term +$SOCAT $opts -T 10 -lpsocat2 file:/dev/null unix-connect:"$ts" 2>"$te2" +# if pty is blocking, first socat is still active and we get a connection now +#((echo "$da"; sleep 2) |$SOCAT -lpsocat3 $opts - file:"$tp",$PTYOPTS2 >"$tf" 2>"$te3") & +( (waitfile "$ts"; echo "$da"; sleep 1) |$SOCAT -lpsocat3 $opts - file:"$tp",$PTYOPTS2 >"$tf" 2>"$te3") & +waitfile "$ts" +# but we need an echoer on the socket +$SOCAT $opts -lpsocat4 unix:"$ts" echo 2>"$te4" +# now $tf file should contain $da +#kill $pid 2>/dev/null +wait +# +if echo "$da" |diff - "$tf"> "$tdiff"; then + $PRINTF "$OK\n" + numOK=$((numOK+1)) +else + $PRINTF "${YELLOW}FAILED${NORMAL}\n" + cat "$te1" + #cat "$te2" # not of interest + cat "$te3" + cat "$te4" + cat "$tdiff" + numCANT=$((numCANT+1)) +fi +} + +NAME=PTMXWAITSLAVE +PTYTYPE=ptmx +case "$TESTS" in +*%functions%*|*%pty%*|*%$NAME%*) +TEST="$NAME: test if master pty ($PTYTYPE) waits for slave connection" +if ! feat=$(testaddrs pty); then + $PRINTF "test $F_n $TEST... ${YELLOW}$(echo $feat| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! feat=$(testoptions "$PTYTYPE" pty-wait-slave); then + $PRINTF "test $F_n $TEST... ${YELLOW}option $(echo $feat| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else + testptywaitslave "$N" "$TEST" "$PTYTYPE" "$opts" +fi +esac +N=$((N+1)) + +NAME=OPENPTYWAITSLAVE +PTYTYPE=openpty +case "$TESTS" in +*%functions%*|*%pty%*|*%$NAME%*) +TEST="$NAME: test if master pty ($PTYTYPE) waits for slave connection" +if ! feat=$(testaddrs pty); then + $PRINTF "test $F_n $TEST... ${YELLOW}$(echo $feat| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! feat=$(testoptions "$PTYTYPE" pty-wait-slave); then + $PRINTF "test $F_n $TEST... ${YELLOW}option $(echo $feat| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else + testptywaitslave "$N" "$TEST" "$PTYTYPE" "$opts" +fi +esac +N=$((N+1)) + + +NAME=CONNECTTIMEOUT +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: test the connect-timeout option" +if ! feat=$(testaddrs tcp); then + $PRINTF "test $F_n $TEST... ${YELLOW}$(echo $feat| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif ! feat=$(testoptions connect-timeout); then + $PRINTF "test $F_n $TEST... ${YELLOW}$(echo $feat| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +# we need a hanging connection attempt, guess an address for this +case "$UNAME" in +Linux) HANGIP=1.0.0.1 ;; +*) HANGIP=255.255.255.254 ;; +esac +te1="$td/test$N.stderr1" +tk1="$td/test$N.kill1" +te2="$td/test$N.stderr2" +tk2="$td/test$N.kill2" +$PRINTF "test $F_n $TEST... " $N +# first, try to make socat hang and see if it can be killed +#$SOCAT $opts - tcp:$HANGIP:1 >"$te1" 2>&1 "$te1" 2>&1 "$tk1"; then + $PRINTF "${YELLOW}does not hang${NORMAL}\n" + numCANT=$((numCANT+1)) +else +# second, set connect-timeout and see if socat exits before kill +$SOCAT $opts - tcp:$HANGIP:1,connect-timeout=1.0 >"$te2" 2>&1 "$tk2"; then + $PRINTF "$FAILED\n" + echo "$CMD" + cat "$te1" + cat "$te2" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + numOK=$((numOK+1)) +fi +fi +wait +fi ;; # testaddrs +esac +N=$((N+1)) + + +NAME=OPENSSLLISTENDSA +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: openssl listen with DSA certificate" +if ! testaddrs openssl >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +SRVCERT=testsrvdsa +gentestdsacert $SRVCERT +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da=$(date) +CMD2="$SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip4,reuseaddr,$SOCAT_EGD,cert=$SRVCERT.pem,key=$SRVCERT.key,verify=0 pipe" +CMD="$SOCAT $opts - openssl:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD" +$PRINTF "test $F_n $TEST... " $N +eval "$CMD2 2>\"${te}1\" &" +pid=$! # background process id +waittcp4port $PORT +echo "$da" |$CMD >$tf 2>"${te}2" +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + echo "$CMD2 &" + echo "$CMD" + cat "${te}1" + cat "${te}2" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat ${te}1 ${te}2; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +wait +fi ;; # testaddrs +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +# derive signal number from signal name +# kill -l should provide the info +signum () { + if [ ! "$BASH_VERSION" ]; then + # we expect: + for i in $(kill -l); do echo $i; done |grep -n -i $1 |cut -d: -f1 + else + # expect: + # " 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL" + signam="$1" + kill -l $tpp"'; echo \$$ '">$tp; read x\"",nofork 2>"$te"; stat=$? +tsh="$td/test$N.sh" +cat <"$tsh" +#! /bin/bash +echo \$PPID >"$tpp" +echo \$\$ >"$tp" +read x +EOF +chmod a+x "$tsh" +$SOCAT $opts echo system:"exec \"$tsh\"",pty,setsid,nofork 2>"$te"; stat=$? +sleep 1; kill -INT $(cat $tp) +wait +if [ "$stat" -eq $((128+$SIG)) ]; then + $PRINTF "$OK\n" + numOK=$((numOK+1)) +else + $PRINTF "$FAILED\n" + cat "$te" + numFAIL=$((numFAIL+1)) +fi +wait +fi ;; # feat +esac +N=$((N+1)) +done + + +NAME=READBYTES +#set -vx +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: restrict reading from file with bytes option" +if false; then + $PRINTF "test $F_n $TEST... ${YELLOW}$(echo $feat| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tr="$td/test$N.ref" +ti="$td/test$N.in" +to="$td/test$N.out" +te="$td/test$N.err" +tdiff="$td/test$N.diff" +da="$(date)" da="$da$($ECHO '\r')" +# the feature that we really want to test is in the readline.sh script: +CMD="$SOCAT $opts -u open:$ti,readbytes=100 -" +printf "test $F_n $TEST... " $N +rm -f "$tf" "$ti" "$to" +# +echo "AAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAA" >"$tr" # 100 bytes +cat "$tr" "$tr" >"$ti" # 200 bytes +$CMD >"$to" 2>"$te" +if ! diff "$tr" "$to" >"$tdiff" 2>&1; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD" + cat "$te" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +fi +esac +N=$((N+1)) + + +NAME=UNIXLISTENFORK +case "$TESTS" in +*%functions%*|*%unix%*|*%listen%*|*%fork%*|*%$NAME%*) +TEST="$NAME: UNIX socket keeps listening after child died" +if false; then + : +else +ts="$td/test$N.socket" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da1="test$N $(date) $RANDOM" +da2="test$N $(date) $RANDOM" +#establish a listening and forking unix socket in background +SRV="$SOCAT $opts -lpserver UNIX-LISTEN:\"$ts\",fork PIPE" +#make a first and a second connection +CLI="$SOCAT $opts -lpclient - UNIX-CONNECT:\"$ts\"" +$PRINTF "test $F_n $TEST... " $N +eval "$SRV 2>${te}s &" +pids=$! +waitfile "$ts" +echo "$da1" |eval "$CLI" >"${tf}1" 2>"${te}1" +if [ $? -ne 0 ]; then + kill "$pids" 2>/dev/null + $PRINTF "$NO_RESULT (first conn failed):\n" + echo "$SRV &" + echo "$CLI" + cat "${te}s" "${te}1" + numCANT=$((numCANT+1)) +elif ! echo "$da1" |diff - "${tf}1" >"$tdiff"; then + kill "$pids" 2>/dev/null + $PRINTF "$NO_RESULT (first conn failed); diff:\n" + cat "$tdiff" + numCANT=$((numCANT+1)) +else +echo "$da2" |eval "$CLI" >"${tf}2" 2>"${te}2" +rc="$?"; kill "$pids" 2>/dev/null +if [ $rc -ne 0 ]; then + $PRINTF "$FAILED:\n" + echo "$SRV &" + echo "$CLI" + cat "${te}s" "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da2" |diff - "${tf}2" >"$tdiff"; then + $PRINTF "$FAILED: diff\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + numOK=$((numOK+1)) +fi # !( $? -ne 0) +fi # !(rc -ne 0) +wait +fi # true +esac +N=$((N+1)) + + +NAME=UNIXTOSTREAM +case "$TESTS" in +*%functions%*|*%unix%*|*%listen%*|*%$NAME%*) +TEST="$NAME: generic UNIX client connects to stream socket" +if false; then + : +else +ts="$td/test$N.socket" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da1="test$N $(date) $RANDOM" +#establish a listening unix socket in background +SRV="$SOCAT $opts -lpserver UNIX-LISTEN:\"$ts\" PIPE" +#make a connection +CLI="$SOCAT $opts -lpclient - UNIX:\"$ts\"" +$PRINTF "test $F_n $TEST... " $N +eval "$SRV 2>${te}s &" +pids=$! +waitfile "$ts" +echo "$da1" |eval "$CLI" >"${tf}1" 2>"${te}1" +if [ $? -ne 0 ]; then + kill "$pids" 2>/dev/null + $PRINTF "$FAILED:\n" + echo "$SRV &" + echo "$CLI" + cat "${te}s" "${te}1" + numFAIL=$((numFAIL+1)) +elif ! echo "$da1" |diff - "${tf}1" >"$tdiff"; then + kill "$pids" 2>/dev/null + $PRINTF "$FAILED; diff:\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + numOK=$((numOK+1)) +fi # !(rc -ne 0) +wait +fi # true +wait +esac +N=$((N+1)) + + +NAME=UNIXTODGRAM +case "$TESTS" in +*%functions%*|*%unix%*|*%recv%*|*%$NAME%*) +TEST="$NAME: generic UNIX client connects to datagram socket" +if false; then + : +else +ts1="$td/test$N.socket1" +ts2="$td/test$N.socket2" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da1="test$N $(date) $RANDOM" +#establish a receiving unix datagram socket in background +SRV="$SOCAT $opts -lpserver UNIX-RECVFROM:\"$ts1\" PIPE" +#make a connection +CLI="$SOCAT $opts -lpclient - UNIX:\"$ts1\",bind=\"$ts2\"" +#CLI="$SOCAT $opts -lpclient - UNIX:\"$ts1\"" +$PRINTF "test $F_n $TEST... " $N +eval "$SRV 2>${te}s &" +pids=$! +waitfile "$ts1" +echo "$da1" |eval "$CLI" >"${tf}1" 2>"${te}1" +if [ $? -ne 0 ]; then + kill "$pids" 2>/dev/null + $PRINTF "$FAILED:\n" + echo "$SRV &" + cat "${te}s" + echo "$CLI" + cat "${te}1" "${te}1" + numFAIL=$((numFAIL+1)) +elif ! echo "$da1" |diff - "${tf}1" >"$tdiff"; then + kill "$pids" 2>/dev/null + $PRINTF "$FAILED:\n" + echo "$SRV &" + cat "${te}s" + echo "$CLI" + cat "${te}1" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + numOK=$((numOK+1)) +fi # !(rc -ne 0) +wait +fi # true +esac +N=$((N+1)) + + +NAME=EXECPIPESSTDERR +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: simple echo via exec of cat with pipes,stderr" +testecho "$N" "$TEST" "" "exec:$CAT,pipes,stderr" "$opts" +esac +N=$((N+1)) + + +NAME=SIMPLEPARSE +case "$TESTS" in +*%functions%*|*%PARSE%*|*%$NAME%*) +TEST="$NAME: invoke socat from socat" +testecho "$N" "$TEST" "" exec:"$SOCAT - exec\:$CAT,pipes" "$opts" +esac +N=$((N+1)) + + +NAME=FULLPARSE +case "$TESTS" in +*%functions%*|*%parse%*|*%$NAME%*) +TEST="$NAME: correctly parse special chars" +$PRINTF "test $F_n $TEST... " $N +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +# a string where commas are hidden in nesting lexical constructs +# if they are scanned incorrectly, socat will see an "unknown option" +dain='(,)[,]{,}","([),])hugo' +daout='(,)[,]{,},([),])hugo' +"$SOCAT" $opts -u "exec:echo $dain" - >"$tf" 2>"$te" +rc=$? +echo "$daout" |diff "$tf" - >"$tdiff" +if [ "$rc" -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$SOCAT" -u "exec:echo $da" - + cat "$te" + numFAIL=$((numFAIL+1)) +elif [ -s "$tdiff" ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo diff: + cat "$tdiff" + if [ -n "$debug" ]; then cat $te; fi + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +esac +N=$((N+1)) + +NAME=NESTEDSOCATEXEC +case "$TESTS" in +*%parse%*|*%functions%*|*%$NAME%*) +TEST="$NAME: does lexical analysis work sensibly (exec)" +testecho "$N" "$TEST" "" "exec:'$SOCAT - exec:$CAT,pipes'" "$opts" 1 +esac +N=$((N+1)) + +NAME=NESTEDSOCATSYSTEM +case "$TESTS" in +*%parse%*|*%functions%*|*%$NAME%*) +TEST="$NAME: does lexical analysis work sensibly (system)" +testecho "$N" "$TEST" "" "system:\"$SOCAT - exec:$CAT,pipes\"" "$opts" 1 +esac +N=$((N+1)) + + +NAME=TCP6BYTCP4 +case "$TESTS" in +*%functions%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%$NAME%*) +TEST="$NAME: TCP4 mapped into TCP6 address space" +if ! testaddrs tcp ip6 >/dev/null || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +tsl=$PORT +ts="127.0.0.1:$tsl" +da=$(date) +CMD1="$SOCAT $opts TCP6-listen:$tsl,reuseaddr PIPE" +CMD2="$SOCAT $opts stdin!!stdout TCP6:$ts" +printf "test $F_n $TEST... " $N +$CMD1 >"$tf" 2>"${te}1" & +pid=$! # background process id +waittcp6port $tsl 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: diff:\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null; wait +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=UDP4DGRAM +case "$TESTS" in +*%functions%*|*%udp%*|*%udp4%*|*%ip4%*|*%dgram%*|*%$NAME%*) +TEST="$NAME: UDP/IPv4 datagram" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +ts1p=$PORT; PORT=$((PORT+1)) +ts1a="127.0.0.1" +ts1="$ts1a:$ts1p" +ts2p=$PORT; PORT=$((PORT+1)) +ts2="127.0.0.1:$ts2p" +da=$(date) +CMD1="$SOCAT $opts UDP4-RECVFROM:$ts1p,reuseaddr,bind=$ts1a PIPE" +CMD2="$SOCAT $opts - UDP4-SENDTO:$ts1,bind=$ts2" +printf "test $F_n $TEST... " $N +$CMD1 2>"${te}1" & +pid1="$!" +waitudp4port $ts1p 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +rc2="$?" +kill "$pid1" 2>/dev/null; wait; +if [ "$rc2" -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi ;; +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=UDP6DGRAM +case "$TESTS" in +*%functions%*|*%udp%*|*%udp6%*|*%ip6%*|*%dgram%*|*%$NAME%*) +TEST="$NAME: UDP/IPv6 datagram" +if ! feat=$(testaddrs tcp ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +ts1p=$PORT; PORT=$((PORT+1)) +tsa="[::1]" +ts1="$tsa:$ts1p" +ts2p=$PORT; PORT=$((PORT+1)) +ts2="$tsa:$ts2p" +da=$(date) +CMD1="$SOCAT $opts UDP6-RECVFROM:$ts1p,reuseaddr,bind=$tsa PIPE" +CMD2="$SOCAT $opts - UDP6-SENDTO:$ts1,bind=$ts2" +printf "test $F_n $TEST... " $N +$CMD1 2>"${te}1" & +waitudp6port $ts1p 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat ${te}1 ${te}2; fi + numOK=$((numOK+1)) +fi +fi ;; # ! feat +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=RAWIP4RECVFROM +case "$TESTS" in +*%functions%*|*%ip%*|*%ip4%*|*%rawip%*|*%rawip4%*|*%dgram%*|*%root%*|*%$NAME%*) +TEST="$NAME: raw IPv4 datagram" +if [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +ts1p=$PROTO; PROTO=$((PROTO+1)) +ts1a="127.0.0.1" +ts1="$ts1a:$ts1p" +ts2a="$SECONDADDR" +ts2="$ts2a:$ts2p" +da=$(date) +CMD1="$SOCAT $opts IP4-RECVFROM:$ts1p,reuseaddr,bind=$ts1a PIPE" +CMD2="$SOCAT $opts - IP4-SENDTO:$ts1,bind=$ts2a" +printf "test $F_n $TEST... " $N +$CMD1 2>"${te}1" & +pid1=$! +waitip4proto $ts1p 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +rc2=$? +kill $pid1 2>/dev/null; wait +if [ $rc2 -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +fi # must be root;; +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +if false; then +NAME=RAWIP6RECVFROM +case "$TESTS" in +*%functions%*|*%ip%*|*%ip6%*|*%rawip%*|*%rawip6%*|*%dgram%*|*%root%*|*%$NAME%*) +TEST="$NAME: raw IPv6 datagram by self addressing" +if [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +ts1p=$PROTO; PROTO=$((PROTO+1)) +tsa="[::1]" +ts1="$tsa:$ts1p" +ts2="$tsa" +da=$(date) +#CMD1="$SOCAT $opts IP6-RECVFROM:$ts1p,reuseaddr,bind=$tsa PIPE" +CMD2="$SOCAT $opts - IP6-SENDTO:$ts1,bind=$ts2" +printf "test $F_n $TEST... " $N +#$CMD1 2>"${te}1" & +waitip6proto $ts1p 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" +# echo "$CMD1 &" +# cat "${te}1" + echo "$CMD2" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "$te"; fi + numOK=$((numOK+1)) +fi +fi # must be root ;; +esac +PORT=$((PORT+1)) +N=$((N+1)) +fi #false + + +NAME=UNIXDGRAM +case "$TESTS" in +*%functions%*|*%unix%*|*%dgram%*|*%$NAME%*) +TEST="$NAME: UNIX datagram" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +ts1="$td/test$N.socket1" +ts2="$td/test$N.socket2" +da=$(date) +CMD1="$SOCAT $opts UNIX-RECVFROM:$ts1,reuseaddr PIPE" +CMD2="$SOCAT $opts - UNIX-SENDTO:$ts1,bind=$ts2" +printf "test $F_n $TEST... " $N +$CMD1 2>"${te}1" & +pid1="$!" +waitfile $ts1 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +rc2=$? +kill "$pid1" 2>/dev/null; wait +if [ $rc2 -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + cat "${te}1" + echo "$CMD2" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi ;; +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=UDP4RECV +case "$TESTS" in +*%functions%*|*%ip4%*|*%dgram%*|*%udp%*|*%udp4%*|*%recv%*|*%$NAME%*) +TEST="$NAME: UDP/IPv4 receive" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +ts1p=$PORT; PORT=$((PORT+1)) +ts1a="127.0.0.1" +ts1="$ts1a:$ts1p" +da=$(date) +CMD1="$SOCAT $opts -u UDP4-RECV:$ts1p,reuseaddr -" +CMD2="$SOCAT $opts -u - UDP4-SENDTO:$ts1" +printf "test $F_n $TEST... " $N +$CMD1 >"$tf" 2>"${te}1" & +pid1="$!" +waitudp4port $ts1p 1 +echo "$da" |$CMD2 2>>"${te}2" +rc2="$?" +#ls -l $tf +i=0; while [ ! -s "$tf" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done +kill "$pid1" 2>/dev/null; wait +if [ "$rc2" -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi ;; +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=UDP6RECV +case "$TESTS" in +*%functions%*|*%ip6%*|*%dgram%*|*%udp%*|*%udp6%*|*%recv%*|*%$NAME%*) +TEST="$NAME: UDP/IPv6 receive" +if ! feat=$(testaddrs tcp ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +ts1p=$PORT; PORT=$((PORT+1)) +ts1a="[::1]" +ts1="$ts1a:$ts1p" +da=$(date) +CMD1="$SOCAT $opts -u UDP6-RECV:$ts1p,reuseaddr -" +CMD2="$SOCAT $opts -u - UDP6-SENDTO:$ts1" +printf "test $F_n $TEST... " $N +$CMD1 >"$tf" 2>"${te}1" & +pid1="$!" +waitudp6port $ts1p 1 +echo "$da" |$CMD2 2>>"${te}2" +rc2="$?" +#ls -l $tf +i=0; while [ ! -s "$tf" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done +kill "$pid1" 2>/dev/null; wait +if [ "$rc2" -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +fi ;; # ! feat +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=RAWIP4RECV +case "$TESTS" in +*%functions%*|*%ip4%*|*%dgram%*|*%rawip%*|*%rawip4%*|*%recv%*|*%root%*|*%$NAME%*) +TEST="$NAME: raw IPv4 receive" +if [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +ts1p=$PROTO; PROTO=$((PROTO+1)) +ts1a="127.0.0.1" +ts1="$ts1a:$ts1p" +da=$(date) +CMD1="$SOCAT $opts -u IP4-RECV:$ts1p,reuseaddr -" +CMD2="$SOCAT $opts -u - IP4-SENDTO:$ts1" +printf "test $F_n $TEST... " $N +$CMD1 >"$tf" 2>"${te}1" & +pid1="$!" +waitip4proto $ts1p 1 +echo "$da" |$CMD2 2>>"${te}2" +rc2="$?" +#ls -l $tf +i=0; while [ ! -s "$tf" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done +kill "$pid1" 2>/dev/null; wait +if [ "$rc2" -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +fi # must be root ;; +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=RAWIP6RECV +case "$TESTS" in +*%functions%*|*%ip6%*|*%dgram%*|*%rawip%*|*%rawip6%*|*%recv%*|*%root%*|*%$NAME%*) +TEST="$NAME: raw IPv6 receive" +if ! feat=$(testaddrs ip6 rawip) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +ts1p=$PROTO; PROTO=$((PROTO+1)) +ts1a="[::1]" +ts1="$ts1a:$ts1p" +da=$(date) +CMD1="$SOCAT $opts -u IP6-RECV:$ts1p,reuseaddr -" +CMD2="$SOCAT $opts -u - IP6-SENDTO:$ts1" +printf "test $F_n $TEST... " $N +$CMD1 >"$tf" 2>"${te}1" & +pid1="$!" +waitip6proto $ts1p 1 +echo "$da" |$CMD2 2>>"${te}2" +rc2="$?" +i=0; while [ ! -s "$tf" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done +kill "$pid1" 2>/dev/null; wait +if [ "$rc2" -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +fi # must be root ;; +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=UNIXRECV +case "$TESTS" in +*%functions%*|*%unix%*|*%dgram%*|*%recv%*|*%$NAME%*) +TEST="$NAME: UNIX receive" +ts="$td/test$N.socket" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +ts1="$ts" +da=$(date) +CMD1="$SOCAT $opts -u UNIX-RECV:$ts1,reuseaddr -" +CMD2="$SOCAT $opts -u - UNIX-SENDTO:$ts1" +printf "test $F_n $TEST... " $N +$CMD1 >"$tf" 2>"${te}1" & +pid1="$!" +waitfile $ts1 1 +echo "$da" |$CMD2 2>>"${te}2" +rc2="$?" +i=0; while [ ! -s "$tf" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done +kill "$pid1" 2>/dev/null; wait +if [ "$rc2" -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi ;; +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=UDP4RECVFROM_SOURCEPORT +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%sourceport%*|*%$NAME%*) +TEST="$NAME: security of UDP4-RECVFROM with SOURCEPORT option" +if ! feat=$(testaddrs udp ip4) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}UDP4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +testserversec "$N" "$TEST" "$opts -s" "udp4-recvfrom:$PORT,reuseaddr" "" "sp=$PORT" "udp4-sendto:127.0.0.1:$PORT" 4 udp $PORT 0 +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=UDP4RECVFROM_LOWPORT +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%lowport%*|*%$NAME%*) +TEST="$NAME: security of UDP4-RECVFROM with LOWPORT option" +if ! feat=$(testaddrs udp ip4) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}UDP4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +testserversec "$N" "$TEST" "$opts -s" "udp4-recvfrom:$PORT,reuseaddr" "" "lowport" "udp4-sendto:127.0.0.1:$PORT" 4 udp $PORT 0 +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=UDP4RECVFROM_RANGE +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%range%*|*%$NAME%*) +TEST="$NAME: security of UDP4-RECVFROM with RANGE option" +#testserversec "$N" "$TEST" "$opts -s" "udp4-recvfrom:$PORT,reuseaddr,fork" "" "range=$SECONDADDR/32" "udp4-sendto:127.0.0.1:$PORT" 4 udp $PORT 0 +testserversec "$N" "$TEST" "$opts -s" "udp4-recvfrom:$PORT,reuseaddr" "" "range=$SECONDADDR/32" "udp4-sendto:127.0.0.1:$PORT" 4 udp $PORT 0 +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=UDP4RECVFROM_TCPWRAP +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%tcpwrap%*|*%$NAME%*) +TEST="$NAME: security of UDP4-RECVFROM with TCPWRAP option" +if ! feat=$(testaddrs ip4 udp libwrap) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +ha="$td/hosts.allow" +hd="$td/hosts.deny" +$ECHO "socat: $SECONDADDR" >"$ha" +$ECHO "ALL: ALL" >"$hd" +#testserversec "$N" "$TEST" "$opts -s" "udp4-recvfrom:$PORT,reuseaddr,fork" "" "tcpwrap=$d" "udp4-sendto:127.0.0.1:$PORT" 4 udp $PORT 0 +testserversec "$N" "$TEST" "$opts -s" "udp4-recvfrom:$PORT,reuseaddr" "" "tcpwrap-etc=$td" "udp4-sendto:127.0.0.1:$PORT" 4 udp $PORT 0 +fi ;; # feat +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=UDP4RECV_SOURCEPORT +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%sourceport%*|*%$NAME%*) +TEST="$NAME: security of UDP4-RECV with SOURCEPORT option" +if ! feat=$(testaddrs udp ip4) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}UDP4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +PORT1=$PORT; PORT=$((PORT+1)) +PORT2=$PORT; PORT=$((PORT+1)) +PORT3=$PORT +# we use the forward channel (PORT1) for testing, and have a backward channel +# (PORT2) to get the data back, so we get the classical echo behaviour +testserversec "$N" "$TEST" "$opts -s" "udp4-recv:$PORT1,reuseaddr!!udp4-sendto:127.0.0.1:$PORT2" "" "sp=$PORT3" "udp4-recv:$PORT2!!udp4-sendto:127.0.0.1:$PORT1" 4 udp $PORT1 0 +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=UDP4RECV_LOWPORT +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%lowport%*|*%$NAME%*) +TEST="$NAME: security of UDP4-RECV with LOWPORT option" +if ! feat=$(testaddrs udp ip4) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}UDP4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +PORT1=$PORT; PORT=$((PORT+1)) +PORT2=$PORT +# we use the forward channel (PORT1) for testing, and have a backward channel +# (PORT2) to get the data back, so we get the classical echo behaviour +testserversec "$N" "$TEST" "$opts -s" "udp4-recv:$PORT1,reuseaddr!!udp4-sendto:127.0.0.1:$PORT2" "" "lowport" "udp4-recv:$PORT2!!udp4-sendto:127.0.0.1:$PORT1" 4 udp $PORT1 0 +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=UDP4RECV_RANGE +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%range%*|*%$NAME%*) +TEST="$NAME: security of UDP4-RECV with RANGE option" +if ! feat=$(testaddrs udp ip4) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}UDP4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +PORT1=$PORT; PORT=$((PORT+1)) +PORT2=$PORT +# we use the forward channel (PORT1) for testing, and have a backward channel +# (PORT2) to get the data back, so we get the classical echo behaviour +testserversec "$N" "$TEST" "$opts -s" "udp4-recv:$PORT1,reuseaddr!!udp4-sendto:127.0.0.1:$PORT2" "" "range=$SECONDADDR/32" "udp4-recv:$PORT2!!udp4-sendto:127.0.0.1:$PORT1" 4 udp $PORT1 0 +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=UDP4RECV_TCPWRAP +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%tcpwrap%*|*%$NAME%*) +TEST="$NAME: security of UDP4-RECV with TCPWRAP option" +if ! feat=$(testaddrs udp ip4 libwrap) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +PORT1=$PORT; PORT=$((PORT+1)) +PORT2=$PORT +ha="$td/hosts.allow" +hd="$td/hosts.deny" +$ECHO "socat: $SECONDADDR" >"$ha" +$ECHO "ALL: ALL" >"$hd" +# we use the forward channel (PORT1) for testing, and have a backward channel +# (PORT2) to get the data back, so we get the classical echo behaviour +testserversec "$N" "$TEST" "$opts -s" "udp4-recv:$PORT1,reuseaddr!!udp4-sendto:127.0.0.1:$PORT2" "" "tcpwrap-etc=$td" "udp4-recv:$PORT2!!udp4-sendto:127.0.0.1:$PORT1" 4 udp $PORT1 0 +fi ;; # feat +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=UDP6RECVFROM_SOURCEPORT +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%sourceport%*|*%$NAME%*) +TEST="$NAME: security of UDP6-RECVFROM with SOURCEPORT option" +if ! feat=$(testaddrs udp ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}UDP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +testserversec "$N" "$TEST" "$opts -s" "udp6-recvfrom:$PORT,reuseaddr" "" "sp=$PORT" "udp6-sendto:[::1]:$PORT" 6 udp $PORT 0 +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=UDP6RECVFROM_LOWPORT +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%lowport%*|*%$NAME%*) +TEST="$NAME: security of UDP6-RECVFROM with LOWPORT option" +if ! feat=$(testaddrs udp ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}UDP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +testserversec "$N" "$TEST" "$opts -s" "udp6-recvfrom:$PORT,reuseaddr" "" "lowport" "udp6-sendto:[::1]:$PORT" 6 udp $PORT 0 +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=UDP6RECVFROM_RANGE +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%range%*|*%$NAME%*) +TEST="$NAME: security of UDP6-RECVFROM with RANGE option" +if ! feat=$(testaddrs tcp ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +#testserversec "$N" "$TEST" "$opts -s" "udp6-recvfrom:$PORT,reuseaddr,fork" "" "range=[::2/128]" "udp6-sendto:[::1]:$PORT" 6 udp $PORT 0 +testserversec "$N" "$TEST" "$opts -s" "udp6-recvfrom:$PORT,reuseaddr" "" "range=[::2/128]" "udp6-sendto:[::1]:$PORT" 6 udp $PORT 0 +fi # ! feat +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=UDP6RECVFROM_TCPWRAP +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%tcpwrap%*|*%$NAME%*) +TEST="$NAME: security of UDP6-RECVFROM with TCPWRAP option" +if ! feat=$(testaddrs udp ip6 libwrap) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +ha="$td/hosts.allow" +hd="$td/hosts.deny" +$ECHO "socat: [::2]" >"$ha" +$ECHO "ALL: ALL" >"$hd" +testserversec "$N" "$TEST" "$opts -s" "udp6-recvfrom:$PORT,reuseaddr" "" "tcpwrap-etc=$td" "udp6-sendto:[::1]:$PORT" 6 udp $PORT 0 +fi ;; # feat +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=UDP6RECV_SOURCEPORT +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%sourceport%*|*%$NAME%*) +TEST="$NAME: security of UDP6-RECV with SOURCEPORT option" +if ! feat=$(testaddrs udp ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}UDP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +PORT1=$PORT; PORT=$((PORT+1)) +PORT2=$PORT; PORT=$((PORT+1)) +PORT3=$PORT +# we use the forward channel (PORT1) for testing, and have a backward channel +# (PORT2) to get the data back, so we get the classical echo behaviour +testserversec "$N" "$TEST" "$opts -s" "udp6-recv:$PORT1,reuseaddr!!udp6-sendto:[::1]:$PORT2" "" "sp=$PORT3" "udp6-recv:$PORT2!!udp6-sendto:[::1]:$PORT1" 6 udp $PORT1 0 +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=UDP6RECV_LOWPORT +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%lowport%*|*%$NAME%*) +TEST="$NAME: security of UDP6-RECV with LOWPORT option" +if ! feat=$(testaddrs udp ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}UDP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +PORT1=$PORT; PORT=$((PORT+1)) +PORT2=$PORT +# we use the forward channel (PORT1) for testing, and have a backward channel +# (PORT2) to get the data back, so we get the classical echo behaviour +testserversec "$N" "$TEST" "$opts -s" "udp6-recv:$PORT1,reuseaddr!!udp6-sendto:[::1]:$PORT2" "" "lowport" "udp6-recv:$PORT2!!udp6-sendto:[::1]:$PORT1" 6 udp $PORT1 0 +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=UDP6RECV_RANGE +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%range%*|*%$NAME%*) +TEST="$NAME: security of UDP6-RECV with RANGE option" +if ! feat=$(testaddrs udp ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}UDP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +PORT1=$PORT; PORT=$((PORT+1)) +PORT2=$PORT +# we use the forward channel (PORT1) for testing, and have a backward channel +# (PORT2) to get the data back, so we get the classical echo behaviour +testserversec "$N" "$TEST" "$opts -s" "udp6-recv:$PORT1,reuseaddr!!udp6-sendto:[::1]:$PORT2" "" "range=[::2/128]" "udp6-recv:$PORT2!!udp6-sendto:[::1]:$PORT1" 6 udp $PORT1 0 +fi +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=UDP6RECV_TCPWRAP +case "$TESTS" in +*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%tcpwrap%*|*%$NAME%*) +TEST="$NAME: security of UDP6-RECV with TCPWRAP option" +if ! feat=$(testaddrs udp ip6 libwrap) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +ha="$td/hosts.allow" +hd="$td/hosts.deny" +$ECHO "socat: [::2]" >"$ha" +$ECHO "ALL: ALL" >"$hd" +PORT1=$PORT; PORT=$((PORT+1)) +PORT2=$PORT +# we use the forward channel (PORT1) for testing, and have a backward channel +# (PORT2) to get the data back, so we get the classical echo behaviour +testserversec "$N" "$TEST" "$opts -s" "udp6-recv:$PORT1,reuseaddr!!udp6-sendto:[::1]:$PORT2" "" "tcpwrap-etc=$td" "udp6-recv:$PORT2!!udp6-sendto:[::1]:$PORT1" 6 udp $PORT1 0 +fi ;; # feat +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=IP4RECVFROM_RANGE +case "$TESTS" in +*%functions%*|*%security%*|*%ip%*|*%ip4%*|*%range%*|*%root%*|*%$NAME%*) +TEST="$NAME: security of IP4-RECVFROM with RANGE option" +if ! feat=$(testaddrs ip4 rawip) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +#testserversec "$N" "$TEST" "$opts -s" "ip4-recvfrom:$PROTO,reuseaddr,fork" "" "range=$SECONDADDR/32" "ip4-sendto:127.0.0.1:$PROTO" 4 ip $PROTO 0 +testserversec "$N" "$TEST" "$opts -s" "ip4-recvfrom:$PROTO,reuseaddr!!udp4-sendto:127.0.0.1:$PORT" "" "range=$SECONDADDR/32" "udp4-recv:$PORT!!ip4-sendto:127.0.0.1:$PROTO" 4 ip $PROTO 0 +fi # not feats, not root +esac +PROTO=$((PROTO+1)) +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=IP4RECVFROM_TCPWRAP +case "$TESTS" in +*%functions%*|*%security%*|*%ip%*|*%ip4%*|*%tcpwrap%*|*%root%*|*%$NAME%*) +TEST="$NAME: security of IP4-RECVFROM with TCPWRAP option" +if ! feat=$(testaddrs ip4 rawip libwrap) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +ha="$td/hosts.allow" +hd="$td/hosts.deny" +$ECHO "socat: $SECONDADDR" >"$ha" +$ECHO "ALL: ALL" >"$hd" +#testserversec "$N" "$TEST" "$opts -s" "ip4-recvfrom:$PROTO,reuseaddr,fork" "" "tcpwrap-etc=$td" "ip4-sendto:127.0.0.1:$PROTO" 4 ip $PROTO 0 +testserversec "$N" "$TEST" "$opts -s" "ip4-recvfrom:$PROTO,reuseaddr!!udp4-sendto:127.0.0.1:$PORT" "" "tcpwrap-etc=$td" "udp4-recv:$PORT!!ip4-sendto:127.0.0.1:$PROTO" 4 ip $PROTO 0 +fi # not feats, not root +esac +PROTO=$((PROTO+1)) +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=IP4RECV_RANGE +case "$TESTS" in +*%functions%*|*%security%*|*%ip%*|*%ip4%*|*%range%*|*%root%*|*%$NAME%*) +TEST="$NAME: security of IP4-RECV with RANGE option" +if ! feat=$(testaddrs ip4 rawip) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}IP4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +PROTO1=$PROTO; PROTO=$((PROTO+1)) +PROTO2=$PROTO +# we use the forward channel (PROTO1) for testing, and have a backward channel +# (PROTO2) to get the data back, so we get the classical echo behaviour +testserversec "$N" "$TEST" "$opts -s" "ip4-recv:$PROTO1,reuseaddr!!ip4-sendto:127.0.0.1:$PROTO2" "" "range=$SECONDADDR/32" "ip4-recv:$PROTO2!!ip4-sendto:127.0.0.1:$PROTO1" 4 ip $PROTO1 0 +fi # not feats, not root +esac +PROTO=$((PROTO+1)) +N=$((N+1)) + + + +NAME=IP4RECV_TCPWRAP +case "$TESTS" in +*%functions%*|*%security%*|*%ip%*|*%ip4%*|*%tcpwrap%*|*%root%*|*%$NAME%*) +TEST="$NAME: security of IP4-RECV with TCPWRAP option" +if ! feat=$(testaddrs ip4 rawip libwrap) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +PROTO1=$PROTO; PROTO=$((PROTO+1)) +PROTO2=$PROTO +ha="$td/hosts.allow" +hd="$td/hosts.deny" +$ECHO "socat: $SECONDADDR" >"$ha" +$ECHO "ALL: ALL" >"$hd" +# we use the forward channel (PROTO1) for testing, and have a backward channel +# (PROTO2) to get the data back, so we get the classical echo behaviour +testserversec "$N" "$TEST" "$opts -s" "ip4-recv:$PROTO1,reuseaddr!!ip4-sendto:127.0.0.1:$PROTO2" "" "tcpwrap-etc=$td" "ip4-recv:$PROTO2!!ip4-sendto:127.0.0.1:$PROTO1" 4 ip $PROTO1 0 +fi # not feats, not root +esac +PROTO=$((PROTO+1)) +N=$((N+1)) + + +NAME=IP6RECVFROM_RANGE +case "$TESTS" in +*%functions%*|*%security%*|*%ip%*|*%ip6%*|*%range%*|*%root%*|*%$NAME%*) +TEST="$NAME: security of IP6-RECVFROM with RANGE option" +if ! feat=$(testaddrs ip6 rawip) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +#testserversec "$N" "$TEST" "$opts -s" "ip6-recvfrom:$PROTO,reuseaddr,fork" "" "range=[::2/128]" "ip6-sendto:[::1]:$PROTO" 6 ip $PROTO 0 +testserversec "$N" "$TEST" "$opts -s" "ip6-recvfrom:$PROTO,reuseaddr!!udp6-sendto:[::1]:$PORT" "" "range=[::2/128]" "udp6-recv:$PORT!!ip6-sendto:[::1]:$PROTO" 6 ip $PROTO 0 +fi # not feats, not root +esac +PROTO=$((PROTO+1)) +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=IP6RECVFROM_TCPWRAP +case "$TESTS" in +*%functions%*|*%security%*|*%ip%*|*%ip6%*|*%tcpwrap%*|*%root%*|*%$NAME%*) +TEST="$NAME: security of IP6-RECVFROM with TCPWRAP option" +if ! feat=$(testaddrs ip6 rawip libwrap) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +ha="$td/hosts.allow" +hd="$td/hosts.deny" +$ECHO "socat: [::2]" >"$ha" +$ECHO "ALL: ALL" >"$hd" +#testserversec "$N" "$TEST" "$opts -s" "ip6-recvfrom:$PROTO,reuseaddr,fork" "" "tcpwrap-etc=$td" "ip6-sendto:[::1]:$PROTO" 6 ip $PROTO 0 +testserversec "$N" "$TEST" "$opts -s" "ip6-recvfrom:$PROTO,reuseaddr!!udp6-sendto:[::1]:$PORT" "" "tcpwrap-etc=$td" "udp6-recv:$PORT!!ip6-sendto:[::1]:$PROTO" 6 ip $PROTO 0 +fi # not feats, not root +esac +PROTO=$((PROTO+1)) +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=IP6RECV_RANGE +case "$TESTS" in +*%functions%*|*%security%*|*%ip%*|*%ip6%*|*%range%*|*%root%*|*%$NAME%*) +TEST="$NAME: security of IP6-RECV with RANGE option" +if ! feat=$(testaddrs ip6 rawip) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}raw IP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +PROTO1=$PROTO; PROTO=$((PROTO+1)) +PROTO2=$PROTO +# we use the forward channel (PROTO1) for testing, and have a backward channel +# (PROTO2) to get the data back, so we get the classical echo behaviour +testserversec "$N" "$TEST" "$opts -s" "ip6-recv:$PROTO1,reuseaddr!!ip6-sendto:[::1]:$PROTO2" "" "range=[::2/128]" "ip6-recv:$PROTO2!!ip6-sendto:[::1]:$PROTO1" 6 ip $PROTO1 0 +fi # not feats, not root +esac +PROTO=$((PROTO+1)) +N=$((N+1)) + +NAME=IP6RECV_TCPWRAP +case "$TESTS" in +*%functions%*|*%security%*|*%ip%*|*%ip6%*|*%tcpwrap%*|*%root%*|*%$NAME%*) +TEST="$NAME: security of IP6-RECV with TCPWRAP option" +if ! feat=$(testaddrs ip6 rawip libwrap) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +PROTO1=$PROTO; PROTO=$((PROTO+1)) +PROTO2=$PROTO +ha="$td/hosts.allow" +hd="$td/hosts.deny" +$ECHO "socat: [::2]" >"$ha" +$ECHO "ALL: ALL" >"$hd" +# we use the forward channel (PROTO1) for testing, and have a backward channel +# (PROTO2) to get the data back, so we get the classical echo behaviour +testserversec "$N" "$TEST" "$opts -s" "ip6-recv:$PROTO1,reuseaddr!!ip6-sendto:[::1]:$PROTO2" "" "tcpwrap-etc=$td" "ip6-recv:$PROTO2!!ip6-sendto:[::1]:$PROTO1" 6 ip $PROTO1 0 +fi # not feats, not root +esac +PROTO=$((PROTO+1)) +N=$((N+1)) + + +NAME=O_NOATIME_FILE +case "$TESTS" in +*%functions%*|*%open%*|*%noatime%*|*%$NAME%*) +TEST="$NAME: option O_NOATIME on file" +# idea: create a file with o-noatime option; one second later create a file +# without this option (using touch); one second later read from the first file. +# Then we check which file has the later ATIME stamp. For this check we use +# "ls -ltu" because it is more portable than "test ... -nt ..." +if ! testoptions o-noatime >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}o-noatime not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.file" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da=$(date) +$PRINTF "test $F_n $TEST... " $N +CMD="$SOCAT $opts -u open:\"${tf}1\",o-noatime /dev/null" +# generate a file +touch "${tf}1" +sleep 1 +# generate a reference file +touch "${tf}2" +sleep 1 +# read from the first file +$CMD 2>"$te" +if [ $? -ne 0 ]; then # command failed + $PRINTF "${FAILED}:\n" + echo "$CMD" + cat "$te" + numFAIL=$((numFAIL+1)) +else +# check which file has a later atime stamp +if [ $(ls -ltu "${tf}1" "${tf}2" |head -1 |sed 's/.* //') != "${tf}2" ]; +then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD" + cat "$te" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "$te"; fi + numOK=$((numOK+1)) +fi # wrong time stamps +fi # command ok +fi ;; # not feats +esac +N=$((N+1)) + +NAME=O_NOATIME_FD +case "$TESTS" in +*%functions%*|*%noatime%*|*%$NAME%*) +TEST="$NAME: option O_NOATIME on file descriptor" +# idea: use a fd of a file with o-noatime option; one second later create a file +# without this option (using touch); one second later read from the first file. +# Then we check which file has the later ATIME stamp. For this check we use +# "ls -ltu" because it is more portable than "test ... -nt ..." +if ! testoptions o-noatime >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}o-noatime not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.file" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da=$(date) +$PRINTF "test $F_n $TEST... " $N +touch ${tf}1 +CMD="$SOCAT $opts -u -,o-noatime /dev/null <${tf}1" +# generate a file, len >= 1 +touch "${tf}1" +sleep 1 +# generate a reference file +touch "${tf}2" +sleep 1 +# read from the first file +sh -c "$CMD" 2>"$te" +if [ $? -ne 0 ]; then # command failed + $PRINTF "${FAILED}:\n" + echo "$CMD" + cat "$te" + numFAIL=$((numFAIL+1)) +else +# check which file has a later atime stamp +if [ $(ls -ltu "${tf}1" "${tf}2" |head -1 |sed 's/.* //') != "${tf}2" ]; +then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD" + cat "$te" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "$te"; fi + numOK=$((numOK+1)) +fi # wrong time stamps +fi # command ok +fi ;; # not feats +esac +N=$((N+1)) + +NAME=EXT2_NOATIME +case "$TESTS" in +*%functions%*|*%ext2%*|*%noatime%*|*%$NAME%*) +TEST="$NAME: extended file system options using ext2fs noatime option" +# idea: create a file with ext2-noatime option; one second later create a file +# without this option (using touch); one second later read from the first file. +# Then we check which file has the later ATIME stamp. For this check we use +# "ls -ltu" because it is more portable than "test ... -nt ..." +if ! testoptions ext2-noatime >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}ext2-noatime not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +ts="$td/test$N.socket" +tf="$td/test$N.file" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +ts1="$ts" +da=$(date) +$PRINTF "test $F_n $TEST... " $N +CMD0="$SOCAT $opts -u /dev/null create:\"${tf}1\"" +CMD="$SOCAT $opts -u /dev/null create:\"${tf}1\",ext2-noatime" +# check if this is a capable FS; lsattr does other things on AIX, thus socat +$CMD0 2>"${te}0" +if [ $? -ne 0 ]; then + $PRINTF "${YELLOW} cannot test${NORMAL}\n" + numCANT=$((numCANT+1)) +else +# generate a file with noatime, len >= 1 +$CMD 2>"$te" +if [ $? -ne 0 ]; then # command failed + $PRINTF "${YELLOW}impotent file system?${NORMAL}\n" + echo "$CMD" + cat "$te" + numCANT=$((numCANT+1)) +else +sleep 1 +# generate a reference file +touch "${tf}2" +sleep 1 +# read from the first file +cat "${tf}1" >/dev/null +# check which file has a later atime stamp +#if [ $(ls -ltu "${tf}1" "${tf}2" |head -n 1 |awk '{print($8);}') != "${tf}2" ]; +if [ $(ls -ltu "${tf}1" "${tf}2" |head -n 1 |sed "s|.*\\($td.*\\)|\1|g") != "${tf}2" ]; +then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD" + cat "$te" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "$te"; fi + numOK=$((numOK+1)) +fi +fi # not impotent +fi # can test +fi ;; # not feats +esac +N=$((N+1)) + + +NAME=COOLWRITE +case "$TESTS" in +*%functions%*|*%timeout%*|*%ignoreeof%*|*%$NAME%*) +TEST="$NAME: option cool-write" +if ! testoptions cool-write >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}option cool-write not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +#set -vx +ti="$td/test$N.file" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="$(date) $RANDOM" +# a reader that will terminate after 1 byte +CMD1="$SOCAT $opts -u pipe:\"$ti\",readbytes=1 /dev/null" +CMD="$SOCAT $opts -u - file:\"$ti\",cool-write" +printf "test $F_n $TEST... " $N +$CMD1 2>"${te}1" & +bg=$! # background process id +sleep 1 +(echo .; sleep 1; echo) |$CMD 2>"$te" +rc=$? +kill $bg 2>/dev/null; wait +if [ $rc -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD &" + cat "$te" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "$te"; fi + numOK=$((numOK+1)) +fi +fi # testoptions +esac +N=$((N+1)) + + +NAME=TCP4ENDCLOSE +case "$TESTS" in +*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%$NAME%*) +TEST="$NAME: end-close keeps TCP V4 socket open" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +p1=$PORT; PORT=$((PORT+1)) +p2=$PORT +da1a="$(date) $RANDOM" +da1b="$(date) $RANDOM" +CMD1="$SOCAT $opts -u - TCP4-CONNECT:$LOCALHOST:$p1" +CMD="$SOCAT $opts -U TCP4:$LOCALHOST:$p2,end-close TCP4-LISTEN:$p1,bind=$LOCALHOST,reuseaddr,fork" +CMD3="$SOCAT $opts -u TCP4-LISTEN:$p2,reuseaddr,bind=$LOCALHOST -" +printf "test $F_n $TEST... " $N +$CMD3 >"$tf" 2>"${te}3" & +pid3=$! +waittcp4port $p2 1 +$CMD 2>"${te}2" & +pid2=$! +waittcp4port $p1 1 +echo "$da1a" |$CMD1 2>>"${te}1a" +echo "$da1b" |$CMD1 2>>"${te}1b" +sleep 1 +kill "$pid3" "$pid2" 2>/dev/null +wait +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1a" "${te}1b" "${te}2" "${te}3" + numFAIL=$((numFAIL+1)) +elif ! echo -e "$da1a\n$da1b" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + cat "${te}1a" "${te}1b" "${te}2" "${te}3" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1a" "${te}1b" "${te}2" "${te}3"; fi + numOK=$((numOK+1)) +fi ;; +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=EXECENDCLOSE +case "$TESTS" in +*%functions%*|*%exec%*|*%$NAME%*) +TEST="$NAME: end-close keeps EXEC child running" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +ts="$td/test$N.sock" +tdiff="$td/test$N.diff" +da1a="$(date) $RANDOM" +da1b="$(date) $RANDOM" +CMD1="$SOCAT $opts - UNIX-CONNECT:$ts" +CMD="$SOCAT -t0.1 $opts EXEC:"$CAT",end-close UNIX-LISTEN:$ts,fork" +printf "test $F_n $TEST... " $N +$CMD 2>"${te}2" & +pid2=$! +waitfile $ts 1 +echo "$da1a" |$CMD1 2>>"${te}1a" >"$tf" +usleep 100000 +echo "$da1b" |$CMD1 2>>"${te}1b" >>"$tf" +usleep 100000 +kill "$pid2" 2>/dev/null +wait +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1a" "${te}1b" "${te}2" + $PRINTF "$FAILED: $SOCAT:\n" +elif ! echo -e "$da1a\n$da1b" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + cat "${te}1a" "${te}1b" "${te}2" + $PRINTF "$FAILED: $SOCAT:\n" +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1a" "${te}1b" "${te}2"; fi + numOK=$((numOK+1)) +fi ;; +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=TCP4RANGEMASK +case "$TESTS" in +*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%range%*|*%$NAME%*) +TEST="$NAME: security of TCP4-L with RANGE option" +if [ "$UNAME" != Linux ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}only on Linux${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +testserversec "$N" "$TEST" "$opts -s" "tcp4-l:$PORT,reuseaddr,fork,retry=1" "" "range=127.0.0.0:255.255.0.0" "tcp4:127.1.0.0:$PORT" 4 tcp $PORT 0 +fi ;; # Linux +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=UDP6LISTENBIND +# this tests for a bug in (up to) 1.5.0.0: +# with upd*-listen, the bind option supported only IPv4 +case "$TESTS" in +*%functions%*|*%bugs%*|*%ip6%*|*%ipapp%*|*%udp%*|*%$NAME%*) +TEST="$NAME: UDP6-LISTEN with bind" +if ! feat=$(testaddrs udp ip6) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}UDP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +tsl=$PORT +ts="$LOCALHOST6:$tsl" +da=$(date) +CMD1="$SOCAT $opts UDP6-LISTEN:$tsl,reuseaddr,bind=$LOCALHOST6 PIPE" +CMD2="$SOCAT $opts - UDP6:$ts" +printf "test $F_n $TEST... " $N +$CMD1 >"$tf" 2>"${te}1" & +pid1=$! +waitudp6port $tsl 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +rc2=$? +kill $pid1 2>/dev/null; wait +if [ $rc2 -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +fi ;; # ! testaddrs +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=TCPWRAPPERS_MULTIOPTS +# this tests for a bug in 1.5.0.0 that let socat fail when more than one +# tcp-wrappers related option was specified in one address +case "$TESTS" in +*%functions%*|*%bugs%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%tcpwrap%*|*%$NAME%*) +TEST="$NAME: use of multiple tcpwrapper enabling options" +if ! feat=$(testaddrs tcp ip4 libwrap) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="$(date) $RANDOM" +ha="$td/hosts.allow" +$ECHO "test : ALL : allow" >"$ha" +CMD1="$SOCAT $opts TCP4-LISTEN:$PORT,reuseaddr,hosts-allow=$a,tcpwrap=test pipe" +CMD2="$SOCAT $opts - TCP:$LOCALHOST:$PORT" +printf "test $F_n $TEST... " $N +$CMD1 2>"${te}1" & +waittcp4port $PORT +echo "$da" |$CMD2 >"$tf" 2>"${te}2" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +fi ;; # feat +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=TCPWRAPPERS_TCP6ADDR +# this tests for a bug in 1.5.0.0 that brought false results with tcp-wrappers +# and IPv6 when +case "$TESTS" in +*%functions%*|*%bugs%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%tcpwrap%*|*%$NAME%*) +TEST="$NAME: specification of TCP6 address in hosts.allow" +if ! feat=$(testaddrs tcp ip6 libwrap) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="$(date) $RANDOM" +ha="$td/hosts.allow" +hd="$td/hosts.deny" +$ECHO "socat : [::1] : allow" >"$ha" +$ECHO "ALL : ALL : deny" >"$hd" +CMD1="$SOCAT $opts TCP6-LISTEN:$PORT,reuseaddr,tcpwrap-etc=$td pipe" +CMD2="$SOCAT $opts - TCP6:[::1]:$PORT" +printf "test $F_n $TEST... " $N +$CMD1 2>"${te}1" & +pid1=$! +waittcp6port $PORT +echo "$da" |$CMD2 >"$tf" 2>"${te}2" +kill $pid1 2>/dev/null; wait +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +fi ;; # feat +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=UDP4BROADCAST +case "$TESTS" in +*%functions%*|*%udp%*|*%udp4%*|*%ip4%*|*%dgram%*|*%broadcast%*|*%$NAME%*) +TEST="$NAME: UDP/IPv4 broadcast" +if [ -z "$BCADDR" ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}dont know a broadcast address${NORMAL}\n" $N +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +ts1p=$PORT; PORT=$((PORT+1)) +#ts1="$BCADDR/8:$ts1p" +ts1="$BCADDR:$ts1p" +ts2p=$PORT; PORT=$((PORT+1)) +ts2="$BCIFADDR:$ts2p" +da=$(date) +CMD1="$SOCAT $opts UDP4-RECVFROM:$ts1p,reuseaddr,broadcast PIPE" +#CMD2="$SOCAT $opts - UDP4-BROADCAST:$ts1" +CMD2="$SOCAT $opts - UDP4-DATAGRAM:$ts1,broadcast" +printf "test $F_n $TEST... " $N +$CMD1 2>"${te}1" & +pid1="$!" +waitudp4port $ts1p 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +rc2="$?" +kill "$pid1" 2>/dev/null; wait; +if [ "$rc2" -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$tut" ]; then + echo "$CMD1 &" + echo "$CMD2" + fi + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +fi ;; # feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=IP4BROADCAST +# test a local broadcast of a raw IPv4 protocol. +# because we receive - in addition to the regular reply - our own broadcast, +# we use a token XXXX that is changed to YYYY in the regular reply packet. +case "$TESTS" in +*%functions%*|*%rawip%*|*%rawip4%*|*%ip4%*|*%dgram%*|*%broadcast%*|*%root%*|*%$NAME%*) +TEST="$NAME: raw IPv4 broadcast" +if ! feat=$(testaddrs ip4 rawip) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}raw IP4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif [ -z "$BCADDR" ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}dont know a broadcast address${NORMAL}\n" $N +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +ts1p=$PROTO +#ts1="$BCADDR/8:$ts1p" +ts1="$BCADDR:$ts1p" +ts2p=$ts1p +ts2="$BCIFADDR" +da="$(date) $RANDOM XXXX" +sh="$td/test$N-sed.sh" +echo 'sed s/XXXX/YYYY/' >"$sh" +chmod a+x "$sh" +CMD1="$SOCAT $opts IP4-RECVFROM:$ts1p,reuseaddr,broadcast exec:$sh" +#CMD2="$SOCAT $opts - IP4-BROADCAST:$ts1" +CMD2="$SOCAT $opts - IP4-DATAGRAM:$ts1,broadcast" +printf "test $F_n $TEST... " $N +$CMD1 2>"${te}1" & +pid1="$!" +waitip4port $ts1p 1 +echo "$da" |$CMD2 2>>"${te}2" |grep -v XXXX >>"$tf" +rc2="$?" +kill "$pid1" 2>/dev/null; wait; +if [ "$rc2" -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" | sed 's/XXXX/YYYY/'|diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +fi ;; # not feats, not root +esac +PROTO=$((PROTO+1)) +N=$((N+1)) + + +#NAME=UDP4BROADCAST_RANGE +#case "$TESTS" in +#*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%dgram%*|*%broadcast%*|*%range%*|*%$NAME%*) +#TEST="$NAME: security of UDP4-BROADCAST with RANGE option" +#if [ -z "$BCADDR" ]; then +# $PRINTF "test $F_n $TEST... ${YELLOW}dont know a broadcast address${NORMAL}\n" $N +#else +#testserversec "$N" "$TEST" "$opts -s" "UDP4-BROADCAST:$BCADDR/8:$PORT" "" "range=127.1.0.0:255.255.0.0" "udp4:127.1.0.0:$PORT" 4 udp $PORT 0 +#fi ;; # feats +#esac +#PORT=$((PORT+1)) +#N=$((N+1)) + + +NAME=UDP4MULTICAST_UNIDIR +case "$TESTS" in +*%functions%*|*%udp%*|*%udp4%*|*%ip4%*|*%dgram%*|*%multicast%*|*%$NAME%*) +TEST="$NAME: UDP/IPv4 multicast, send only" +if ! feat=$(testaddrs ip4 udp) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +ts1p=$PORT; PORT=$((PORT+1)) +ts1a="$SECONDADDR" +ts1="$ts1a:$ts1p" +da=$(date) +CMD1="$SOCAT -u $opts UDP4-RECV:$ts1p,reuseaddr,ip-add-membership=224.255.255.254:$ts1a -" +CMD2="$SOCAT -u $opts - UDP4-SENDTO:224.255.255.254:$ts1p,bind=$ts1a" +printf "test $F_n $TEST... " $N +$CMD1 2>"${te}1" >"${tf}" & +pid1="$!" +waitudp4port $ts1p 1 +echo "$da" |$CMD2 2>>"${te}2" +rc2="$?" +usleep $MICROS +kill "$pid1" 2>/dev/null; wait; +if [ "$rc2" -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +fi ;; # not feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=IP4MULTICAST_UNIDIR +case "$TESTS" in +*%functions%*|*%rawip%*|*%ip4%*|*%dgram%*|*%multicast%*|*%root%*|*%$NAME%*) +TEST="$NAME: IPv4 multicast" +if ! feat=$(testaddrs ip4 rawip) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +ts1p=$PROTO +ts1a="$SECONDADDR" +ts1="$ts1a:$ts1p" +da=$(date) +CMD1="$SOCAT -u $opts IP4-RECV:$ts1p,reuseaddr,ip-add-membership=224.255.255.254:$ts1a -" +CMD2="$SOCAT -u $opts - IP4-SENDTO:224.255.255.254:$ts1p,bind=$ts1a" +printf "test $F_n $TEST... " $N +$CMD1 2>"${te}1" >"${tf}" & +pid1="$!" +waitip4proto $ts1p 1 +usleep $MICROS +echo "$da" |$CMD2 2>>"${te}2" +rc2="$?" +usleep $MICROS +kill "$pid1" 2>/dev/null; wait; +if [ "$rc2" -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +fi ;; # not feats, not root +esac +PROTO=$((PROTO+1)) +N=$((N+1)) + +if false; then +NAME=UDP6MULTICAST_UNIDIR +case "$TESTS" in +*%functions%*|*%udp%*|*%udp6%*|*%ip6%*|*%dgram%*|*%multicast%*|*%$NAME%*) +TEST="$NAME: UDP/IPv6 multicast" +if ! feat=$(testaddrs ip6 udp) || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +ts1p=$PORT; PORT=$((PORT+1)) +if1="$MCINTERFACE" +ts1a="[::1]" +da=$(date) +CMD1="$SOCAT -u $opts UDP6-RECV:$ts1p,reuseaddr,ipv6-join-group=[ff02::2]:$if1 -" +CMD2="$SOCAT -u $opts - UDP6-SENDTO:[ff02::2]:$ts1p,bind=$ts1a" +printf "test $F_n $TEST... " $N +$CMD1 2>"${te}1" >"${tf}" & +pid1="$!" +waitudp6port $ts1p 1 +echo "$da" |$CMD2 2>>"${te}2" +rc2="$?" +usleep $MICROS +kill "$pid1" 2>/dev/null; wait; +if [ "$rc2" -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +fi ;; # not feats +esac +PORT=$((PORT+1)) +N=$((N+1)) +fi # false + +NAME=UDP4MULTICAST_BIDIR +case "$TESTS" in +*%functions%*|*%udp%*|*%udp4%*|*%ip4%*|*%dgram%*|*%multicast%*|*%$NAME%*) +TEST="$NAME: UDP/IPv4 multicast, with reply" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +ts1p=$PORT; PORT=$((PORT+1)) +ts1a="$SECONDADDR" +ts1="$ts1a:$ts1p" +ts2p=$PORT; PORT=$((PORT+1)) +ts2="$BCIFADDR:$ts2p" +da=$(date) +CMD1="$SOCAT $opts UDP4-RECVFROM:$ts1p,reuseaddr,ip-add-membership=224.255.255.254:$ts1a PIPE" +#CMD2="$SOCAT $opts - UDP4-MULTICAST:224.255.255.254:$ts1p,bind=$ts1a" +CMD2="$SOCAT $opts - UDP4-DATAGRAM:224.255.255.254:$ts1p,bind=$ts1a" +printf "test $F_n $TEST... " $N +$CMD1 2>"${te}1" & +pid1="$!" +waitudp4port $ts1p 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +rc2="$?" +kill "$pid1" 2>/dev/null; wait; +if [ "$rc2" -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$tut" ]; then + echo "$CMD1 &" + echo "$CMD2" + fi + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi ;; +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=IP4MULTICAST_BIDIR +case "$TESTS" in +*%functions%*|*%rawip%*|*%ip4%*|*%dgram%*|*%multicast%*|*%root%*|*%$NAME%*) +TEST="$NAME: IPv4 multicast, with reply" +if ! feat=$(testaddrs ip4 rawip) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +ts1p=$PROTO +ts1a="$SECONDADDR" +ts1="$ts1a:$ts1p" +da=$(date) +CMD1="$SOCAT $opts IP4-RECVFROM:$ts1p,reuseaddr,ip-add-membership=224.255.255.254:$ts1a PIPE" +#CMD2="$SOCAT $opts - IP4-MULTICAST:224.255.255.254:$ts1p,bind=$ts1a" +CMD2="$SOCAT $opts - IP4-DATAGRAM:224.255.255.254:$ts1p,bind=$ts1a" +printf "test $F_n $TEST... " $N +$CMD1 2>"${te}1" & +pid1="$!" +waitip4port $ts1p 1 +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +rc2="$?" +kill "$pid1" 2>/dev/null; wait; +if [ "$rc2" -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$tut" ]; then + echo "$CMD1 &" + echo "$CMD2" + fi + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +fi ;; # not feats, not root +esac +PROTO=$((PROTO+1)) +N=$((N+1)) + + +NAME=TUNREAD +case "$TESTS" in +*%functions%*|*%tun%*|*%root%*|*%$NAME%*) +TEST="$NAME: reading data sent through tun interface" +#idea: create a TUN interface and send a datagram to one of the addresses of +# its virtual network. On the tunnel side, read the packet and compare its last +# bytes with the datagram payload +if ! feat=$(testaddrs ip4 tun) || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +tl="$td/test$N.lock" +da="$(date) $RANDOM" +dalen=$((${#da}+1)) +TUNNET=10.255.255 +CMD1="$SOCAT $opts -u - UDP4-SENDTO:$TUNNET.2:$PORT" +#CMD="$SOCAT $opts -u -L $tl TUN,ifaddr=$TUNNET.1,netmask=255.255.255.0,iff-up=1 -" +CMD="$SOCAT $opts -u -L $tl TUN:$TUNNET.1/24,iff-up=1 -" +printf "test $F_n $TEST... " $N +$CMD 2>"${te}" |tail --bytes=$dalen >"${tf}" & +sleep 1 +echo "$da" |$CMD1 2>"${te}1" +sleep 1 +kill "$(cat $tl)" 2>/dev/null +wait +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD &" + echo "$CMD1" + cat "${te}" "${te}1" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + cat "${te}" "${te}1" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}" "${te}1"; fi + numOK=$((numOK+1)) +fi +fi ;; # not feats, not root +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=ABSTRACTSTREAM +case "$TESTS" in +*%functions%*|*%unix%*|*%abstract%*|*%connect%*|*%listen%*|*%$NAME%*) +TEST="$NAME: abstract UNIX stream socket, listen and connect" +if ! feat=$(testaddrs abstract-unixsocket); then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +ts="$td/test$N.socket" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da1="test$N $(date) $RANDOM" +#establish a listening abstract unix socket +SRV="$SOCAT $opts -lpserver ABSTRACT-LISTEN:\"$ts\" PIPE" +#make a connection +CMD="$SOCAT $opts - ABSTRACT-CONNECT:$ts" +$PRINTF "test $F_n $TEST... " $N +touch "$ts" # make a file with same name, so non-abstract fails +eval "$SRV 2>${te}s &" +pids=$! +#waitfile "$ts" +echo "$da1" |eval "$CMD" >"${tf}1" 2>"${te}1" +if [ $? -ne 0 ]; then + kill "$pids" 2>/dev/null + $PRINTF "$FAILED:\n" + echo "$SRV &" + cat "${te}s" + echo "$CMD" + cat "${te}1" + numFAIL=$((numFAIL+1)) +elif ! echo "$da1" |diff - "${tf}1" >"$tdiff"; then + kill "$pids" 2>/dev/null + $PRINTF "$FAILED:\n" + echo "$SRV &" + cat "${te}s" + echo "$CMD" + cat "${te}1" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi # !(rc -ne 0) +wait +fi ;; # not feats +esac +N=$((N+1)) + + +NAME=ABSTRACTDGRAM +case "$TESTS" in +*%functions%*|*%unix%*|*%abstract%*|*%dgram%*|*%$NAME%*) +TEST="$NAME: abstract UNIX datagram" +if ! feat=$(testaddrs abstract-unixsocket); then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +ts1="$td/test$N.socket1" +ts2="$td/test$N.socket2" +da=$(date) +CMD1="$SOCAT $opts ABSTRACT-RECVFROM:$ts1,reuseaddr PIPE" +#CMD2="$SOCAT $opts - ABSTRACT-SENDTO:$ts1,bind=$ts2" +CMD2="$SOCAT $opts - ABSTRACT-SENDTO:$ts1,bind=$ts2" +printf "test $F_n $TEST... " $N +touch "$ts1" # make a file with same name, so non-abstract fails +$CMD1 2>"${te}1" & +pid1="$!" +echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +rc2=$? +kill "$pid1" 2>/dev/null; wait +if [ $rc2 -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + cat "${te}1" + echo "$CMD2" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +fi ;; # not feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=ABSTRACTRECV +case "$TESTS" in +*%functions%*|*%unix%*|*%abstract%*|*%dgram%*|*%recv%*|*%$NAME%*) +TEST="$NAME: abstract UNIX datagram receive" +if ! feat=$(testaddrs abstract-unixsocket); then + $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +ts="$td/test$N.socket" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +ts1="$ts" +da=$(date) +CMD1="$SOCAT $opts -u ABSTRACT-RECV:$ts1,reuseaddr -" +CMD2="$SOCAT $opts -u - ABSTRACT-SENDTO:$ts1" +printf "test $F_n $TEST... " $N +touch "$ts1" # make a file with same name, so non-abstract fails +$CMD1 >"$tf" 2>"${te}1" & +pid1="$!" +#waitfile $ts1 1 +echo "$da" |$CMD2 2>>"${te}2" +rc2="$?" +i=0; while [ ! -s "$tf" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done +kill "$pid1" 2>/dev/null; wait +if [ "$rc2" -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +fi ;; # not feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + + +NAME=OPENSSLREAD +# socat determined availability of data using select(). With openssl, the +# following situation might occur: +# a SSL data block with more than 8192 bytes (socat defaults blocksize) +# arrives; socat calls SSL_read, and the SSL routine reads the complete block. +# socat then reads 8192 bytes from the SSL layer, the rest remains buffered. +# If the TCP connection stays idle for some time, the data in the SSL layer +# keeps there and is not transferred by socat until the socket indicates more +# data or EOF. +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: socat handles data buffered by openssl" +#idea: have a socat process (server) that gets an SSL block that is larger than +# socat transfer block size; keep the socket connection open and kill the +# server process after a short time; if not the whole data block has been +# transferred, the test has failed. +if ! feat=$(testaddrs openssl) >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$(echo $feat| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.out" +te="$td/test$N.err" +tdiff="$td/test$N.diff" +da="$(date) $RANDOM" +SRVCERT=testsrv +gentestcert "$SRVCERT" +CMD1="$SOCAT $opts -u -T 1 -b $($ECHO "$da\c" |wc -c) OPENSSL-LISTEN:$PORT,reuseaddr,cert=$SRVCERT.pem,verify=0 -" +CMD2="$SOCAT $opts -u - OPENSSL-CONNECT:$LOCALHOST:$PORT,verify=0" +printf "test $F_n $TEST... " $N +# +$CMD1 2>"${te}1" >"$tf" & +pid=$! # background process id +(echo "$da"; sleep 2) |$CMD2 2>"${te}2" +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1" + cat "${te}1" + echo "$CMD2" + cat "${te}2" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +fi +esac +N=$((N+1)) + + +# test: there is a bug with the readbytes option: when the socket delivered +# exacly that many bytes as specified with readbytes and the stays idle (no +# more data, no EOF), socat waits for more data instead of generating EOF on +# this in put stream. +NAME=READBYTES_EOF +#set -vx +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: trigger EOF after that many bytes, even when socket idle" +#idea: we deliver that many bytes to socat; the process should terminate then. +# we try to transfer data in the other direction then; if transfer succeeds, +# the process did not terminate and the bug is still there. +if false; then + $PRINTF "test $F_n $TEST... ${YELLOW}$(echo $feat| tr 'a-z' 'A-Z') not avail +able${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tr="$td/test$N.ref" +ti="$td/test$N.in" +to="$td/test$N.out" +te="$td/test$N.err" +tdiff="$td/test$N.diff" +da="$(date)" da="$da$($ECHO '\r')" +CMD="$SOCAT $opts system:\"echo A; sleep 2\",readbytes=2!!- -!!/dev/null" +printf "test $F_n $TEST... " $N +(sleep 1; echo) |eval "$CMD" >"$to" 2>"$te" +if test -s "$to"; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat $te; fi + numOK=$((numOK+1)) +fi +fi +esac +N=$((N+1)) + +echo "summary: $((N-1)) tests; $numOK ok, $numFAIL failed, $numCANT could not be performed" + +if [ "$numFAIL" -gt 0 ]; then + exit 1 +fi +exit 0 + +#============================================================================== + +rm -f testsrv.* testcli.* testsrvdsa* testsrvfips* testclifips* + +# end + +# too dangerous - run as root and having a shell problem, it might purge your +# file systems +#rm -r "$td" + +# sometimes subprocesses hang; we want to see this +wait + +exit + +# template +NAME=!!! +case "$TESTS" in +*%functions%*|*%$NAME%*) +TEST="$NAME: !!!" +printf "test $F_n $TEST... " $N +!!! +if [ !!! ]; then + $PRINTF "$OK\n" +else + $PRINTF "$FAILED\n" + cat "$te" +fi +esac +N=$((N+1)) + + +TEST="$NAME: transferring from one file to another with echo" +tf1="$td/file$N.input" +tf2="$td/file$N.output" +testecho "$N" "$TEST" "" "echo" "$opts" + + +# MANUAL TESTS + +# ZOMBIES +# have httpd on PORT/tcp +# nice -20 $SOCAT -d tcp-l:24080,fork tcp:$LOCALHOST:PORT +# i=0; while [ $i -lt 100 ]; do $ECHO 'GET / HTTP/1.0\n' |$SOCAT -t -,ignoreeof tcp:$LOCALHOST:24080 >/dev/null& i=$((i+1)); done diff --git a/testcert.conf b/testcert.conf new file mode 100644 index 0000000..64b06cd --- /dev/null +++ b/testcert.conf @@ -0,0 +1,9 @@ +prompt=no + +[ req ] +default_bits = 768 +distinguished_name=Test + +[ Test ] +countryName = XY + diff --git a/utils.c b/utils.c new file mode 100644 index 0000000..e2d6824 --- /dev/null +++ b/utils.c @@ -0,0 +1,147 @@ +/* $Id: utils.c,v 1.17 2007/02/08 18:36:16 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* useful additions to C library */ + +#include "config.h" + +#include "sysincludes.h" + +#include "compat.h" /* socklen_t */ +#include "mytypes.h" +#include "sycls.h" +#include "utils.h" + + +#if !HAVE_MEMRCHR +/* GNU extension, available since glibc 2.1.91 */ +void *memrchr(const void *s, int c, size_t n) { + const unsigned char *t = ((unsigned char *)s)+n; + while (--t >= (unsigned char *)s) { + if (*t == c) break; + } + if (t < (unsigned char *)s) + return NULL; + return (void *)t; +} +#endif /* !HAVE_MEMRCHR */ + +void *memdup(const void *src, size_t n) { + void *dest; + + if ((dest = Malloc(n)) == NULL) { + return NULL; + } + + memcpy(dest, src, n); + return dest; +} + +/* 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. */ +const struct wordent *keyw(const struct wordent *keywds, const char *name, unsigned int nkeys) { + unsigned int lower, upper, mid; + int r; + + lower = 0; + upper = nkeys; + + while (upper - lower > 1) + { + mid = (upper + lower) >> 1; + if (!(r = strcasecmp(keywds[mid].name, name))) + { + return &keywds[mid]; + } + if (r < 0) + lower = mid; + else + upper = mid; + } + if (nkeys > 0 && !(strcasecmp(keywds[lower].name, name))) + { + return &keywds[lower]; + } + return NULL; +} + +/* Linux: setenv(), AIX: putenv() */ +#if !HAVE_SETENV +int setenv(const char *name, const char *value, int overwrite) { + int result; + char *env; + if (!overwrite) { + if (getenv(name)) return 0; /* already exists */ + } + if ((env = Malloc(strlen(name)+strlen(value)+2)) != NULL) { + return -1; + } + sprintf(env, "%s=%s", name, value); + if ((result = putenv(env)) != 0) { /* AIX docu says "... nonzero ..." */ + free(env); + result = -1; + } + /* linux "man putenv" says: ...this string becomes part of the environment*/ + return result; +} +#endif /* !HAVE_SETENV */ + + + +/* sanitize an "untrusted" character. output buffer must provide at least 5 + characters space. + Does not append null. returns length out output (currently: max 4) */ +static size_t sanitize_char(char c, char *o, int style) { + int hn; /* high nibble */ + int ln; /* low nibble */ + int n; /* written chars */ + if (isprint(c)) { + *o = c; + return 1; + } + *o++ = '\\'; + n = 2; + switch (c) { + case '\0': *o++ = '0'; break; + case '\a': *o++ = 'a'; break; + case '\b': *o++ = 'b'; break; + case '\t': *o++ = 't'; break; + case '\n': *o++ = 'n'; break; + case '\v': *o++ = 'v'; break; + case '\f': *o++ = 'f'; break; + case '\r': *o++ = 'r'; break; + case '\'': *o++ = '\''; break; + case '\"': *o++ = '"'; break; + case '\\': *o++ = '\\'; break; + default: + *o++ = 'x'; + hn = (c>>4)&0x0f; + ln = c&0x0f; + *o++ = (hn>=10 ? (('A'-1)+(hn-10)) : ('0'+hn)); + *o++ = (ln>=10 ? (('A'-1)+(ln-10)) : ('0'+ln)); + n = 4; + } + return n; +} + +/* sanitize "untrusted" text, replacing special control characters with the C + string version ("\x"), and replacing unprintable chars with ".". + text can grow to four times of input, so keep output buffer long enough! + returns a pointer to the first untouched byte of the output buffer. +*/ +char *sanitize_string(const char *data, /* input data */ + size_t bytes, /* length of input data, >=0 */ + char *coded, /* output buffer, must be long enough */ + int style + ) { + int c; + + while (bytes > 0) { + c = *(unsigned char *)data++; + coded += sanitize_char(c, coded, style); + --bytes; + } + return coded; +} diff --git a/utils.h b/utils.h new file mode 100644 index 0000000..c974a41 --- /dev/null +++ b/utils.h @@ -0,0 +1,68 @@ +/* $Id: utils.h,v 1.7 2007/02/08 18:36:16 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __utils_h_included +#define __utils_h_included 1 + +/* a generic name table entry */ +struct wordent { + const char *name; + void *desc; +} ; + +#if !HAVE_MEMRCHR +extern void *memrchr(const void *s, int c, size_t n); +#endif +extern void *memdup(const void *src, size_t n); +#if !HAVE_SETENV +extern int setenv(const char *name, const char *value, int overwrite); +#endif /* !HAVE_SETENV */ + +extern const struct wordent *keyw(const struct wordent *keywds, const char *name, unsigned int nkeys); + + +#define XIOSAN_ZERO_MASK 0x000f +#define XIOSAN_ZERO_DEFAULT 0x0000 +#define XIOSAN_ZERO_DOT 0x0001 +#define XIOSAN_ZERO_BACKSLASH_OCT_3 0x0002 +#define XIOSAN_ZERO_BACKSLASH_OCT_4 0x0003 +#define XIOSAN_ZERO_BACKSLASHX_HEX_UP 0x0004 +#define XIOSAN_ZERO_BACKSLASHX_HEX_LOW 0x0005 +#define XIOSAN_ZERO_PERCENT_HEX_UP 0x0006 +#define XIOSAN_ZERO_PERCENT_HEX_LOW 0x0007 +#define XIOSAN_CONTROL_MASK 0x00f0 +#define XIOSAN_CONTROL_DEFAULT 0x0000 +#define XIOSAN_CONTROL_DOT 0x0010 +#define XIOSAN_CONTROL_BACKSLASH_OCT_3 0x0020 +#define XIOSAN_CONTROL_BACKSLASH_OCT_4 0x0030 +#define XIOSAN_CONTROL_BACKSLASHX_HEX_UP 0x0040 +#define XIOSAN_CONTROL_BACKSLASHX_HEX_LOW 0x0050 +#define XIOSAN_CONTROL_PERCENT_HEX_UP 0x0060 +#define XIOSAN_CONTROL_PERCENT_HEX_LOW 0x0070 +#define XIOSAN_UNPRINT_MASK 0x0f00 +#define XIOSAN_UNPRINT_DEFAULT 0x0000 +#define XIOSAN_UNPRINT_DOT 0x0100 +#define XIOSAN_UNPRINT_BACKSLASH_OCT_3 0x0200 +#define XIOSAN_UNPRINT_BACKSLASH_OCT_4 0x0300 +#define XIOSAN_UNPRINT_BACKSLASHX_HEX_UP 0x0400 +#define XIOSAN_UNPRINT_BACKSLASHX_HEX_LOW 0x0500 +#define XIOSAN_UNPRINT_PERCENT_HEX_UP 0x0600 +#define XIOSAN_UNPRINT_PERCENT_HEX_LOW 0x0700 +#define XIOSAN_DEFAULT_MASK 0xf000 +#define XIOSAN_DEFAULT_BACKSLASH_DOT 0x1000 +#define XIOSAN_DEFAULT_BACKSLASH_OCT_3 0x2000 +#define XIOSAN_DEFAULT_BACKSLASH_OCT_4 0x3000 +#define XIOSAN_DEFAULT_BACKSLASHX_HEX_UP 0x4000 +#define XIOSAN_DEFAULT_BACKSLASHX_HEX_LOW 0x5000 +#define XIOSAN_DEFAULT_PERCENT_HEX_UP 0x6000 +#define XIOSAN_DEFAULT_PERCENT_HEX_LOW 0x7000 + +extern +char *sanitize_string(const char *data, /* input data */ + size_t bytes, /* length of input data, >=0 */ + char *coded, /* output buffer, must be long enough */ + int style); + +#endif /* !defined(__utils_h_included) */ + diff --git a/xio-ascii.c b/xio-ascii.c new file mode 100644 index 0000000..4ebe0d2 --- /dev/null +++ b/xio-ascii.c @@ -0,0 +1,107 @@ +/* $Id: xio-ascii.c,v 1.5 2006/07/23 07:30:46 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2002-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains functions for text encoding, decoding, and conversions */ + + +#include +#include +#include + +#include "xio-ascii.h" + +/* for each 6 bit pattern we have an ASCII character in the arry */ +const static int base64chars[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/', +} ; + +#define CHAR64(c) (base64chars[c]) + +char * + xiob64encodeline(const char *data, /* input data */ + size_t bytes, /* length of input data, >=0 */ + char *coded /* output buffer, must be long enough */ + ) { + int c1, c2, c3; + + while (bytes > 0) { + c1 = *data++; + *coded++ = CHAR64(c1>>2); + if (--bytes == 0) { + *coded++ = CHAR64((c1&0x03)<<4); + *coded++ = '='; + *coded++ = '='; + } else { + c2 = *data++; + *coded++ = CHAR64(((c1&0x03)<<4)|(c2>>4)); + if (--bytes == 0) { + *coded++ = CHAR64((c2&0x0f)<<2); + *coded++ = '='; + } else { + c3 = *data++; --bytes; + *coded++ = CHAR64(((c2&0x0f)<<2)|(c3>>6)); + *coded++ = CHAR64(c3&0x3f); + } + } + } + return coded; +} + + + +/* sanitize "untrusted" text, replacing special control characters with the C + string version ("\x"), and replacing unprintable chars with ".". + text can grow to double size, so keep output buffer long enough! + returns a pointer to the first untouched byte of the output buffer. +*/ +char *xiosanitize(const char *data, /* input data */ + size_t bytes, /* length of input data, >=0 */ + char *coded /* output buffer, must be long enough */ + ) { + int c; + + while (bytes > 0) { + c = *(unsigned char *)data++; + switch (c) { + case '\0' : *coded++ = '\\'; *coded++ = '0'; break; + case '\a' : *coded++ = '\\'; *coded++ = 'a'; break; + case '\b' : *coded++ = '\\'; *coded++ = 'b'; break; + case '\t' : *coded++ = '\\'; *coded++ = 't'; break; + case '\n' : *coded++ = '\\'; *coded++ = 'n'; break; + case '\v' : *coded++ = '\\'; *coded++ = 'v'; break; + case '\f' : *coded++ = '\\'; *coded++ = 'f'; break; + case '\r' : *coded++ = '\\'; *coded++ = 'r'; break; + case '\'' : *coded++ = '\\'; *coded++ = '\''; break; + case '\"' : *coded++ = '\\'; *coded++ = '"'; break; + case '\\' : *coded++ = '\\'; *coded++ = '\\'; break; + default: + if (!isprint(c)) + c = '.'; + *coded++ = c; + break; + } + --bytes; + } + return coded; +} + + +/* print the bytes in hex */ +char * + xiohexdump(const unsigned char *data, size_t bytes, char *coded) { + int space = 0; + while (bytes-- > 0) { + if (space) { *coded++ = ' '; } + coded += sprintf(coded, "%02x", *data++); + space = 1; + } + return coded; +} diff --git a/xio-ascii.h b/xio-ascii.h new file mode 100644 index 0000000..bc4735d --- /dev/null +++ b/xio-ascii.h @@ -0,0 +1,20 @@ +/* $Id: xio-ascii.h,v 1.4 2006/07/23 07:30:49 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2002-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_ascii_h_included +#define __xio_ascii_h_included 1 + +extern char * + xiob64encodeline(const char *data, /* input data */ + size_t bytes, /* length of input data, >=0 */ + char *coded /* output buffer, must be long enough */ + ); +extern char *xiosanitize(const char *data, /* input data */ + size_t bytes, /* length of input data, >=0 */ + char *coded /* output buffer, must be long enough */ + ); +extern char * + xiohexdump(const unsigned char *data, size_t bytes, char *coded); + +#endif /* !defined(__xio_ascii_h_included) */ diff --git a/xio-creat.c b/xio-creat.c new file mode 100644 index 0000000..edc490a --- /dev/null +++ b/xio-creat.c @@ -0,0 +1,79 @@ +/* $Id: xio-creat.c,v 1.16 2006/07/13 06:39:01 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for opening addresses of create type */ + +#include "xiosysincludes.h" + +#if WITH_CREAT + +#include "xioopen.h" +#include "xio-named.h" +#include "xio-creat.h" + + +static int xioopen_creat(int arg, const char *argv[], struct opt *opts, int rw, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); + + +/*! within stream model, this is a write-only address - use 2 instead of 3 */ +const struct addrdesc addr_creat = { "create", 3, xioopen_creat, GROUP_FD|GROUP_NAMED|GROUP_FILE, 0, 0, 0 HELP(":") }; + + +/* retrieve the mode option and perform the creat() call. + returns the file descriptor or a negative value. */ +static int _xioopen_creat(const char *path, int rw, struct opt *opts) { + mode_t mode = 0666; + int fd; + + retropt_modet(opts, OPT_PERM, &mode); + + if ((fd = Creat(path, mode)) < 0) { + Error3("creat(\"%s\", 0%03o): %s", + path, mode, strerror(errno)); + return STAT_RETRYLATER; + } + return fd; +} + + +static int xioopen_creat(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3) { + const char *filename = argv[1]; + int rw = (xioflags&XIO_ACCMODE); + bool exists; + bool opt_unlink_close = false; + int result; + + /* remove old file, or set user/permissions on old file; parse options */ + if ((result = _xioopen_named_early(argc, argv, fd, groups, &exists, opts)) < 0) { + return result; + } + + retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); + if (opt_unlink_close) { + if ((fd->stream.unlink_close = strdup(filename)) == NULL) { + Error1("strdup(\"%s\"): out of memory", filename); + } + fd->stream.opt_unlink_close = true; + } + + Notice2("creating regular file \"%s\" for %s", filename, ddirection[rw]); + if ((result = _xioopen_creat(filename, rw, opts)) < 0) + return result; + fd->stream.fd = result; + + applyopts_named(filename, opts, PH_PASTOPEN); + if ((result = applyopts2(fd->stream.fd, opts, PH_PASTOPEN, PH_LATE2)) < 0) + return result; + + applyopts_cloexec(fd->stream.fd, opts); + + applyopts_fchown(fd->stream.fd, opts); + + if ((result = _xio_openlate(&fd->stream, opts)) < 0) + return result; + + return 0; +} + +#endif /* WITH_CREAT */ diff --git a/xio-creat.h b/xio-creat.h new file mode 100644 index 0000000..afe8073 --- /dev/null +++ b/xio-creat.h @@ -0,0 +1,10 @@ +/* $Id: xio-creat.h,v 1.4 2001/11/04 17:19:20 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_creat_h_included +#define __xio_creat_h_included 1 + +extern const struct addrdesc addr_creat; + +#endif /* !defined(__xio_creat_h_included) */ diff --git a/xio-exec.c b/xio-exec.c new file mode 100644 index 0000000..2b2c3cd --- /dev/null +++ b/xio-exec.c @@ -0,0 +1,137 @@ +/* $Id: xio-exec.c,v 1.19 2006/07/12 21:59:28 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for opening addresses of exec type */ + +#include "xiosysincludes.h" +#include "xioopen.h" +#include "nestlex.h" + +#include "xio-progcall.h" +#include "xio-exec.h" + +#if WITH_EXEC + +static int xioopen_exec(int argc, const char *argv[], struct opt *opts, + int xioflags, /* XIO_RDONLY etc. */ + xiofile_t *fd, + unsigned groups, + int dummy1, int dummy2, int dummy3 + ); + +const struct addrdesc addr_exec = { "exec", 3, xioopen_exec, GROUP_FD|GROUP_FORK|GROUP_EXEC|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_TERMIOS|GROUP_FIFO|GROUP_PTY|GROUP_PARENT, 0, 0, 0 HELP(":") }; + +const struct optdesc opt_dash = { "dash", "login", OPT_DASH, GROUP_EXEC, PH_PREEXEC, TYPE_BOOL, OFUNC_SPEC }; + +static int xioopen_exec(int argc, const char *argv[], struct opt *opts, + int xioflags, /* XIO_RDONLY, XIO_MAYCHILD etc. */ + xiofile_t *fd, + unsigned groups, + int dummy1, int dummy2, int dummy3 + ) { + int status; + bool dash = false; + + if (argc != 2) { + Error3("\"%s:%s\": wrong number of parameters (%d instead of 1)", argv[0], argv[1], argc-1); + } + + retropt_bool(opts, OPT_DASH, &dash); + + status = _xioopen_foxec(xioflags, &fd->stream, groups, &opts); + if (status < 0) return status; + if (status == 0) { /* child */ + const char *ends[] = { " ", NULL }; + const char *hquotes[] = { "'", NULL }; + const char *squotes[] = { "\"", NULL }; + const char *nests[] = { + "'", "'", + "(", ")", + "[", "]", + "{", "}", + NULL + } ; + char **pargv = NULL; + int pargc, i; + size_t len; + const char *strp; + char *token; /*! */ + char *tokp; + char *path = NULL; + char *tmp; + int numleft; + int result; + + /*! Close(something) */ + /* parse command line */ + Debug1("child: args = \"%s\"", argv[1]); + pargv = Malloc(8*sizeof(char *)); + if (pargv == NULL) return STAT_RETRYLATER; + i = 0; + len = strlen(argv[1])+1; + strp = argv[1]; + token = Malloc(len); /*! */ + tokp = token; + if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests, + true, true, false) < 0) { + Error("internal: miscalculated string lengths"); + } + *tokp++ = '\0'; + pargv[0] = strrchr(tokp-1, '/'); + if (pargv[0] == NULL) pargv[0] = token; else ++pargv[0]; + pargc = 1; + while (*strp == ' ') { + if ((pargc & 0x07) == 0) { + pargv = Realloc(pargv, (pargc+8)*sizeof(char *)); + if (pargv == NULL) return STAT_RETRYLATER; + } + ++strp; + pargv[pargc++] = tokp; + if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests, + true, true, false) < 0) { + Error("internal: miscalculated string lengths"); + } + *tokp++ = '\0'; + } + pargv[pargc] = NULL; + + if ((tmp = Malloc(strlen(pargv[0])+2)) == NULL) { + return STAT_RETRYLATER; + } + if (dash) { + tmp[0] = '-'; + strcpy(tmp+1, pargv[0]); + } else { + strcpy(tmp, pargv[0]); + } + pargv[0] = tmp; + + if (setopt_path(opts, &path) < 0) { + /* this could be dangerous, so let us abort this child... */ + Exit(1); + } + + if ((numleft = leftopts(opts)) > 0) { + Error1("%d option(s) could not be used", numleft); + showleft(opts); + return STAT_NORETRY; + } + + Notice1("execvp'ing \"%s\"", token); + result = Execvp(token, pargv); + /* here we come only if execvp() failed */ + switch (pargc) { + case 1: Error3("execvp(\"%s\", \"%s\"): %s", token, pargv[0], strerror(errno)); break; + case 2: Error4("execvp(\"%s\", \"%s\", \"%s\"): %s", token, pargv[0], pargv[1], strerror(errno)); break; + case 3: + default: + Error5("execvp(\"%s\", \"%s\", \"%s\", \"%s\", ...): %s", token, pargv[0], pargv[1], pargv[2], strerror(errno)); break; + } + Exit(1); /* this child process */ + } + + /* parent */ + return 0; +} +#endif /* WITH_EXEC */ diff --git a/xio-exec.h b/xio-exec.h new file mode 100644 index 0000000..ab84aed --- /dev/null +++ b/xio-exec.h @@ -0,0 +1,12 @@ +/* $Id: xio-exec.h,v 1.6 2002/05/19 08:05:36 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001, 2002 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_exec_h_included +#define __xio_exec_h_included 1 + +extern const struct addrdesc addr_exec; + +extern const struct optdesc opt_dash; + +#endif /* !defined(__xio_exec_h_included) */ diff --git a/xio-ext2.c b/xio-ext2.c new file mode 100644 index 0000000..6082190 --- /dev/null +++ b/xio-ext2.c @@ -0,0 +1,91 @@ +/* $Id: xio-ext2.c,v 1.1 2006/05/07 17:06:53 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2005-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for handling Linux ext2fs options + they can also be set with chattr(1) and viewed with lsattr(1) */ + +#include "xiosysincludes.h" +#include "xioopen.h" + +#include "xio-ext2.h" + + +#if WITH_EXT2 + +/****** FD options ******/ + +#ifdef EXT2_SECRM_FL +/* secure deletion, chattr 's' */ +const struct optdesc opt_ext2_secrm = { "ext2-secrm", "secrm", OPT_EXT2_SECRM, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, EXT2_IOC_GETFLAGS, EXT2_IOC_SETFLAGS, EXT2_SECRM_FL }; +#endif /* EXT2_SECRM_FL */ + +#ifdef EXT2_UNRM_FL +/* undelete, chattr 'u' */ +const struct optdesc opt_ext2_unrm = { "ext2-unrm", "unrm", OPT_EXT2_UNRM, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, EXT2_IOC_GETFLAGS, EXT2_IOC_SETFLAGS, EXT2_UNRM_FL }; +#endif /* EXT2_UNRM_FL */ + +#ifdef EXT2_COMPR_FL +/* compress file, chattr 'c' */ +const struct optdesc opt_ext2_compr = { "ext2-compr", "compr", OPT_EXT2_COMPR, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, EXT2_IOC_GETFLAGS, EXT2_IOC_SETFLAGS, EXT2_COMPR_FL }; +#endif /* EXT2_COMPR_FL */ + +#ifdef EXT2_SYNC_FL +/* synchronous update, chattr 'S' */ +const struct optdesc opt_ext2_sync = { "ext2-sync", "sync", OPT_EXT2_SYNC, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, EXT2_IOC_GETFLAGS, EXT2_IOC_SETFLAGS, EXT2_SYNC_FL }; +#endif /* EXT2_SYNC_FL */ + +#ifdef EXT2_IMMUTABLE_FL +/* immutable file, chattr 'i' */ +const struct optdesc opt_ext2_immutable = { "ext2-immutable", "immutable", OPT_EXT2_IMMUTABLE, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, EXT2_IOC_GETFLAGS, EXT2_IOC_SETFLAGS, EXT2_IMMUTABLE_FL }; +#endif /* EXT2_IMMUTABLE_FL */ + +#ifdef EXT2_APPEND_FL +/* writes to file may only append, chattr 'a' */ +const struct optdesc opt_ext2_append = { "ext2-append", "append", OPT_EXT2_APPEND, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, EXT2_IOC_GETFLAGS, EXT2_IOC_SETFLAGS, EXT2_APPEND_FL }; +#endif /* EXT2_APPEND_FL */ + +#ifdef EXT2_NODUMP_FL +/* do not dump file, chattr 'd' */ +const struct optdesc opt_ext2_nodump = { "ext2-nodump", "nodump", OPT_EXT2_NODUMP, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, EXT2_IOC_GETFLAGS, EXT2_IOC_SETFLAGS, EXT2_NODUMP_FL }; +#endif /* EXT2_NODUMP_FL */ + +#ifdef EXT2_NOATIME_FL +/* do not update atime, chattr 'A' */ +const struct optdesc opt_ext2_noatime = { "ext2-noatime", "noatime", OPT_EXT2_NOATIME, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, EXT2_IOC_GETFLAGS, EXT2_IOC_SETFLAGS, EXT2_NOATIME_FL }; +#endif /* EXT2_NOATIME_FL */ + +/* EXT2_DIRTY_FL ??? */ +/* EXT2_COMPRBLK_FL one ore more compress clusters */ +/* EXT2_NOCOMPR_FL access raw compressed data */ +/* EXT2_ECOMPR_FL compression error */ +/* EXT2_BTREE_FL btree format dir */ +/* EXT2_INDEX_FL hash indexed directory */ +/* EXT2_IMAGIC ??? */ + +#ifdef EXT2_JOURNAL_DATA_FL +/* file data should be journaled, chattr 'j' */ +const struct optdesc opt_ext2_journal_data = { "ext2-journal-data", "journal-data", OPT_EXT2_JOURNAL_DATA, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, EXT2_IOC_GETFLAGS, EXT2_IOC_SETFLAGS, EXT2_JOURNAL_DATA_FL }; +#endif /* EXT2_JOURNAL_DATA_FL */ + +#ifdef EXT2_NOTAIL_FL +/* file tail should not be merged, chattr 't' */ +const struct optdesc opt_ext2_notail = { "ext2-notail", "notail", OPT_EXT2_NOTAIL, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, EXT2_IOC_GETFLAGS, EXT2_IOC_SETFLAGS, EXT2_NOTAIL_FL }; +#endif /* EXT2_NOTAIL_FL */ + +#ifdef EXT2_DIRSYNC_FL +/* synchronous directory modifications, chattr 'D' */ +const struct optdesc opt_ext2_dirsync = { "ext2-dirsync", "dirsync", OPT_EXT2_DIRSYNC, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, EXT2_IOC_GETFLAGS, EXT2_IOC_SETFLAGS, EXT2_DIRSYNC_FL }; +#endif /* EXT2_DIRSYNC_FL */ + +#ifdef EXT2_TOPDIR_FL +/* top of directory hierarchies, chattr 'T' */ +const struct optdesc opt_ext2_topdir = { "ext2-topdir", "topdir", OPT_EXT2_TOPDIR, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, EXT2_IOC_GETFLAGS, EXT2_IOC_SETFLAGS, EXT2_TOPDIR_FL }; +#endif /* EXT2_TOPDIR_FL */ + +/* EXTENTS inode uses extents */ + + +#endif /* WITH_EXT2 */ + + diff --git a/xio-ext2.h b/xio-ext2.h new file mode 100644 index 0000000..a7571c4 --- /dev/null +++ b/xio-ext2.h @@ -0,0 +1,21 @@ +/* $Id: xio-ext2.h,v 1.2 2006/05/31 19:28:24 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_ext2_h_included +#define __xio_ext2_h_included 1 + +extern const struct optdesc opt_ext2_secrm; +extern const struct optdesc opt_ext2_unrm; +extern const struct optdesc opt_ext2_compr; +extern const struct optdesc opt_ext2_sync; +extern const struct optdesc opt_ext2_immutable; +extern const struct optdesc opt_ext2_append; +extern const struct optdesc opt_ext2_nodump; +extern const struct optdesc opt_ext2_noatime; +extern const struct optdesc opt_ext2_journal_data; +extern const struct optdesc opt_ext2_notail; +extern const struct optdesc opt_ext2_dirsync; +extern const struct optdesc opt_ext2_topdir; + +#endif /* !defined(__xio_ext2_h_included) */ diff --git a/xio-fd.c b/xio-fd.c new file mode 100644 index 0000000..e9c29b9 --- /dev/null +++ b/xio-fd.c @@ -0,0 +1,77 @@ +/* $Id: xio-fd.c,v 1.26 2006/12/28 07:35:50 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains common file descriptor related option definitions */ + +#include "xiosysincludes.h" +#include "xioopen.h" + +#include "xio-fd.h" + +/****** for ALL addresses - with open() or fcntl(F_SETFL) ******/ +const struct optdesc opt_append = { "append", NULL, OPT_O_APPEND, GROUP_OPEN|GROUP_FD, PH_LATE, TYPE_BOOL, OFUNC_FCNTL, F_SETFL, O_APPEND }; +const struct optdesc opt_nonblock = { "o-nonblock", "nonblock", OPT_O_NONBLOCK, GROUP_OPEN|GROUP_FD, PH_FD, TYPE_BOOL, OFUNC_FCNTL, F_SETFL, O_NONBLOCK }; +#if defined(O_NDELAY) && (!defined(O_NONBLOCK) || O_NDELAY != O_NONBLOCK) +const struct optdesc opt_o_ndelay = { "o-ndelay", NULL, OPT_O_NDELAY, GROUP_OPEN|GROUP_FD, PH_LATE, TYPE_BOOL, OFUNC_FCNTL, F_SETFL, O_NDELAY }; +#endif +#ifdef O_ASYNC +const struct optdesc opt_async = { "async", NULL, OPT_O_ASYNC, GROUP_OPEN|GROUP_FD, PH_LATE, TYPE_BOOL, OFUNC_FCNTL, F_SETFL, O_ASYNC }; +#endif +#ifdef O_BINARY +const struct optdesc opt_o_binary = { "o-binary", "binary", OPT_O_BINARY, GROUP_OPEN|GROUP_FD, PH_OPEN, TYPE_BOOL, OFUNC_FCNTL, F_SETFL, O_BINARY }; +#endif +#ifdef O_TEXT +const struct optdesc opt_o_text = { "o-text", "text", OPT_O_TEXT, GROUP_OPEN|GROUP_FD, PH_OPEN, TYPE_BOOL, OFUNC_FCNTL, F_SETFL, O_TEXT }; +#endif +#ifdef O_NOINHERIT +const struct optdesc opt_o_noinherit = { "o-noinherit", "noinherit", OPT_O_NOINHERIT, GROUP_OPEN|GROUP_FD, PH_OPEN, TYPE_BOOL, OFUNC_FCNTL, F_SETFL, O_NOINHERIT }; +#endif +#ifdef O_NOATIME +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 }; +/****** ftruncate() ******/ +/* this record is good for ftruncate() or ftruncate64() if available */ +#if HAVE_FTRUNCATE64 +const struct optdesc opt_ftruncate32 = { "ftruncate32", NULL, OPT_FTRUNCATE32, GROUP_REG, PH_LATE, TYPE_OFF32, OFUNC_SPEC }; +const struct optdesc opt_ftruncate64 = { "ftruncate64", "truncate", OPT_FTRUNCATE64, GROUP_REG, PH_LATE, TYPE_OFF64, OFUNC_SPEC }; +#else +const struct optdesc opt_ftruncate32 = { "ftruncate32", "truncate", OPT_FTRUNCATE32, GROUP_REG, PH_LATE, TYPE_OFF32, OFUNC_SPEC }; +#endif /* !HAVE_FTRUNCATE64 */ +/****** for ALL addresses - permissions, ownership, and positioning ******/ +const struct optdesc opt_group = { "group", "gid", OPT_GROUP, GROUP_FD|GROUP_NAMED,PH_FD,TYPE_GIDT,OFUNC_SPEC }; +const struct optdesc opt_group_late= { "group-late","gid-l", OPT_GROUP_LATE,GROUP_FD, PH_LATE, TYPE_GIDT, OFUNC_SPEC }; +const struct optdesc opt_perm = { "perm", "mode", OPT_PERM, GROUP_FD|GROUP_NAMED, PH_FD, TYPE_MODET,OFUNC_SPEC }; +const struct optdesc opt_perm_late = { "perm-late", NULL, OPT_PERM_LATE, GROUP_FD, PH_LATE, TYPE_MODET,OFUNC_SPEC }; +const struct optdesc opt_user = { "user", "uid", OPT_USER, GROUP_FD|GROUP_NAMED, PH_FD, TYPE_UIDT, OFUNC_SPEC }; +const struct optdesc opt_user_late = { "user-late", "uid-l", OPT_USER_LATE, GROUP_FD, PH_LATE, TYPE_UIDT, OFUNC_SPEC }; +/* for something like random access files */ +#if HAVE_LSEEK64 +const struct optdesc opt_lseek32_cur = { "lseek32-cur", NULL, OPT_SEEK32_CUR, GROUP_REG|GROUP_BLK, PH_LATE, TYPE_OFF32, OFUNC_SEEK32, SEEK_CUR }; +const struct optdesc opt_lseek32_end = { "lseek32-end", NULL, OPT_SEEK32_END, GROUP_REG|GROUP_BLK, PH_LATE, TYPE_OFF32, OFUNC_SEEK32, SEEK_END }; +const struct optdesc opt_lseek32_set = { "lseek32-set", NULL, OPT_SEEK32_SET, GROUP_REG|GROUP_BLK, PH_LATE, TYPE_OFF32, OFUNC_SEEK32, SEEK_SET }; +const struct optdesc opt_lseek64_cur = { "lseek64-cur", "seek-cur", OPT_SEEK64_CUR, GROUP_REG|GROUP_BLK, PH_LATE, TYPE_OFF64, OFUNC_SEEK64, SEEK_CUR }; +const struct optdesc opt_lseek64_end = { "lseek64-end", "seek-end", OPT_SEEK64_END, GROUP_REG|GROUP_BLK, PH_LATE, TYPE_OFF64, OFUNC_SEEK64, SEEK_END }; +const struct optdesc opt_lseek64_set = { "lseek64-set", "seek", OPT_SEEK64_SET, GROUP_REG|GROUP_BLK, PH_LATE, TYPE_OFF64, OFUNC_SEEK64, SEEK_SET }; +#else +const struct optdesc opt_lseek32_cur = { "lseek32-cur", "seek-cur", OPT_SEEK32_CUR, GROUP_REG|GROUP_BLK, PH_LATE, TYPE_OFF32, OFUNC_SEEK32, SEEK_CUR }; +const struct optdesc opt_lseek32_end = { "lseek32-end", "seek-end", OPT_SEEK32_END, GROUP_REG|GROUP_BLK, PH_LATE, TYPE_OFF32, OFUNC_SEEK32, SEEK_END }; +const struct optdesc opt_lseek32_set = { "lseek32-set", "seek", OPT_SEEK32_SET, GROUP_REG|GROUP_BLK, PH_LATE, TYPE_OFF32, OFUNC_SEEK32, SEEK_SET }; +#endif /* !HAVE_LSEEK64 */ +/* for all addresses (?) */ +const struct optdesc opt_f_setlk_rd = { "f-setlk-rd", "setlk-rd", OPT_F_SETLK_RD, GROUP_FD, PH_FD,TYPE_BOOL, OFUNC_SPEC, F_SETLK, F_RDLCK }; +const struct optdesc opt_f_setlkw_rd = { "f-setlkw-rd", "setlkw-rd",OPT_F_SETLKW_RD, GROUP_FD, PH_FD,TYPE_BOOL, OFUNC_SPEC, F_SETLKW, F_RDLCK }; +const struct optdesc opt_f_setlk_wr = { "f-setlk-wr", "setlk", OPT_F_SETLK_WR, GROUP_FD, PH_FD,TYPE_BOOL, OFUNC_SPEC, F_SETLK, F_WRLCK }; +const struct optdesc opt_f_setlkw_wr = { "f-setlkw-wr", "setlkw", OPT_F_SETLKW_WR, GROUP_FD, PH_FD,TYPE_BOOL, OFUNC_SPEC, F_SETLKW, F_WRLCK }; +#if HAVE_FLOCK +const struct optdesc opt_flock_sh = { "flock-sh", NULL, OPT_FLOCK_SH, GROUP_FD, PH_FD,TYPE_BOOL, OFUNC_FLOCK, LOCK_SH }; +const struct optdesc opt_flock_sh_nb = { "flock-sh-nb", NULL, OPT_FLOCK_SH_NB, GROUP_FD, PH_FD,TYPE_BOOL, OFUNC_FLOCK, LOCK_SH|LOCK_NB }; +const struct optdesc opt_flock_ex = { "flock-ex", "flock", OPT_FLOCK_EX, GROUP_FD, PH_FD,TYPE_BOOL, OFUNC_FLOCK, LOCK_EX }; +const struct optdesc opt_flock_ex_nb = { "flock-ex-nb", "flock-nb", OPT_FLOCK_EX_NB, GROUP_FD, PH_FD,TYPE_BOOL, OFUNC_FLOCK, LOCK_EX|LOCK_NB }; +#endif /* HAVE_FLOCK */ +const struct optdesc opt_cool_write = { "cool-write", "coolwrite", OPT_COOL_WRITE, GROUP_FD, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.cool_write }; + +/* control closing of connections */ +const struct optdesc opt_end_close = { "end-close", "close", OPT_END_CLOSE, GROUP_FD, PH_INIT, TYPE_CONST, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoend, END_CLOSE }; diff --git a/xio-fd.h b/xio-fd.h new file mode 100644 index 0000000..6e3ed7d --- /dev/null +++ b/xio-fd.h @@ -0,0 +1,41 @@ +/* $Id: xio-fd.h,v 1.12 2006/12/28 07:35:50 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_fd_h_included +#define __xio_fd_h_included 1 + +extern const struct optdesc opt_append; +extern const struct optdesc opt_nonblock; +extern const struct optdesc opt_o_ndelay; +extern const struct optdesc opt_async; +extern const struct optdesc opt_o_binary; +extern const struct optdesc opt_o_text; +extern const struct optdesc opt_o_noinherit; +extern const struct optdesc opt_cloexec; +extern const struct optdesc opt_ftruncate32; +extern const struct optdesc opt_ftruncate64; +extern const struct optdesc opt_group; +extern const struct optdesc opt_group_late; +extern const struct optdesc opt_perm; +extern const struct optdesc opt_perm_late; +extern const struct optdesc opt_user; +extern const struct optdesc opt_user_late; +extern const struct optdesc opt_lseek32_cur; +extern const struct optdesc opt_lseek32_end; +extern const struct optdesc opt_lseek32_set; +extern const struct optdesc opt_lseek64_cur; +extern const struct optdesc opt_lseek64_end; +extern const struct optdesc opt_lseek64_set; +extern const struct optdesc opt_flock_sh; +extern const struct optdesc opt_flock_sh_nb; +extern const struct optdesc opt_flock_ex; +extern const struct optdesc opt_flock_ex_nb; +extern const struct optdesc opt_f_setlk_rd; +extern const struct optdesc opt_f_setlkw_rd; +extern const struct optdesc opt_f_setlk_wr; +extern const struct optdesc opt_f_setlkw_wr; +extern const struct optdesc opt_cool_write; +extern const struct optdesc opt_end_close; + +#endif /* !defined(__xio_fd_h_included) */ diff --git a/xio-fdnum.c b/xio-fdnum.c new file mode 100644 index 0000000..859a816 --- /dev/null +++ b/xio-fdnum.c @@ -0,0 +1,78 @@ +/* $Id: xio-fdnum.c,v 1.13 2006/07/08 10:03:14 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for opening addresses of fdnum type */ + +#include "xiosysincludes.h" +#include "xioopen.h" + +#include "xio-fdnum.h" + + +#if WITH_FDNUM + +static int xioopen_fdnum(int argc, const char *argv[], struct opt *opts, int rw, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3); + + +const struct addrdesc addr_fd = { "fd", 3, xioopen_fdnum, 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(":") }; + + +/* use some file descriptor and apply the options. Set the FD_CLOEXEC flag. */ +static int xioopen_fdnum(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xfd, unsigned groups, + int dummy1, int dummy2, int dummy3) { + char *a1; + int rw = (xioflags&XIO_ACCMODE); + int numfd; + int result; + + if (argc != 2) { + Error3("%s:%s: wrong number of parameters (%d instead of 1)", argv[0], argv[1], argc-1); + } + + numfd = strtoul(argv[1], &a1, 0); + if (*a1 != '\0') { + Error1("error in FD number \"%s\"", argv[1]); + } + /* we dont want to see these fds in child processes */ + if (Fcntl_l(numfd, F_SETFD, FD_CLOEXEC) < 0) { + Warn2("fcntl(%d, F_SETFD, FD_CLOEXEC): %s", numfd, strerror(errno)); + } + Notice2("using file descriptor %d for %s", numfd, ddirection[rw]); + if ((result = xioopen_fd(opts, rw, &xfd->stream, numfd, dummy2, dummy3)) < 0) { + return result; + } + return 0; +} + +#endif /* WITH_FDNUM */ + +#if WITH_FD + +/* retrieve and apply options to a standard file descriptor. + Do not set FD_CLOEXEC flag. */ +int xioopen_fd(struct opt *opts, int rw, xiosingle_t *xfd, int numfd, int dummy2, int dummy3) { + + xfd->fd = numfd; + xfd->howtoend = END_NONE; + +#if WITH_TERMIOS + if (Isatty(xfd->fd)) { + if (Tcgetattr(xfd->fd, &xfd->savetty) < 0) { + Warn2("cannot query current terminal settings on fd %d: %s", + xfd->fd, strerror(errno)); + } else { + xfd->ttyvalid = true; + } + } +#endif /* WITH_TERMIOS */ + if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; + applyopts(-1, opts, PH_INIT); + + applyopts2(xfd->fd, opts, PH_INIT, PH_FD); + + return _xio_openlate(xfd, opts); +} + +#endif /* WITH_FD */ diff --git a/xio-fdnum.h b/xio-fdnum.h new file mode 100644 index 0000000..f9acf03 --- /dev/null +++ b/xio-fdnum.h @@ -0,0 +1,12 @@ +/* $Id: xio-fdnum.h,v 1.6 2006/03/21 20:48:31 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_fdnum_h_included +#define __xio_fdnum_h_included 1 + +extern const struct addrdesc addr_fd; + +extern int xioopen_fd(struct opt *opts, int rw, xiosingle_t *xfd, int numfd, int dummy2, int dummy3); + +#endif /* !defined(__xio_fdnum_h_included) */ diff --git a/xio-file.c b/xio-file.c new file mode 100644 index 0000000..2156913 --- /dev/null +++ b/xio-file.c @@ -0,0 +1,124 @@ +/* $Id: xio-file.c,v 1.21 2007/03/06 21:07:25 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for opening addresses of open type */ + +#include "xiosysincludes.h" +#include "xioopen.h" + +#include "xio-named.h" +#include "xio-file.h" + + +static int xioopen_open(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); + + +#if WITH_OPEN + +/****** OPEN addresses ******/ +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_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 +const struct optdesc opt_o_sync = { "o-sync", "sync", OPT_O_SYNC, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_SYNC }; +#endif +#ifdef O_NOFOLLOW +const struct optdesc opt_o_nofollow = { "o-nofollow", "nofollow",OPT_O_NOFOLLOW, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_NOFOLLOW }; +#endif +#ifdef O_DIRECTORY +const struct optdesc opt_o_directory = { "o-directory", "directory",OPT_O_DIRECTORY, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_DIRECTORY }; +#endif +#ifdef O_LARGEFILE +const struct optdesc opt_o_largefile = { "o-largefile", "largefile",OPT_O_LARGEFILE, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_LARGEFILE }; +#endif +#ifdef O_NSHARE +const struct optdesc opt_o_nshare = { "o-nshare", "nshare", OPT_O_NSHARE, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_NSHARE }; +#endif +#ifdef O_RSHARE +const struct optdesc opt_o_rshare = { "o-rshare", "rshare", OPT_O_RSHARE, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_RSHARE }; +#endif +#ifdef O_DEFER +const struct optdesc opt_o_defer = { "o-defer", "defer", OPT_O_DEFER, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_DEFER }; +#endif +#ifdef O_DIRECT +const struct optdesc opt_o_direct = { "o-direct", "direct", OPT_O_DIRECT, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_DIRECT }; +#endif +#ifdef O_DSYNC +const struct optdesc opt_o_dsync = { "o-dsync", "dsync", OPT_O_DSYNC, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_DSYNC }; +#endif +#ifdef O_RSYNC +const struct optdesc opt_o_rsync = { "o-rsync", "rsync", OPT_O_RSYNC, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_RSYNC }; +#endif +#ifdef O_DELAY +const struct optdesc opt_o_delay = { "o-delay", "delay", OPT_O_DELAY, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_DELAY }; +#endif +#ifdef O_PRIV +const struct optdesc opt_o_priv = { "o-priv", "priv", OPT_O_PRIV, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_PRIV }; +#endif +const struct optdesc opt_o_trunc = { "o-trunc", "trunc", OPT_O_TRUNC, GROUP_OPEN, PH_LATE, TYPE_BOOL, OFUNC_FLAG, O_TRUNC }; + +#endif /* WITH_OPEN */ + + +#if _WITH_FILE /*! inconsistent name FILE vs. OPEN */ + +const struct addrdesc addr_open = { "open", 3, xioopen_open, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_REG|GROUP_NAMED|GROUP_OPEN|GROUP_FILE|GROUP_TERMIOS, 0, 0, 0 HELP(":") }; + +/* open for writing: + if the filesystem entry already exists, the data is appended + if it does not exist, a file is created and the data is appended +*/ +static int xioopen_open(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3) { + const char *filename = argv[1]; + int rw = (xioflags & XIO_ACCMODE); + bool exists; + bool opt_unlink_close = false; + int result; + + /* remove old file, or set user/permissions on old file; parse options */ + if ((result = _xioopen_named_early(argc, argv, fd, groups, &exists, opts)) < 0) { + return result; + } + + retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); + if (opt_unlink_close) { + if ((fd->stream.unlink_close = strdup(filename)) == NULL) { + Error1("strdup(\"%s\"): out of memory", filename); + } + fd->stream.opt_unlink_close = true; + } + + Notice3("opening %s \"%s\" for %s", + filetypenames[(result&S_IFMT)>>12], filename, ddirection[rw]); + if ((result = _xioopen_open(filename, rw, opts)) < 0) + return result; + fd->stream.fd = result; + +#if WITH_TERMIOS + if (Isatty(fd->stream.fd)) { + if (Tcgetattr(fd->stream.fd, &fd->stream.savetty) < 0) { + Warn2("cannot query current terminal settings on fd %d: %s", + fd->stream.fd, strerror(errno)); + } else { + fd->stream.ttyvalid = true; + } + } +#endif /* WITH_TERMIOS */ + + applyopts_named(filename, opts, PH_FD); + applyopts(fd->stream.fd, opts, PH_FD); + applyopts_cloexec(fd->stream.fd, opts); + + applyopts_fchown(fd->stream.fd, opts); + + if ((result = _xio_openlate(&fd->stream, opts)) < 0) + return result; + + return 0; +} + +#endif /* _WITH_FILE */ diff --git a/xio-file.h b/xio-file.h new file mode 100644 index 0000000..03d16c9 --- /dev/null +++ b/xio-file.h @@ -0,0 +1,31 @@ +/* $Id: xio-file.h,v 1.8 2006/07/13 21:19:15 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_file_h_included +#define __xio_file_h_included 1 + +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_excl; +extern const struct optdesc opt_o_noctty; +extern const struct optdesc opt_o_sync; +extern const struct optdesc opt_o_nofollow; +extern const struct optdesc opt_o_directory; +extern const struct optdesc opt_o_largefile; +extern const struct optdesc opt_o_nshare; +extern const struct optdesc opt_o_rshare; +extern const struct optdesc opt_o_defer; +extern const struct optdesc opt_o_direct; +extern const struct optdesc opt_o_dsync; +extern const struct optdesc opt_o_rsync; +extern const struct optdesc opt_o_delay; +extern const struct optdesc opt_o_priv; +extern const struct optdesc opt_o_trunc; +extern const struct optdesc opt_o_noatime; + +extern const struct addrdesc addr_open; + +#endif /* !defined(__xio_file_h_included) */ diff --git a/xio-gopen.c b/xio-gopen.c new file mode 100644 index 0000000..3108da8 --- /dev/null +++ b/xio-gopen.c @@ -0,0 +1,218 @@ +/* $Id: xio-gopen.c,v 1.32 2007/02/08 18:36:44 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for opening addresses of generic open type */ + +#include "xiosysincludes.h" +#include "xioopen.h" + +#include "xio-named.h" +#include "xio-unix.h" +#include "xio-gopen.h" + + +#if WITH_GOPEN + +static int xioopen_gopen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); + + +const struct addrdesc addr_gopen = { "gopen", 3, xioopen_gopen, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_REG|GROUP_NAMED|GROUP_OPEN|GROUP_FILE|GROUP_TERMIOS|GROUP_SOCKET|GROUP_SOCK_UNIX, 0, 0, 0 HELP(":") }; + +static int xioopen_gopen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3) { + const char *filename = argv[1]; + flags_t openflags = (xioflags & XIO_ACCMODE); + mode_t st_mode; + bool exists; + bool opt_unlink_close = false; + int result; + + if ((result = + _xioopen_named_early(argc, argv, fd, GROUP_NAMED|groups, &exists, opts)) < 0) { + return result; + } + st_mode = result; + + if (exists) { + /* file (or at least named entry) exists */ + if ((xioflags&XIO_ACCMODE) != XIO_RDONLY) { + openflags |= O_APPEND; + } + } else { + openflags |= O_CREAT; + } + + /* note: when S_ISSOCK was undefined, it always gives 0 */ + if (exists && S_ISSOCK(st_mode)) { +#if WITH_UNIX + int socktype = SOCK_STREAM; + int optsotype = -1; + struct sockaddr_un sa, us; + socklen_t salen, uslen = sizeof(us); + bool needbind = false; + char infobuff[256]; + struct opt *opts2; + + socket_un_init(&sa); + socket_un_init(&us); + + Info1("\"%s\" is a socket, connecting to it", filename); + if (retropt_int(opts, OPT_SO_TYPE, &optsotype) == 0) { + socktype = optsotype; + } + + if (retropt_bind(opts, AF_UNIX, socktype, 0, (struct sockaddr *)&us, &uslen, 0, 0, 0) != STAT_NOACTION) { + needbind = true; + } + + retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); + if (opt_unlink_close) { + if ((fd->stream.unlink_close = strdup(filename)) == NULL) { + Error1("strdup(\"%s\"): out of memory", filename); + } + fd->stream.opt_unlink_close = true; + } + + /* save options, because we might have to start again with Socket() */ + opts2 = copyopts(opts, GROUP_ALL); + + if ((fd->stream.fd = Socket(PF_UNIX, socktype, 0)) < 0) { + Error2("socket(PF_UNIX, %d, 0): %s", socktype, strerror(errno)); + return STAT_RETRYLATER; + } + /*0 Info2("socket(PF_UNIX, %d, 0) -> %d", socktype, fd->stream.fd);*/ + applyopts(fd->stream.fd, opts, PH_PASTSOCKET); + applyopts(fd->stream.fd, opts, PH_FD); + + applyopts_cloexec(fd->stream.fd, opts); + + sa.sun_family = AF_UNIX; + salen = xiosetunix(&sa, filename, false, false); + +#if 0 + applyopts(fd->stream.fd, opts, PH_PREBIND); + applyopts(fd->stream.fd, opts, PH_BIND); + if (us) { + if (Bind(fd->stream.fd, us, uslen) < 0) { + Error4("bind(%d, {%s}, "F_Zd"): %s", + fd->fd, sockaddr_info(us, infobuff, sizeof(infobuff)), + uslen, strerror(errno)); + if (fd->forever || --fd->retry) { + Nanosleep(&fd->intervall, NULL); + continue; + } else + return STAT_RETRYLATER; + } + } + applyopts(fd->stream.fd, opts, PH_PASTBIND); +#endif /* 0 */ + + applyopts(fd->stream.fd, opts, PH_CONNECT); + if ((result = Connect(fd->stream.fd, (struct sockaddr *)&sa, salen)) < 0) { + if (errno == EINPROGRESS) { + Warn4("connect(%d, %s, "F_Zd"): %s", + fd->stream.fd, sockaddr_unix_info(&sa, salen, infobuff, sizeof(infobuff)), + sizeof(sa), strerror(errno)); + } else if (errno == EPROTOTYPE && optsotype != SOCK_STREAM) { + Warn4("connect(%d, %s, "F_Zd"): %s", + fd->stream.fd, sockaddr_unix_info(&sa, salen, infobuff, sizeof(infobuff)), + sizeof(sa), strerror(errno)); + Info("assuming datagram socket"); + Close(fd->stream.fd); + + opts = opts2; + if ((fd->stream.fd = Socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) { + Error1("socket(PF_UNIX, SOCK_DGRAM, 0): %s", strerror(errno)); + return STAT_RETRYLATER; + } + /*0 Info1("socket(PF_UNIX, SOCK_DGRAM, 0) -> %d", fd->stream.fd);*/ + + applyopts(fd->stream.fd, opts, PH_PASTSOCKET); + applyopts(fd->stream.fd, opts, PH_FD); + + applyopts_cloexec(fd->stream.fd, opts); + + sa.sun_family = AF_UNIX; + strncpy(sa.sun_path, filename, sizeof(sa.sun_path)); + + fd->stream.dtype = XIODATA_RECVFROM; + fd->stream.salen = sizeof(sa); + memcpy(&fd->stream.peersa.soa, &sa, fd->stream.salen); + } else { + Error4("connect(%d, %s, "F_Zd"): %s", + fd->stream.fd, sockaddr_unix_info(&sa, fd->stream.salen, infobuff, sizeof(infobuff)), + sizeof(sa), strerror(errno)); + return STAT_RETRYLATER; + } + } + if (fd->stream.howtoend == END_UNSPEC) { + fd->stream.howtoend = END_SHUTDOWN; + } + + applyopts_fchown(fd->stream.fd, opts); + applyopts(fd->stream.fd, opts, PH_CONNECTED); + applyopts(fd->stream.fd, opts, PH_LATE); + applyopts_named(filename, opts, PH_PASTOPEN); /* unlink-late */ + + if (Getsockname(fd->stream.fd, (struct sockaddr *)&us, &uslen) < 0) { + Warn4("getsockname(%d, %p, {%d}): %s", + fd->stream.fd, &us, uslen, strerror(errno)); + } else { + Notice1("successfully connected via %s", + sockaddr_unix_info(&us, uslen, infobuff, sizeof(infobuff))); + } +#else + Error("\"%s\" is a socket, but UNIX socket support is not compiled in"); + return -1; +#endif /* WITH_UNIX */ + + } else { + /* a file name */ + + Info1("\"%s\" is not a socket, open()'ing it", filename); + + retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); + if (opt_unlink_close) { + if ((fd->stream.unlink_close = strdup(filename)) == NULL) { + Error1("strdup(\"%s\"): out of memory", filename); + } + fd->stream.opt_unlink_close = true; + } + + Notice3("opening %s \"%s\" for %s", + filetypenames[(st_mode&S_IFMT)>>12], filename, ddirection[(xioflags&XIO_ACCMODE)]); + if ((result = _xioopen_open(filename, openflags, opts)) < 0) + return result; +#ifdef I_PUSH + if (S_ISCHR(st_mode)) { + Ioctl(result, I_PUSH, "ptem"); + Ioctl(result, I_PUSH, "ldterm"); + Ioctl(result, I_PUSH, "ttcompat"); + } +#endif + fd->stream.fd = result; + +#if WITH_TERMIOS + if (Isatty(fd->stream.fd)) { + if (Tcgetattr(fd->stream.fd, &fd->stream.savetty) < 0) { + Warn2("cannot query current terminal settings on fd %d: %s", + fd->stream.fd, strerror(errno)); + } else { + fd->stream.ttyvalid = true; + } + } +#endif /* WITH_TERMIOS */ + applyopts_named(filename, opts, PH_FD); + applyopts(fd->stream.fd, opts, PH_FD); + applyopts_cloexec(fd->stream.fd, opts); + } + + if ((result = applyopts2(fd->stream.fd, opts, PH_PASTSOCKET, PH_CONNECTED)) < 0) + return result; + + if ((result = _xio_openlate(&fd->stream, opts)) < 0) + return result; + return 0; +} + +#endif /* WITH_GOPEN */ diff --git a/xio-gopen.h b/xio-gopen.h new file mode 100644 index 0000000..dff3084 --- /dev/null +++ b/xio-gopen.h @@ -0,0 +1,10 @@ +/* $Id: xio-gopen.h,v 1.4 2001/11/04 17:19:20 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_gopen_h_included +#define __xio_gopen_h_included 1 + +extern const struct addrdesc addr_gopen; + +#endif /* !defined(__xio_gopen_h_included) */ diff --git a/xio-ip.c b/xio-ip.c new file mode 100644 index 0000000..cb065dc --- /dev/null +++ b/xio-ip.c @@ -0,0 +1,510 @@ +/* $Id: xio-ip.c,v 1.31 2007/03/06 21:08:02 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for IP related functions */ + +#include "xiosysincludes.h" + +#if _WITH_IP4 || _WITH_IP6 + +#include "xioopen.h" +#include "xio-socket.h" +#include "xio-ip.h" +#include "xio-ip6.h" + + +#if WITH_IP4 || WITH_IP6 + +#ifdef IP_OPTIONS +const struct optdesc opt_ip_options = { "ip-options", "ipoptions", OPT_IP_OPTIONS, GROUP_SOCK_IP, PH_PASTSOCKET,TYPE_BIN, OFUNC_SOCKOPT_APPEND, SOL_IP, IP_OPTIONS }; +#endif +#ifdef IP_PKTINFO +const struct optdesc opt_ip_pktinfo = { "ip-pktinfo", "pktinfo", OPT_IP_PKTINFO, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_PKTINFO }; +#endif +#ifdef IP_RECVTOS +const struct optdesc opt_ip_recvtos = { "ip-recvtos", "recvtos", OPT_IP_RECVTOS, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_RECVTOS }; +#endif +#ifdef IP_RECVTTL +const struct optdesc opt_ip_recvttl = { "ip-recvttl", "recvttl", OPT_IP_RECVTTL, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_RECVTTL }; +#endif +#ifdef IP_RECVOPTS +const struct optdesc opt_ip_recvopts= { "ip-recvopts","recvopts", OPT_IP_RECVOPTS,GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_RECVOPTS }; +#endif +#ifdef IP_RETOPTS +const struct optdesc opt_ip_retopts = { "ip-retopts", "retopts", OPT_IP_RETOPTS, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_RETOPTS }; +#endif +const struct optdesc opt_ip_tos = { "ip-tos", "tos", OPT_IP_TOS, GROUP_SOCK_IP, PH_PASTSOCKET,TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_TOS }; +const struct optdesc opt_ip_ttl = { "ip-ttl", "ttl", OPT_IP_TTL, GROUP_SOCK_IP, PH_PASTSOCKET,TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_TTL }; +#ifdef IP_HDRINCL +const struct optdesc opt_ip_hdrincl = { "ip-hdrincl", "hdrincl", OPT_IP_HDRINCL, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_HDRINCL }; +#endif +#ifdef IP_RECVERR +const struct optdesc opt_ip_recverr = { "ip-recverr", "recverr", OPT_IP_RECVERR, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_RECVERR }; +#endif +#ifdef IP_MTU_DISCOVER +const struct optdesc opt_ip_mtu_discover={"ip-mtu-discover","mtudiscover",OPT_IP_MTU_DISCOVER,GROUP_SOCK_IP,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_IP,IP_MTU_DISCOVER }; +#endif +#ifdef IP_MTU +const struct optdesc opt_ip_mtu = { "ip-mtu", "mtu", OPT_IP_MTU, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_MTU }; +#endif +#ifdef IP_FREEBIND +const struct optdesc opt_ip_freebind= { "ip-freebind","freebind", OPT_IP_FREEBIND,GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_FREEBIND }; +#endif +#ifdef IP_ROUTER_ALERT +const struct optdesc opt_ip_router_alert={"ip-router-alert","routeralert",OPT_IP_ROUTER_ALERT,GROUP_SOCK_IP,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_IP,IP_ROUTER_ALERT}; +#endif +/* following: Linux allows int but OpenBSD reqs char/byte */ +const struct optdesc opt_ip_multicast_ttl={"ip-multicast-ttl","multicastttl",OPT_IP_MULTICAST_TTL,GROUP_SOCK_IP,PH_PASTSOCKET,TYPE_BYTE,OFUNC_SOCKOPT,SOL_IP,IP_MULTICAST_TTL}; +const struct optdesc opt_ip_multicast_loop={"ip-multicast-loop","multicastloop",OPT_IP_MULTICAST_LOOP,GROUP_SOCK_IP,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_IP,IP_MULTICAST_LOOP}; +const struct optdesc opt_ip_multicast_if ={"ip-multicast-if", "multicast-if", OPT_IP_MULTICAST_IF, GROUP_SOCK_IP,PH_PASTSOCKET,TYPE_IP4NAME,OFUNC_SOCKOPT,SOL_IP,IP_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 +const struct optdesc opt_ip_add_membership = { "ip-add-membership", "membership",OPT_IP_ADD_MEMBERSHIP, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_IP_MREQN, OFUNC_SOCKOPT, SOL_IP, IP_ADD_MEMBERSHIP }; +#endif + +#if HAVE_RESOLV_H +const struct optdesc opt_res_debug = { "res-debug", NULL, OPT_RES_DEBUG, GROUP_SOCK_IP, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, (size_t)&((xiosingle_t *)0)->para.socket.ip.res_opts, sizeof(unsigned long), RES_DEBUG }; +const struct optdesc opt_res_aaonly = { "res-aaonly", "aaonly", OPT_RES_AAONLY, GROUP_SOCK_IP, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, (size_t)&((xiosingle_t *)0)->para.socket.ip.res_opts, sizeof(unsigned long), RES_AAONLY }; +const struct optdesc opt_res_usevc = { "res-usevc", "usevc", OPT_RES_USEVC, GROUP_SOCK_IP, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, (size_t)&((xiosingle_t *)0)->para.socket.ip.res_opts, sizeof(unsigned long), RES_USEVC }; +const struct optdesc opt_res_primary = { "res-primary", "primary", OPT_RES_PRIMARY, GROUP_SOCK_IP, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, (size_t)&((xiosingle_t *)0)->para.socket.ip.res_opts, sizeof(unsigned long), RES_PRIMARY }; +const struct optdesc opt_res_igntc = { "res-igntc", "igntc", OPT_RES_IGNTC, GROUP_SOCK_IP, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, (size_t)&((xiosingle_t *)0)->para.socket.ip.res_opts, sizeof(unsigned long), RES_IGNTC }; +const struct optdesc opt_res_recurse = { "res-recurse", "recurse", OPT_RES_RECURSE, GROUP_SOCK_IP, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, (size_t)&((xiosingle_t *)0)->para.socket.ip.res_opts, sizeof(unsigned long), RES_RECURSE }; +const struct optdesc opt_res_defnames = { "res-defnames", "defnames", OPT_RES_DEFNAMES, GROUP_SOCK_IP, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, (size_t)&((xiosingle_t *)0)->para.socket.ip.res_opts, sizeof(unsigned long), RES_DEFNAMES }; +const struct optdesc opt_res_stayopen = { "res-stayopen", "stayopen", OPT_RES_STAYOPEN, GROUP_SOCK_IP, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, (size_t)&((xiosingle_t *)0)->para.socket.ip.res_opts, sizeof(unsigned long), RES_STAYOPEN }; +const struct optdesc opt_res_dnsrch = { "res-dnsrch", "dnsrch", OPT_RES_DNSRCH, GROUP_SOCK_IP, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, (size_t)&((xiosingle_t *)0)->para.socket.ip.res_opts, sizeof(unsigned long), RES_DNSRCH }; +#endif /* HAVE_RESOLV_H */ + +#endif /* WITH_IP4 || WITH_IP6 */ + + +#if HAVE_RESOLV_H +int Res_init(void) { + int result; + Debug("res_init()"); + result = res_init(); + Debug1("res_init() -> %d", result); + return result; +} +#endif /* HAVE_RESOLV_H */ + +#if HAVE_RESOLV_H +unsigned long res_opts() { + return _res.options; +} +#endif /* HAVE_RESOLV_H */ + +/* the ultimate(?) socat resolver function + node: the address to be resolved; supported forms: + 1.2.3.4 (IPv4 address) + [::2] (IPv6 address) + hostname (hostname resolving to IPv4 or IPv6 address) + hostname.domain (fq hostname resolving to IPv4 or IPv6 address) + service: the port specification; may be numeric or symbolic + 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 + returns: STAT_OK, STAT_RETRYLATER +*/ +int xiogetaddrinfo(const char *node, const char *service, + int family, int socktype, int protocol, + union sockaddr_union *sau, socklen_t *socklen, + unsigned long res_opts0, unsigned long res_opts1) { + int port = -1; + char *numnode = NULL; + size_t nodelen; + unsigned long save_res_opts = 0; +#if HAVE_GETADDRINFO + struct addrinfo hints = {0}; + struct addrinfo *res = NULL; +#else /* HAVE_GETIPNODEBYNAME || nothing */ + struct hostent *host; +#endif + int error_num; + +#if HAVE_RESOLV_H + if (res_opts0 | res_opts1) { + if (!(_res.options & RES_INIT)) { + Res_init(); /*!!! returns -1 on error */ + } + save_res_opts = _res.options; + _res.options &= ~res_opts0; + _res.options |= res_opts1; + Debug2("changed _res.options from 0x%lx to 0x%lx", + save_res_opts, _res.options); + } +#endif /* HAVE_RESOLV_H */ + memset(sau, 0, *socklen); + sau->soa.sa_family = family; + + /* if service is numeric we don't want to have a lookup (might take long + with NIS), so we handle this specially */ + if (service && isdigit(service[0]&0xff)) { + char *extra; + port = strtoul(service, &extra, 0); + if (*extra != '\0') { + Warn2("xiogetaddrinfo(, \"%s\", ...): extra trailing data \"%s\"", + service, extra); + } + service = NULL; + } + + /* 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 */ + if (node && isdigit(node[0]&0xff)) { +#if HAVE_GETADDRINFO + hints.ai_flags |= AI_NUMERICHOST; +#endif /* HAVE_GETADDRINFO */ + if (family == PF_UNSPEC) { + family = PF_INET; +#if HAVE_GETADDRINFO + } else if (family == PF_INET6) { + /* map "explicitely" into IPv6 address space; getipnodebyname() does + this with AI_V4MAPPED, but not getaddrinfo() */ + if ((numnode = Malloc(strlen(node)+7+1)) == NULL) { +#if HAVE_RESOLV_H + if (res_opts0 | res_opts1) { + _res.options = (_res.options & (~res_opts0&~res_opts1) | + save_res_opts& ( res_opts0| res_opts1)); + } +#endif + return STAT_NORETRY; + } + sprintf(numnode, "::ffff:%s", node); + node = numnode; + hints.ai_flags |= AI_NUMERICHOST; +#endif /* HAVE_GETADDRINFO */ + } +#if WITH_IP6 + } else if (node && node[0] == '[' && node[(nodelen=strlen(node))-1]==']') { + if ((numnode = Malloc(nodelen-1)) == NULL) { +#if HAVE_RESOLV_H + if (res_opts0 | res_opts1) { + _res.options = (_res.options & (~res_opts0&~res_opts1) | + save_res_opts& ( res_opts0| res_opts1)); + } +#endif + return STAT_NORETRY; + } + strncpy(numnode, node+1, nodelen-2); + numnode[nodelen-2] = '\0'; + node = numnode; +#if HAVE_GETADDRINFO + hints.ai_flags |= AI_NUMERICHOST; +#endif /* HAVE_GETADDRINFO */ + if (family == PF_UNSPEC) family = PF_INET6; +#endif /* WITH_IP6 */ + } + +#if HAVE_GETADDRINFO + if (node != NULL || service != NULL) { + struct addrinfo *record; + + hints.ai_flags |= AI_PASSIVE; + hints.ai_family = family; + hints.ai_socktype = socktype; + hints.ai_protocol = protocol; + hints.ai_addrlen = 0; + hints.ai_addr = NULL; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + + if ((error_num = Getaddrinfo(node, service, &hints, &res)) != 0) { + Error7("getaddrinfo(\"%s\", \"%s\", {%d,%d,%d,%d}, {}): %s", + node, service, 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); + if (numnode) free(numnode); + +#if HAVE_RESOLV_H + if (res_opts0 | res_opts1) { + _res.options = (_res.options & (~res_opts0&~res_opts1) | + save_res_opts& ( res_opts0| res_opts1)); + } +#endif + return STAT_RETRYLATER; + } + + record = res; + if (family == PF_UNSPEC && xioopts.preferred_ip == '0') { + /* we just take the first result */ + family = res[0].ai_addr->sa_family; + } + if (family == PF_UNSPEC) { + int trypf; + trypf = (xioopts.preferred_ip=='6'?PF_INET6:PF_INET); + /* we must look for a matching entry */ + while (record != NULL) { + if (record->ai_family == trypf) { + family = trypf; + break; /* family and record set accordingly */ + } + record = record->ai_next; + } + if (record == NULL) { + /* we did not find a "preferred" entry, take the first */ + record = res; + family = res[0].ai_addr->sa_family; + } + } + + switch (family) { +#if WITH_IP4 + case PF_INET: + if (*socklen > record->ai_addrlen) { + *socklen = record->ai_addrlen; + } + memcpy(&sau->ip4, record->ai_addr, *socklen); + break; +#endif /* WITH_IP4 */ +#if WITH_IP6 + case PF_INET6: +#if _AIX + /* older AIX versions pass wrong length, so we correct it */ + record->ai_addr->sa_len = sizeof(struct sockaddr_in6); +#endif + if (*socklen > record->ai_addrlen) { + *socklen = record->ai_addrlen; + } + memcpy(&sau->ip6, record->ai_addr, *socklen); + break; +#endif /* WITH_IP6 */ + default: + Error1("address resolved to unknown protocol family %d", + record->ai_addr->sa_family); + break; + } + freeaddrinfo(res); + } else { + switch (family) { +#if WITH_IP4 + case PF_INET: *socklen = sizeof(sau->ip4); break; +#endif /* WITH_IP4 */ +#if WITH_IP6 + case PF_INET6: *socklen = sizeof(sau->ip6); break; +#endif /* WITH_IP6 */ + } + } + +#elif HAVE_GETIPNODEBYNAME /* !HAVE_GETADDRINFO */ + + if (node != NULL) { + /* first fallback is getipnodebyname() */ + if (family == PF_UNSPEC) { +#if WITH_IP4 && WITH_IP6 + family = xioopts.default_ip=='6'?PF_INET6:PF_INET; +#elif WITH_IP6 + family = PF_INET6; +#else + family = PF_INET; +#endif + } + host = Getipnodebyname(node, family, AI_V4MAPPED, &error_num); + if (host == NULL) { + const static char ai_host_not_found[] = "Host not found"; + const static char ai_no_address[] = "No address"; + const static char ai_no_recovery[] = "No recovery"; + const static char ai_try_again[] = "Try again"; + const char *error_msg = "Unknown error"; + switch (error_num) { + case HOST_NOT_FOUND: error_msg = ai_host_not_found; break; + case NO_ADDRESS: error_msg = ai_no_address; + case NO_RECOVERY: error_msg = ai_no_recovery; + case TRY_AGAIN: error_msg = ai_try_again; + } + Error2("getipnodebyname(\"%s\", ...): %s", node, error_msg); + } else { + switch (family) { +#if WITH_IP4 + case PF_INET: + *socklen = sizeof(sau->ip4); + sau->soa.sa_family = PF_INET; + memcpy(&sau->ip4.sin_addr, host->h_addr_list[0], 4); + break; +#endif +#if WITH_IP6 + case PF_INET6: + *socklen = sizeof(sau->ip6); + sau->soa.sa_family = PF_INET6; + memcpy(&sau->ip6.sin6_addr, host->h_addr_list[0], 16); + break; +#endif + } + } + freehostent(host); + } + +#else /* !HAVE_GETIPNODEBYNAME */ + + if (node != NULL) { + /* this is not a typical IP6 resolver function - but Linux + "man gethostbyname" says that the only supported address type with + this function is AF_INET _at present_, so maybe this fallback will + be useful somewhere sometimesin a future even for IP6 */ + if (family == PF_UNSPEC) { +#if WITH_IP4 && WITH_IP6 + family = xioopts.default_ip=='6'?PF_INET6:PF_INET; +#elif WITH_IP6 + family = PF_INET6; +#else + family = PF_INET; +#endif + } + /*!!! try gethostbyname2 for IP6 */ + if ((host = Gethostbyname(node)) == NULL) { + Error2("gethostbyname(\"%s\"): %s", node, + h_errno == NETDB_INTERNAL ? strerror(errno) : + hstrerror(h_errno)); +#if HAVE_RESOLV_H + if (res_opts0 | res_opts1) { + _res.options = (_res.options & (~res_opts0&~res_opts1) | + save_res_opts& ( res_opts0| res_opts1)); + } +#endif + return STAT_RETRYLATER; + } + if (host->h_addrtype != family) { + Error2("xioaddrinfo(): \"%s\" does not resolve to %s", + node, family==PF_INET?"IP4":"IP6"); + } else { + switch (family) { +#if WITH_IP4 + case PF_INET: + *socklen = sizeof(sau->ip4); + sau->soa.sa_family = PF_INET; + memcpy(&sau->ip4.sin_addr, host->h_addr_list[0], 4); + break; +#endif /* WITH_IP4 */ +#if WITH_IP6 + case PF_INET6: + *socklen = sizeof(sau->ip6); + sau->soa.sa_family = PF_INET6; + memcpy(&sau->ip6.sin6_addr, host->h_addr_list[0], 16); + break; +#endif /* WITH_IP6 */ + } + } + } + +#endif + +#if WITH_TCP || WITH_UDP + if (service) { + port = parseport(service, family); + } + if (port >= 0) { + switch (family) { +#if WITH_IP4 + case PF_INET: sau->ip4.sin_port = htons(port); break; +#endif /* WITH_IP4 */ +#if WITH_IP6 + case PF_INET6: sau->ip6.sin6_port = htons(port); break; +#endif /* WITH_IP6 */ + } + } +#endif /* WITH_TCP || WITH_UDP */ + + if (numnode) free(numnode); + +#if HAVE_RESOLV_H + if (res_opts0 | res_opts1) { + _res.options = (_res.options & (~res_opts0&~res_opts1) | + save_res_opts& ( res_opts0| res_opts1)); + } +#endif /* HAVE_RESOLV_H */ + return STAT_OK; +} + + +int xioparsenetwork(const char *rangename, int pf, union xiorange_union *range) { +#if WITH_IP4 + struct in_addr *netaddr_in = &range->ip4.netaddr; + struct in_addr *netmask_in = &range->ip4.netmask; +#endif /* WITH_IP4 */ + struct hostent *maskaddr; + char *delimpos; /* absolute address of delimiter */ + int bits; + + switch (pf) { +#if WITH_IP4 + char *rangename1; /* a copy of rangename with writing allowed */ + case PF_INET: + if ((rangename1 = strdup(rangename)) == NULL) { + Error1("strdup(\"%s\"): out of memory", rangename); + return STAT_RETRYLATER; + } + + if (delimpos = strchr(rangename1, '/')) { + bits = strtoul(delimpos+1, NULL, 10); + netmask_in->s_addr = htonl((0xffffffff << (32-bits))); + } else if (delimpos = strchr(rangename1, ':')) { + if ((maskaddr = Gethostbyname(delimpos+1)) == NULL) { + Error2("gethostbyname(\"%s\"): %s", delimpos+1, + h_errno == NETDB_INTERNAL ? strerror(errno) : + hstrerror(h_errno)); + return STAT_NORETRY; + } + netmask_in->s_addr = *(uint32_t *)maskaddr->h_addr_list[0]; + } else { + Error1("xioparsenetwork(\"%s\",,): missing netmask delimiter", rangename); + free(rangename1); + return STAT_NORETRY; + } + { + struct hostent *nameaddr; + *delimpos = 0; + if ((nameaddr = Gethostbyname(rangename1)) == NULL) { + Error2("gethostbyname(\"%s\"): %s", rangename1, + h_errno == NETDB_INTERNAL ? strerror(errno) : + hstrerror(h_errno)); + free(rangename1); + return STAT_NORETRY; + } + netaddr_in->s_addr = *(unsigned long *)nameaddr->h_addr_list[0]; + } + free(rangename1); + break; +#endif /* WITH_IP4 */ +#if WITH_IP6 + case PF_INET6: + return xioparsenetwork_ip6(rangename, &range->ip6); + break; +#endif /* WITH_IP6 */ + default: + Error1("range option not supported with address family %d", pf); + return STAT_NORETRY; + } + return STAT_OK; +} + +/* parses a string of form address/bits or address:mask, and fills the fields + of the range union. The addr component is masked with mask. */ +int parserange(const char *rangename, int pf, union xiorange_union *range) { + if (xioparsenetwork(rangename, pf, range) < 0) { + return -1; + } + switch (pf) { +#if WITH_IP4 + case PF_INET: + range->ip4.netaddr.s_addr &= range->ip4.netmask.s_addr; + break; +#endif /* WITH_IP4 */ +#if WITH_IP6 + case PF_INET6: + return xiorange_ip6andmask(&range->ip6); + break; +#endif /* WITH_IP6 */ + default: + Error1("range option not supported with address family %d", pf); + return STAT_NORETRY; + } + return 0; +} + +#endif /* _WITH_IP4 || _WITH_IP6 */ diff --git a/xio-ip.h b/xio-ip.h new file mode 100644 index 0000000..2cf8277 --- /dev/null +++ b/xio-ip.h @@ -0,0 +1,48 @@ +/* $Id: xio-ip.h,v 1.11 2007/03/06 21:19:18 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_ip_h_included +#define __xio_ip_h_included 1 + +extern const struct optdesc opt_ip_options; +extern const struct optdesc opt_ip_pktinfo; +extern const struct optdesc opt_ip_recvtos; +extern const struct optdesc opt_ip_recvttl; +extern const struct optdesc opt_ip_recvopts; +extern const struct optdesc opt_ip_retopts; +extern const struct optdesc opt_ip_tos; +extern const struct optdesc opt_ip_ttl; +extern const struct optdesc opt_ip_hdrincl; +extern const struct optdesc opt_ip_recverr; +extern const struct optdesc opt_ip_mtu_discover; +extern const struct optdesc opt_ip_mtu; +extern const struct optdesc opt_ip_freebind; +extern const struct optdesc opt_ip_router_alert; +extern const struct optdesc opt_ip_multicast_ttl; +extern const struct optdesc opt_ip_multicast_loop; +extern const struct optdesc opt_ip_multicast_if; +extern const struct optdesc opt_ip_pktoptions; +extern const struct optdesc opt_ip_add_membership; + +extern const struct optdesc opt_res_debug; +extern const struct optdesc opt_res_aaonly; +extern const struct optdesc opt_res_usevc; +extern const struct optdesc opt_res_primary; +extern const struct optdesc opt_res_igntc; +extern const struct optdesc opt_res_recurse; +extern const struct optdesc opt_res_defnames; +extern const struct optdesc opt_res_stayopen; +extern const struct optdesc opt_res_dnsrch; + +extern int xiogetaddrinfo(const char *node, const char *service, + int family, int socktype, int protocol, + union sockaddr_union *sa, socklen_t *socklen, + unsigned long res_opts0, unsigned long res_opts1); +extern +int xioparsenetwork(const char *rangename, int pf, + union xiorange_union *range); +extern +int parserange(const char *rangename, int pf, union xiorange_union *range); + +#endif /* !defined(__xio_ip_h_included) */ diff --git a/xio-ip4.c b/xio-ip4.c new file mode 100644 index 0000000..29e121a --- /dev/null +++ b/xio-ip4.c @@ -0,0 +1,46 @@ +/* $Id: xio-ip4.c,v 1.13 2007/03/06 21:08:38 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for IP4 related functions */ + +#include "xiosysincludes.h" + +#if WITH_IP4 + +#include "xioopen.h" +#include "xio-socket.h" +#include "xio-ip.h" +#include "xio-ip4.h" + +/* check if peer address is within permitted range. + return >= 0 if so. */ +int xiocheckrange_ip4(struct sockaddr_in *pa, struct xiorange_ip4 *range) { + struct in_addr *netaddr_in = &range->netaddr; + struct in_addr *netmask_in = &range->netmask; + char addrbuf[256], maskbuf[256]; + char peername[256]; + + /* is provided client address valid? */ + if (pa->sin_addr.s_addr == 0) { + Warn("invalid client address 0.0.0.0"); + return -1; + } + /* client address restriction */ + Debug2("permitted client subnet: %s:%s", + inet4addr_info(ntohl(netaddr_in->s_addr), addrbuf, sizeof(addrbuf)), + inet4addr_info(ntohl(netmask_in->s_addr), maskbuf, sizeof(maskbuf))); + Debug1("client address is 0x%08x", + ntohl(pa->sin_addr.s_addr)); + Debug1("masked address is 0x%08x", + ntohl(pa->sin_addr.s_addr & netmask_in->s_addr)); + if ((pa->sin_addr.s_addr & netmask_in->s_addr) + != netaddr_in->s_addr) { + Debug1("client address %s is not permitted", + sockaddr_inet4_info(pa, peername, sizeof(peername))); + return -1; + } + return 0; +} + +#endif /* WITH_IP4 */ diff --git a/xio-ip4.h b/xio-ip4.h new file mode 100644 index 0000000..5af6e23 --- /dev/null +++ b/xio-ip4.h @@ -0,0 +1,13 @@ +/* $Id: xio-ip4.h,v 1.9 2007/03/06 21:19:18 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_ip4_h_included +#define __xio_ip4_h_included 1 + +extern const struct optdesc opt_ip4_add_membership; + +extern +int xiocheckrange_ip4(struct sockaddr_in *pa, struct xiorange_ip4 *range); + +#endif /* !defined(__xio_ip4_h_included) */ diff --git a/xio-ip6.c b/xio-ip6.c new file mode 100644 index 0000000..78a233f --- /dev/null +++ b/xio-ip6.c @@ -0,0 +1,145 @@ +/* $Id: xio-ip6.c,v 1.31 2007/03/06 21:19:18 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for IP6 related functions */ + +#include "xiosysincludes.h" + +#if WITH_IP6 + +#include "xioopen.h" +#include "xio-socket.h" +#include "xio-ip.h" /* xiogetaddrinfo() */ + +#include "xio-ip6.h" + +#ifdef IPV6_V6ONLY +const struct optdesc opt_ipv6_v6only = { "ipv6-v6only", "ipv6only", OPT_IPV6_V6ONLY, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_BOOL, 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_PASTBIND, TYPE_IP_MREQN, OFUNC_SOCKOPT, SOL_IPV6, IPV6_JOIN_GROUP }; +#endif + +int xioparsenetwork_ip6(const char *rangename, struct xiorange_ip6 *range) { + char *delimpos; /* absolute address of delimiter */ + size_t delimind; /* index of delimiter in string */ + int bits; + char *baseaddr; + union sockaddr_union sockaddr; + socklen_t sockaddrlen = sizeof(sockaddr); + union xioin6_u *rangeaddr = (union xioin6_u *)&range->addr; + union xioin6_u *rangemask = (union xioin6_u *)&range->mask; + union xioin6_u *nameaddr = (union xioin6_u *)&sockaddr.ip6.sin6_addr; + + if (rangename[0] != '[' || rangename[strlen(rangename)-1] != ']') { + Error1("missing brackets for IPv6 range definition \"%s\"", + rangename); + return STAT_NORETRY; + } + if ((delimpos = strchr(rangename, '/')) == NULL) { + Error1("xioparsenetwork_ip6(\"%s\",,): missing mask bits delimiter '/'", + rangename); + return STAT_NORETRY; + } + delimind = delimpos - rangename; + + if ((baseaddr = strdup(rangename+1)) == NULL) { + Error1("strdup(\"%s\"): out of memory", rangename+1); + return STAT_NORETRY; + } + baseaddr[delimind-1] = '\0'; + if (xiogetaddrinfo(baseaddr, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen, + 0, 0) + != STAT_OK) { + return STAT_NORETRY; + } + rangeaddr->u6_addr32[0] = nameaddr->u6_addr32[0]; + rangeaddr->u6_addr32[1] = nameaddr->u6_addr32[1]; + rangeaddr->u6_addr32[2] = nameaddr->u6_addr32[2]; + rangeaddr->u6_addr32[3] = nameaddr->u6_addr32[3]; + bits = strtoul(delimpos+1, NULL, 10); + if (bits > 128) { + Error1("invalid number of mask bits %u", bits); + return STAT_NORETRY; + } + if (bits < 32) { + rangemask->u6_addr32[0] = htonl(0xffffffff << (32-bits)); + rangemask->u6_addr32[1] = 0; + rangemask->u6_addr32[2] = 0; + rangemask->u6_addr32[3] = 0; + } else if (bits < 64) { + rangemask->u6_addr32[0] = 0xffffffff; + rangemask->u6_addr32[1] = htonl(0xffffffff << (64-bits)); + rangemask->u6_addr32[2] = 0; + rangemask->u6_addr32[3] = 0; + } else if (bits < 96) { + rangemask->u6_addr32[0] = 0xffffffff; + rangemask->u6_addr32[1] = 0xffffffff; + rangemask->u6_addr32[2] = htonl(0xffffffff << (96-bits)); + rangemask->u6_addr32[3] = 0; + } else { + rangemask->u6_addr32[0] = 0xffffffff; + rangemask->u6_addr32[1] = 0xffffffff; + rangemask->u6_addr32[2] = 0xffffffff; + rangemask->u6_addr32[3] = htonl(0xffffffff << (128-bits)); + } + return 0; +} + +int xiorange_ip6andmask(struct xiorange_ip6 *range) { + int i; +#if 0 + range->addr.s6_addr32[0] &= range->mask.s6_addr32[0]; + range->addr.s6_addr32[1] &= range->mask.s6_addr32[1]; + range->addr.s6_addr32[2] &= range->mask.s6_addr32[2]; + range->addr.s6_addr32[3] &= range->mask.s6_addr32[3]; +#else + for (i = 0; i < 16; ++i) { + range->addr.s6_addr[i] &= range->mask.s6_addr[i]; + } +#endif + return 0; +} + +/* check if peer address is within permitted range. + return >= 0 if so. */ +int xiocheckrange_ip6(struct sockaddr_in6 *pa, struct xiorange_ip6 *range) { + union xioin6_u masked; + int i; + char peername[256]; + union xioin6_u *rangeaddr = (union xioin6_u *)&range->addr; + union xioin6_u *rangemask = (union xioin6_u *)&range->mask; + + Debug16("permitted client subnet: [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]", + htons(rangeaddr->u6_addr16[0]), htons(rangeaddr->u6_addr16[1]), + htons(rangeaddr->u6_addr16[2]), htons(rangeaddr->u6_addr16[3]), + htons(rangeaddr->u6_addr16[4]), htons(rangeaddr->u6_addr16[5]), + htons(rangeaddr->u6_addr16[6]), htons(rangeaddr->u6_addr16[7]), + htons(rangemask->u6_addr16[0]), htons(rangemask->u6_addr16[1]), + htons(rangemask->u6_addr16[2]), htons(rangemask->u6_addr16[3]), + htons(rangemask->u6_addr16[4]), htons(rangemask->u6_addr16[5]), + htons(rangemask->u6_addr16[6]), htons(rangemask->u6_addr16[7])); + Debug1("client address is %s", + sockaddr_inet6_info(pa, peername, sizeof(peername))); + + for (i = 0; i < 4; ++i) { + masked.u6_addr32[i] = pa->sin6_addr.s6_addr[i] & rangemask->u6_addr16[i]; + } + Debug8("masked address is [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]", + htons(masked.u6_addr16[0]), htons(masked.u6_addr16[1]), + htons(masked.u6_addr16[2]), htons(masked.u6_addr16[3]), + htons(masked.u6_addr16[4]), htons(masked.u6_addr16[5]), + htons(masked.u6_addr16[6]), htons(masked.u6_addr16[7])); + + if (masked.u6_addr32[0] != rangeaddr->u6_addr32[0] || + masked.u6_addr32[1] != rangeaddr->u6_addr32[1] || + masked.u6_addr32[2] != rangeaddr->u6_addr32[2] || + masked.u6_addr32[3] != rangeaddr->u6_addr32[3]) { + Debug1("client address %s is not permitted", peername); + return -1; + } + return 0; +} + +#endif /* WITH_IP6 */ diff --git a/xio-ip6.h b/xio-ip6.h new file mode 100644 index 0000000..2c5b809 --- /dev/null +++ b/xio-ip6.h @@ -0,0 +1,22 @@ +/* $Id: xio-ip6.h,v 1.13 2007/03/06 21:19:18 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_ip6_h_included +#define __xio_ip6_h_included 1 + +#if WITH_IP6 + +extern const struct optdesc opt_ipv6_v6only; +extern const struct optdesc opt_ipv6_join_group; + +extern +int xioparsenetwork_ip6(const char *rangename, struct xiorange_ip6 *range); +extern int xiorange_ip6andmask(struct xiorange_ip6 *range); + +extern +int xiocheckrange_ip6(struct sockaddr_in6 *pa, struct xiorange_ip6 *range); + +#endif /* WITH_IP6 */ + +#endif /* !defined(__xio_ip6_h_included) */ diff --git a/xio-ipapp.c b/xio-ipapp.c new file mode 100644 index 0000000..b1fd5c3 --- /dev/null +++ b/xio-ipapp.c @@ -0,0 +1,298 @@ +/* $Id: xio-ipapp.c,v 1.34 2007/02/08 18:27:00 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for TCP and UDP related options */ + +#include "xiosysincludes.h" + +#if WITH_TCP || WITH_UDP + +#include "xioopen.h" +#include "xio-socket.h" +#include "xio-ip.h" +#include "xio-listen.h" +#include "xio-ip6.h" +#include "xio-ipapp.h" + +const struct optdesc opt_sourceport = { "sourceport", "sp", OPT_SOURCEPORT, GROUP_IPAPP, PH_LATE,TYPE_2BYTE, OFUNC_SPEC }; +/*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 +/* we expect the form "host:port" */ +int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xxfd, + unsigned groups, int socktype, int ipproto, + int pf) { + struct single *xfd = &xxfd->stream; + struct opt *opts0 = NULL; + const char *hostname = argv[1], *portname = argv[2]; + bool dofork = false; + union sockaddr_union us_sa, *us = &us_sa; + union sockaddr_union them_sa, *them = &them_sa; + socklen_t uslen = sizeof(us_sa); + socklen_t themlen = sizeof(them_sa); + bool needbind = false; + bool lowport = false; + int level; + int result; + + if (argc != 3) { + Error2("%s: wrong number of parameters (%d instead of 2)", argv[0], argc-1); + } + + xfd->howtoend = END_SHUTDOWN; + + if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; + applyopts(-1, opts, PH_INIT); + + retropt_bool(opts, OPT_FORK, &dofork); + + if (_xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto, + xfd->para.socket.ip.res_opts[1], + xfd->para.socket.ip.res_opts[0], + them, &themlen, us, &uslen, &needbind, &lowport, + &socktype) != STAT_OK) { + return STAT_NORETRY; + } + + if (xioopts.logopt == 'm') { + Info("starting connect loop, switching to syslog"); + diag_set('y', xioopts.syslogfac); xioopts.logopt = 'y'; + } else { + Info("starting connect loop"); + } + + do { /* loop over retries and forks */ + +#if WITH_RETRY + if (xfd->forever || xfd->retry) { + level = E_INFO; + } else +#endif /* WITH_RETRY */ + level = E_ERROR; + + result = + _xioopen_connect(xfd, + needbind?(struct sockaddr *)us:NULL, uslen, + (struct sockaddr *)them, themlen, + opts, pf, socktype, ipproto, lowport, level); + switch (result) { + case STAT_OK: break; +#if WITH_RETRY + case STAT_RETRYLATER: + case STAT_RETRYNOW: + if (xfd->forever || xfd->retry) { + --xfd->retry; + if (result == STAT_RETRYLATER) { + Nanosleep(&xfd->intervall, NULL); + } + dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); + continue; + } + return STAT_NORETRY; +#endif /* WITH_RETRY */ + default: + return result; + } + +#if WITH_RETRY + if (dofork) { + pid_t pid; + while ((pid = Fork()) < 0) { + int level = E_ERROR; + if (xfd->forever || --xfd->retry) { + level = E_WARN; /* most users won't expect a problem here, + so Notice is too weak */ + } + Msg1(level, "fork(): %s", strerror(errno)); + if (xfd->forever || xfd->retry) { + dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); + Nanosleep(&xfd->intervall, NULL); continue; + } + return STAT_RETRYLATER; + } + if (pid == 0) { /* child process */ + Info1("just born: TCP client process "F_pid, Getpid()); + + /* drop parents locks, reset FIPS... */ + if (xio_forked_inchild() != 0) { + Exit(1); + } + break; + } + /* parent process */ + Notice1("forked off child process "F_pid, pid); + Close(xfd->fd); + /* with and without retry */ + Nanosleep(&xfd->intervall, NULL); + dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); + continue; /* with next socket() bind() connect() */ + } else +#endif /* WITH_RETRY */ + { + break; + } + } while (true); + + if ((result = _xio_openlate(xfd, opts)) < 0) { + return result; + } + return 0; +} + + +/* returns STAT_OK on success or some other value on failure */ +int + _xioopen_ipapp_prepare(struct opt *opts, struct opt **opts0, + const char *hostname, + const char *portname, + int *pf, + int protocol, + unsigned long res_opts0, unsigned long res_opts1, + union sockaddr_union *them, socklen_t *themlen, + union sockaddr_union *us, socklen_t *uslen, + bool *needbind, bool *lowport, + int *socktype) { + uint16_t port; + char infobuff[256]; + int result; + + retropt_socket_pf(opts, pf); + + if ((result = + xiogetaddrinfo(hostname, portname, + *pf, *socktype, protocol, + (union sockaddr_union *)them, themlen, + res_opts0, res_opts1 + )) + != STAT_OK) { + return STAT_NORETRY; /*! STAT_RETRYLATER? */ + } + if (*pf == PF_UNSPEC) { + *pf = them->soa.sa_family; + } + + applyopts(-1, opts, PH_EARLY); + + /* 3 means: IP address AND port accepted */ + if (retropt_bind(opts, *pf, *socktype, protocol, (struct sockaddr *)us, uslen, 3, + res_opts0, res_opts1) + != STAT_NOACTION) { + *needbind = true; + } else { + switch (*pf) { +#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 */ + } + } + + if (retropt_2bytes(opts, OPT_SOURCEPORT, &port) >= 0) { + switch (*pf) { +#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); + retropt_int(opts, OPT_SO_TYPE, socktype); + + *opts0 = copyopts(opts, GROUP_ALL); + + Notice1("opening connection to %s", + sockaddr_info((struct sockaddr *)them, *themlen, infobuff, sizeof(infobuff))); + return STAT_OK; +} +#endif /* WITH_IP4 */ + + +#if WITH_TCP && WITH_LISTEN +int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0, + const char *portname, int *pf, int ipproto, + unsigned long res_opts0, + unsigned long res_opts1, + union sockaddr_union *us, socklen_t *uslen, + int *socktype) { + char *bindname = NULL; + int result; + + retropt_int(opts, OPT_SO_TYPE, socktype); + + retropt_socket_pf(opts, pf); + + retropt_string(opts, OPT_BIND, &bindname); + if ((result = + xiogetaddrinfo(bindname, portname, *pf, *socktype, ipproto, + (union sockaddr_union *)us, uslen, + res_opts0, res_opts1)) + != STAT_OK) { + /*! STAT_RETRY? */ + return result; + } + + *opts0 = copyopts(opts, GROUP_ALL); + return STAT_OK; +} + + +/* we expect the form: port */ +/* currently only used for TCP4 */ +int xioopen_ipapp_listen(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *fd, + unsigned groups, int socktype, + int ipproto, int pf) { + struct opt *opts0 = NULL; + union sockaddr_union us_sa, *us = &us_sa; + socklen_t uslen = sizeof(us_sa); + int result; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1); + } + + if (pf == PF_UNSPEC) { +#if WITH_IP4 && WITH_IP6 + pf = xioopts.default_ip=='6'?PF_INET6:PF_INET; +#elif WITH_IP6 + pf = PF_INET6; +#else + pf = PF_INET; +#endif + } + + fd->stream.howtoend = END_SHUTDOWN; + + if (applyopts_single(&fd->stream, opts, PH_INIT) < 0) return -1; + applyopts(-1, opts, PH_INIT); + applyopts(-1, opts, PH_EARLY); + + if (_xioopen_ipapp_listen_prepare(opts, &opts0, argv[1], &pf, ipproto, + fd->stream.para.socket.ip.res_opts[1], + fd->stream.para.socket.ip.res_opts[0], + us, &uslen, &socktype) + != STAT_OK) { + return STAT_NORETRY; + } + + if ((result = + xioopen_listen(&fd->stream, xioflags, + (struct sockaddr *)us, uslen, + opts, opts0, pf, socktype, ipproto)) + != 0) + return result; + return 0; +} +#endif /* WITH_IP4 && WITH_TCP && WITH_LISTEN */ + +#endif /* WITH_TCP || WITH_UDP */ diff --git a/xio-ipapp.h b/xio-ipapp.h new file mode 100644 index 0000000..9d44407 --- /dev/null +++ b/xio-ipapp.h @@ -0,0 +1,48 @@ +/* $Id: xio-ipapp.h,v 1.13 2006/05/19 05:54:39 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_ipapp_h_included +#define __xio_ipapp_h_included 1 + + +/* when selecting a low port, this is the lowest possible */ +#define XIO_IPPORT_LOWER 640 + + +extern const struct optdesc opt_sourceport; +/*extern const struct optdesc opt_port;*/ +extern const struct optdesc opt_lowport; + +extern int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, + unsigned groups, int socktype, + int ipproto, int protname); +extern int + _xioopen_ipapp_prepare(struct opt *opts, struct opt **opts0, + const char *hostname, + const char *portname, int *pf, int protocol, + unsigned long res_opts0, unsigned long res_opts1, + union sockaddr_union *them, socklen_t *themlen, + 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_listen(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *fd, + unsigned groups, int socktype, + int ipproto, int protname); +extern int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0, + const char *portname, int *pf, int ipproto, + unsigned long res_opts0, + unsigned long res_opts1, + union sockaddr_union *us, socklen_t *uslen, + int *socktype); +extern int xioopen_ip6app_connect(int argc, const char *argv[], struct opt *opts, + int rw, xiofile_t *fd, + unsigned groups, int socktype, int ipproto, + void *protname); + +#endif /* !defined(__xio_ipapp_h_included) */ diff --git a/xio-listen.c b/xio-listen.c new file mode 100644 index 0000000..518291b --- /dev/null +++ b/xio-listen.c @@ -0,0 +1,333 @@ +/* $Id: xio-listen.c,v 1.44 2007/02/08 18:27:00 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for listen socket options */ + +#include "xiosysincludes.h" + +#if WITH_LISTEN + +#include "xioopen.h" +#include "xio-named.h" +#include "xio-socket.h" +#include "xio-ip.h" +#include "xio-ip4.h" +#include "xio-listen.h" +#include "xio-tcpwrap.h" + +/***** LISTEN options *****/ +const struct optdesc opt_backlog = { "backlog", NULL, OPT_BACKLOG, GROUP_LISTEN, PH_LISTEN, TYPE_INT, OFUNC_SPEC }; +const struct optdesc opt_fork = { "fork", NULL, OPT_FORK, GROUP_CHILD, PH_PASTACCEPT, TYPE_BOOL, OFUNC_SPEC }; +/**/ +#if (WITH_UDP || WITH_TCP) +const struct optdesc opt_range = { "range", NULL, OPT_RANGE, GROUP_RANGE, PH_ACCEPT, TYPE_STRING, OFUNC_SPEC }; +#endif + + +int + xioopen_listen(struct single *xfd, int xioflags, + struct sockaddr *us, socklen_t uslen, + struct opt *opts, struct opt *opts0, + int pf, int socktype, int proto) { + int level; + int result; + +#if WITH_RETRY + if (xfd->forever || xfd->retry) { + level = E_INFO; + } else +#endif /* WITH_RETRY */ + level = E_ERROR; + + while (true) { /* loop over failed attempts */ + + /* tcp listen; this can fork() for us; it only returns on error or on + successful establishment of tcp connection */ + result = _xioopen_listen(xfd, xioflags, + (struct sockaddr *)us, uslen, + opts, pf, socktype, proto, +#if WITH_RETRY + (xfd->retry||xfd->forever)?E_INFO:E_ERROR +#else + E_ERROR +#endif /* WITH_RETRY */ + ); + /*! not sure if we should try again on retry/forever */ + switch (result) { + case STAT_OK: break; +#if WITH_RETRY + case STAT_RETRYLATER: + case STAT_RETRYNOW: + if (xfd->forever || xfd->retry) { + dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); + if (result == STAT_RETRYLATER) { + Nanosleep(&xfd->intervall, NULL); + } + dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); + --xfd->retry; + continue; + } + return STAT_NORETRY; +#endif /* WITH_RETRY */ + default: + return result; + } + + break; + } /* drop out on success */ + + return result; +} + + +/* waits for incoming connection, checks its source address and port. Depending + on fork option, it may fork a subprocess. + Returns 0 if a connection was accepted; with fork option, this is always in + a subprocess! + Other return values indicate a problem; this can happen in the master + process or in a subprocess. + This function does not retry. If you need retries, handle this is a + loop in the calling function. + after fork, we set the forever/retry of the child process to 0 + */ +int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, socklen_t uslen, + struct opt *opts, int pf, int socktype, int proto, int level) { + struct sockaddr sa; + socklen_t salen; + int backlog = 5; /* why? 1 seems to cause problems under some load */ + char *rangename; + bool dofork = false; + pid_t pid; /* mostly int; only used with fork */ + char infobuff[256]; + char lisname[256]; + int result; + + retropt_bool(opts, OPT_FORK, &dofork); + + if (dofork) { + if (!(xioflags & XIO_MAYFORK)) { + Error("option fork not allowed here"); + return STAT_NORETRY; + } + xfd->flags |= XIO_DOESFORK; + } + + if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; + +#if 1 + if (dofork) { +#if HAVE_SIGACTION + struct sigaction act; + memset(&act, 0, sizeof(struct sigaction)); + act.sa_flags = SA_NOCLDSTOP|SA_RESTART +#ifdef SA_NOMASK + |SA_NOMASK +#endif + ; + act.sa_handler = childdied; + if (Sigaction(SIGCHLD, &act, NULL) < 0) { + /*! man does not say that errno is defined */ + Warn2("sigaction(SIGCHLD, %p, NULL): %s", childdied, strerror(errno)); + } +#else /* HAVE_SIGACTION */ + if (Signal(SIGCHLD, childdied) == SIG_ERR) { + Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno)); + } +#endif /* !HAVE_SIGACTION */ + } +#endif /* 1 */ + + if ((xfd->fd = Socket(pf, socktype, proto)) < 0) { + Msg4(level, + "socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno)); + return STAT_RETRYLATER; + } + + applyopts(xfd->fd, opts, PH_PASTSOCKET); + + applyopts_cloexec(xfd->fd, opts); + + applyopts(xfd->fd, opts, PH_PREBIND); + applyopts(xfd->fd, opts, PH_BIND); + if (Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) { + Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd, + sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen, + strerror(errno)); + Close(xfd->fd); + return STAT_RETRYLATER; + } + +#if WITH_UNIX + if (us->sa_family == AF_UNIX) { + applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD); + } +#endif + /* under some circumstances (e.g., TCP listen on port 0) bind() fills empty + fields that we want to know. */ + salen = sizeof(sa); + if (Getsockname(xfd->fd, us, &uslen) < 0) { + Warn4("getsockname(%d, %p, {%d}): %s", + xfd->fd, &us, uslen, strerror(errno)); + } + + applyopts(xfd->fd, opts, PH_PASTBIND); +#if WITH_UNIX + if (us->sa_family == AF_UNIX) { + /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/ + applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_EARLY); + applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_PREOPEN); + } +#endif /* WITH_UNIX */ + + retropt_int(opts, OPT_BACKLOG, &backlog); + if (Listen(xfd->fd, backlog) < 0) { + Error3("listen(%d, %d): %s", xfd->fd, backlog, strerror(errno)); + return STAT_RETRYLATER; + } + +#if WITH_IP4 /*|| WITH_IP6*/ + if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { + if (parserange(rangename, us->sa_family, &xfd->para.socket.range) < 0) { + free(rangename); + return STAT_NORETRY; + } + free(rangename); + xfd->para.socket.dorange = true; + } +#endif + +#if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP + xio_retropt_tcpwrap(xfd, opts); +#endif /* && (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */ + +#if WITH_TCP || WITH_UDP + if (retropt_ushort(opts, OPT_SOURCEPORT, &xfd->para.socket.ip.sourceport) >= 0) { + xfd->para.socket.ip.dosourceport = true; + } + retropt_bool(opts, OPT_LOWPORT, &xfd->para.socket.ip.lowport); +#endif /* WITH_TCP || WITH_UDP */ + + if (xioopts.logopt == 'm') { + Info("starting accept loop, switching to syslog"); + diag_set('y', xioopts.syslogfac); xioopts.logopt = 'y'; + } else { + Info("starting accept loop"); + } + while (true) { /* but we only loop if fork option is set */ + char peername[256]; + char sockname[256]; + int ps; /* peer socket */ + union sockaddr_union _peername; + union sockaddr_union _sockname; + union sockaddr_union *pa = &_peername; /* peer address */ + union sockaddr_union *la = &_sockname; /* local address */ + socklen_t pas = sizeof(_peername); /* peer address size */ + socklen_t las = sizeof(_sockname); /* local address size */ + salen = sizeof(struct sockaddr); + + do { + /*? int level = E_ERROR;*/ + Notice1("listening on %s", sockaddr_info(us, uslen, lisname, sizeof(lisname))); + ps = Accept(xfd->fd, (struct sockaddr *)&sa, &salen); + if (ps >= 0) { + /*0 Info4("accept(%d, %p, {"F_Zu"}) -> %d", xfd->fd, &sa, salen, ps);*/ + break; /* success, break out of loop */ + } + if (errno == EINTR) { + continue; + } + if (errno == ECONNABORTED) { + Notice4("accept(%d, %p, {"F_Zu"}): %s", + xfd->fd, &sa, salen, strerror(errno)); + continue; + } + Msg4(level, "accept(%d, %p, {"F_Zu"}): %s", + xfd->fd, &sa, salen, strerror(errno)); + Close(xfd->fd); + return STAT_RETRYLATER; + } while (true); + applyopts_cloexec(ps, opts); + if (Getpeername(ps, &pa->soa, &pas) < 0) { + Warn4("getpeername(%d, %p, {"F_socklen"}): %s", + ps, pa, pas, strerror(errno)); + } + if (Getsockname(ps, &la->soa, &las) < 0) { + Warn4("getsockname(%d, %p, {"F_socklen"}): %s", + ps, pa, pas, strerror(errno)); + } + Notice2("accepting connection from %s on %s", + sockaddr_info(&pa->soa, pas, peername, sizeof(peername)), + sockaddr_info(&la->soa, las, sockname, sizeof(sockname))); + + if (xiocheckpeer(xfd, pa, la) < 0) { + if (Shutdown(ps, 2) < 0) { + Info2("shutdown(%d, 2): %s", ps, strerror(errno)); + } + continue; + } + + Info1("permitting connection from %s", + sockaddr_info((struct sockaddr *)pa, pas, + infobuff, sizeof(infobuff))); + + applyopts(xfd->fd, opts, PH_FD); + + applyopts(xfd->fd, opts, PH_CONNECTED); + + if (dofork) { + if ((pid = Fork()) < 0) { + Msg1(level, "fork(): %s", strerror(errno)); + Close(xfd->fd); + return STAT_RETRYLATER; + } + if (pid == 0) { /* child */ + if (Close(xfd->fd) < 0) { + Info2("close(%d): %s", xfd->fd, strerror(errno)); + } + xfd->fd = ps; + +#if WITH_RETRY + /* !? */ + xfd->retry = 0; + xfd->forever = 0; + level = E_ERROR; +#endif /* WITH_RETRY */ + + /* drop parents locks, reset FIPS... */ + if (xio_forked_inchild() != 0) { + Exit(1); + } + +#if WITH_UNIX + /* with UNIX sockets: only listening parent is allowed to remove + the socket file */ + xfd->opt_unlink_close = false; +#endif /* WITH_UNIX */ + + break; + } + + /* server: continue loop with listen */ + /* shutdown() closes the socket even for the child process, but + close() does what we want */ + if (Close(ps) < 0) { + Info2("close(%d): %s", ps, strerror(errno)); + } + Notice1("forked off child process "F_pid, pid); + Info("still listening"); + } else { + if (Close(xfd->fd) < 0) { + Info2("close(%d): %s", xfd->fd, strerror(errno)); + } + xfd->fd = ps; + break; + } + } + if ((result = _xio_openlate(xfd, opts)) < 0) + return result; + + return 0; +} + +#endif /* WITH_LISTEN */ diff --git a/xio-listen.h b/xio-listen.h new file mode 100644 index 0000000..7c2adf2 --- /dev/null +++ b/xio-listen.h @@ -0,0 +1,21 @@ +/* $Id: xio-listen.h,v 1.10 2006/07/13 06:44:53 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_listen_h_included +#define __xio_listen_h_included 1 + +extern const struct optdesc opt_backlog; +extern const struct optdesc opt_fork; +extern const struct optdesc opt_range; + +int + xioopen_listen(struct single *xfd, int xioflags, + struct sockaddr *us, socklen_t uslen, + struct opt *opts, struct opt *opts0, + int pf, int socktype, int proto); +int _xioopen_listen(struct single *fd, int xioflags, + struct sockaddr *us, socklen_t uslen, + struct opt *opts, int pf, int socktype, int proto, int level); + +#endif /* !defined(__xio_listen_h_included) */ diff --git a/xio-named.c b/xio-named.c new file mode 100644 index 0000000..ead5333 --- /dev/null +++ b/xio-named.c @@ -0,0 +1,216 @@ +/* $Id: xio-named.c,v 1.28 2007/03/06 21:09:01 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for filesystem entry functions */ + +#include "xiosysincludes.h" + +#if _WITH_NAMED + +#include "xioopen.h" +#include "xio-named.h" + + +#if WITH_NAMED +const struct optdesc opt_group_early = { "group-early", NULL, OPT_GROUP_EARLY, GROUP_NAMED, PH_PREOPEN, TYPE_GIDT, OFUNC_SPEC }; +const struct optdesc opt_perm_early = { "perm-early", NULL, OPT_PERM_EARLY, GROUP_NAMED, PH_PREOPEN, TYPE_MODET,OFUNC_SPEC }; +const struct optdesc opt_user_early = { "user-early", NULL, OPT_USER_EARLY, GROUP_NAMED, PH_PREOPEN, TYPE_UIDT, OFUNC_SPEC }; +/*0 const struct optdesc opt_force = { "force", NULL, OPT_FORCE, GROUP_NAMED, PH_???, TYPE_BOOL, OFUNC_SPEC };*/ +const struct optdesc opt_unlink = { "unlink", NULL, OPT_UNLINK, GROUP_NAMED, PH_PREOPEN, TYPE_BOOL, OFUNC_SPEC }; +const struct optdesc opt_unlink_early= { "unlink-early",NULL, OPT_UNLINK_EARLY,GROUP_NAMED, PH_EARLY, TYPE_BOOL, OFUNC_SPEC }; +const struct optdesc opt_unlink_late = { "unlink-late", NULL, OPT_UNLINK_LATE, GROUP_NAMED, PH_PASTOPEN, TYPE_BOOL, OFUNC_SPEC }; +const struct optdesc opt_unlink_close = { "unlink-close", NULL, OPT_UNLINK_CLOSE, GROUP_NAMED, PH_LATE, TYPE_BOOL, OFUNC_SPEC }; +const struct optdesc opt_umask = { "umask", NULL, OPT_UMASK, GROUP_NAMED, PH_EARLY, TYPE_MODET, OFUNC_SPEC }; +#endif /* _WITH_NAMED */ + +/* applies to fd all options belonging to phase */ +int applyopts_named(const char *filename, struct opt *opts, unsigned int phase) { + struct opt *opt; + + if (!opts) return 0; + + opt = opts; while (opt->desc != ODESC_END) { + if (opt->desc == ODESC_DONE || + opt->desc->phase != phase && phase != PH_ALL || + !(opt->desc->group & GROUP_NAMED)) { + ++opt; continue; } + switch (opt->desc->optcode) { + case OPT_GROUP_EARLY: + case OPT_GROUP: + if (Chown(filename, -1, opt->value.u_gidt) < 0) { + Error3("chown(\"%s\", -1, "F_gid"): %s", filename, + opt->value.u_gidt, strerror(errno)); + } + break; + case OPT_USER_EARLY: + case OPT_USER: + if (Chown(filename, opt->value.u_uidt, -1) < 0) { + Error3("chown(\"%s\", "F_uid", -1): %s", filename, + opt->value.u_uidt, strerror(errno)); + } + break; + case OPT_PERM_EARLY: + case OPT_PERM: + if (Chmod(filename, opt->value.u_modet) < 0) { + Error3("chmod(\"%s\", "F_mode"): %s", + filename, opt->value.u_modet, strerror(errno)); + } + break; + case OPT_UNLINK_EARLY: + case OPT_UNLINK: + case OPT_UNLINK_LATE: + if (Unlink(filename) < 0) { + if (errno == ENOENT) { + Warn2("unlink(\"%s\"): %s", filename, strerror(errno)); + } else { + Error2("unlink(\"%s\"): %s", filename, strerror(errno)); + } + } + break; + case OPT_UMASK: + if (Umask(opt->value.u_modet) < 0) { + /* linux docu says it always succeeds, but who believes it? */ + Error2("umask("F_mode"): %s", opt->value.u_modet, strerror(errno)); + } + break; + default: Error1("applyopts_named(): option \"%s\" not implemented", + opt->desc->defname); + break; + } + opt->desc = ODESC_DONE; + ++opt; + } + return 0; +} + + +/* perform actions that are common to all NAMED group addresses: checking if + the entry exists, parsing options, ev.removing old filesystem entry or + setting early owners and permissions. + It applies options of PH_EARLY and PH_PREOPEN. + If the path exists, its st_mode field is returned. + After this sub you may proceed with open() or whatever... + */ +int _xioopen_named_early(int argc, const char *argv[], xiofile_t *xfd, + int groups, + bool *exists, struct opt *opts) { + const char *path = argv[1]; + unsigned int iogroups = 0; +#if HAVE_STAT64 + struct stat64 statbuf; +#else + struct stat statbuf; +#endif /* !HAVE_STAT64 */ + bool opt_unlink_early = false; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", argv[0]?argv[0]:"", argc); + } + statbuf.st_mode = 0; + /* find the appropriate groupbits */ + if ( +#if HAVE_STAT64 + Stat64(path, &statbuf) < 0 +#else + Stat(path, &statbuf) < 0 +#endif /* !HAVE_STAT64 */ + ) { + if (errno != ENOENT) { + Error2("stat(\"%s\"): %s", path, strerror(errno)); + return STAT_RETRYLATER; + } + iogroups = GROUP_REG; + *exists = false; + } else { + iogroups = _groupbits(statbuf.st_mode); + *exists = true; + } + + if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1; + applyopts(-1, opts, PH_INIT); + + retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early); + if (*exists && opt_unlink_early) { + Info1("\"%s\" already exists; removing it", path); + if (Unlink(path) < 0) { + Error2("unlink(\"%s\"): %s", path, strerror(errno)); + *exists = true; + } else { + *exists = false; + } + } + + applyopts(-1, opts, PH_EARLY); + applyopts_named(path, opts, PH_EARLY); + if (*exists) { + applyopts_named(path, opts, PH_PREOPEN); + } else { + dropopts(opts, PH_PREOPEN); + } + + return statbuf.st_mode; +} + + +/* retrieve the OPEN group options and perform the open() call. + returns the file descriptor or a negative value. + Applies options of phases PREOPEN, OPEN, PASTOPEN, and FD +*/ +int _xioopen_open(const char *path, int rw, struct opt *opts) { + mode_t mode = 0666; + flags_t flags = rw; + bool flag; + int fd; + + applyopts_named(path, opts, PH_PREOPEN); + + /* this only applies pure OPEN flags, not mixed OPEN/FCNTL options */ + applyopts_flags(opts, GROUP_OPEN, &flags); + + /* we have to handle mixed OPEN/FCNTL flags specially */ + if (retropt_bool(opts, OPT_O_APPEND, &flag) >= 0 && flag) + flags |= O_APPEND; + if (retropt_bool(opts, OPT_O_NONBLOCK, &flag) >= 0 && flag) + flags |= O_NONBLOCK; +#ifdef O_ASYNC + if (retropt_bool(opts, OPT_O_ASYNC, &flag) >= 0 && flag) + flags |= O_ASYNC; +#endif + if (retropt_bool(opts, OPT_O_TRUNC, &flag) >= 0 && flag) + flags |= O_TRUNC; +#ifdef O_BINARY + if (retropt_bool(opts, OPT_O_BINARY, &flag) >= 0 && flag) + flags |= O_BINARY; +#endif +#ifdef O_TEXT + if (retropt_bool(opts, OPT_O_TEXT, &flag) >= 0 && flag) + flags |= O_TEXT; +#endif +#ifdef O_NOINHERIT + if (retropt_bool(opts, OPT_O_NOINHERIT, &flag) >= 0 && flag) + flags |= O_NOINHERIT; +#endif +#ifdef O_NOATIME + if (retropt_bool(opts, OPT_O_NOATIME, &flag) >= 0 && flag) + flags |= O_NOATIME; +#endif + + retropt_modet(opts, OPT_PERM, &mode); + + if ((fd = Open(path, flags, mode)) < 0) { + Error4("open(\"%s\", 0%lo, 0%03o): %s", + path, flags, mode, strerror(errno)); + return STAT_RETRYLATER; + } + /*0 Info4("open(\"%s\", 0%o, 0%03o) -> %d", path, flags, mode, fd);*/ + applyopts_named(path, opts, PH_PASTOPEN); +#if 0 + applyopts_named(path, opts, PH_FD); + applyopts(fd, opts, PH_FD); + applyopts_cloexec(fd, opts); +#endif + return fd; +} + +#endif /* WITH_NAMED */ diff --git a/xio-named.h b/xio-named.h new file mode 100644 index 0000000..e3db995 --- /dev/null +++ b/xio-named.h @@ -0,0 +1,26 @@ +/* $Id: xio-named.h,v 1.8 2006/03/18 20:04:31 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_named_h_included +#define __xio_named_h_included 1 + +extern const struct optdesc opt_group_early; +extern const struct optdesc opt_perm_early; +extern const struct optdesc opt_user_early; +/*0 extern const struct optdesc opt_cleanup; */ +/*0 extern const struct optdesc opt_force; */ +extern const struct optdesc opt_unlink; +extern const struct optdesc opt_unlink_early; +extern const struct optdesc opt_unlink_late; +extern const struct optdesc opt_unlink_close; +extern const struct optdesc opt_umask; + +extern int + applyopts_named(const char *filename, struct opt *opts, unsigned int phase); +extern int _xioopen_named_early(int argc, const char *argv[], xiofile_t *xfd, + int groups, + bool *exists, struct opt *opts); +extern int _xioopen_open(const char *path, int rw, struct opt *opts); + +#endif /* !defined(__xio_named_h_included) */ diff --git a/xio-openssl.c b/xio-openssl.c new file mode 100644 index 0000000..4f8e98e --- /dev/null +++ b/xio-openssl.c @@ -0,0 +1,1155 @@ +/* $Id: xio-openssl.c,v 1.33 2007/02/26 21:31:40 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2002-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the implementation of the openssl addresses */ + +#include "xiosysincludes.h" +#if WITH_OPENSSL /* make this address configure dependend */ +#include "xioopen.h" + +#include "xio-fd.h" +#include "xio-socket.h" /* _xioopen_connect() */ +#include "xio-listen.h" +#include "xio-ipapp.h" +#include "xio-openssl.h" + +/* the openssl library requires a file descriptor for external communications. + so our best effort is to provide any possible kind of un*x file descriptor + (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" */ + +/* generate a simple openssl server for testing: + 1) generate a private key + openssl genrsa -out server.key 1024 + 2) generate a self signed cert + openssl req -new -key server.key -x509 -days 3653 -out server.crt + enter fields... + 3) generate the pem file + cat server.key server.crt >server.pem + openssl s_server (listens on 4433/tcp) + */ + +/* static declaration of ssl's open function */ +static int xioopen_openssl_connect(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *fd, unsigned groups, + int dummy1, int dummy2, int dummy3); + +/* static declaration of ssl's open function */ +static int xioopen_openssl_listen(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *fd, unsigned groups, + int dummy1, int dummy2, int dummy3); +static int openssl_SSL_ERROR_SSL(int level, const char *funcname); +static int openssl_handle_peer_certificate(struct single *xfd, bool opt_ver, + int level); +static int xioSSL_set_fd(struct single *xfd, int level); +static int xioSSL_connect(struct single *xfd, bool opt_ver, int level); + + +/* description record for ssl connect */ +const struct addrdesc addr_openssl = { + "openssl", /* keyword for selecting this address type in xioopen calls + (canonical or main name) */ + 3, /* data flow directions this address supports on API layer: + 1..read, 2..write, 3..both */ + xioopen_openssl_connect, /* a function pointer used to "open" these addresses.*/ + GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_CHILD|GROUP_OPENSSL|GROUP_RETRY, /* bitwise OR of address groups this address belongs to. + You might have to specify a new group in xioopts.h */ + 0, /* an integer passed to xioopen_openssl; makes it possible to + use the same xioopen_openssl function for slightly different + address types. */ + 0, /* like previous argument */ + 0 /* like previous arguments, but pointer type. + No trailing comma or semicolon! */ + HELP("::") /* a text displayed from xio help function. + No trailing comma or semicolon! + only generates this text if WITH_HELP is != 0 */ +} ; + +#if WITH_LISTEN +/* description record for ssl listen */ +const struct addrdesc addr_openssl_listen = { + "openssl-listen", /* keyword for selecting this address type in xioopen calls + (canonical or main name) */ + 3, /* data flow directions this address supports on API layer: + 1..read, 2..write, 3..both */ + xioopen_openssl_listen, /* a function pointer used to "open" these addresses.*/ + GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_OPENSSL|GROUP_RETRY, /* bitwise OR of address groups this address belongs to. + You might have to specify a new group in xioopts.h */ + 0, /* an integer passed to xioopen_openssl_listen; makes it possible to + use the same xioopen_openssl_listen function for slightly different + address types. */ + 0, /* like previous argument */ + 0 /* like previous arguments, but pointer type. + No trailing comma or semicolon! */ + HELP(":") /* a text displayed from xio help function. + No trailing comma or semicolon! + only generates this text if WITH_HELP is != 0 */ +} ; +#endif /* WITH_LISTEN */ + +/* both client and server */ +const struct optdesc opt_openssl_cipherlist = { "openssl-cipherlist", "ciphers", OPT_OPENSSL_CIPHERLIST, GROUP_OPENSSL, PH_SPEC, TYPE_STRING, OFUNC_SPEC }; +const struct optdesc opt_openssl_method = { "openssl-method", "method", OPT_OPENSSL_METHOD, GROUP_OPENSSL, PH_SPEC, TYPE_STRING, OFUNC_SPEC }; +const struct optdesc opt_openssl_verify = { "openssl-verify", "verify", OPT_OPENSSL_VERIFY, GROUP_OPENSSL, PH_SPEC, TYPE_BOOL, OFUNC_SPEC }; +const struct optdesc opt_openssl_certificate = { "openssl-certificate", "cert", OPT_OPENSSL_CERTIFICATE, GROUP_OPENSSL, PH_SPEC, TYPE_FILENAME, OFUNC_SPEC }; +const struct optdesc opt_openssl_key = { "openssl-key", "key", OPT_OPENSSL_KEY, GROUP_OPENSSL, PH_SPEC, TYPE_FILENAME, OFUNC_SPEC }; +const struct optdesc opt_openssl_dhparam = { "openssl-dhparam", "dh", OPT_OPENSSL_DHPARAM, GROUP_OPENSSL, PH_SPEC, TYPE_FILENAME, OFUNC_SPEC }; +const struct optdesc opt_openssl_cafile = { "openssl-cafile", "cafile", OPT_OPENSSL_CAFILE, GROUP_OPENSSL, PH_SPEC, TYPE_FILENAME, OFUNC_SPEC }; +const struct optdesc opt_openssl_capath = { "openssl-capath", "capath", OPT_OPENSSL_CAPATH, GROUP_OPENSSL, PH_SPEC, TYPE_FILENAME, OFUNC_SPEC }; +const struct optdesc opt_openssl_egd = { "openssl-egd", "egd", OPT_OPENSSL_EGD, GROUP_OPENSSL, PH_SPEC, TYPE_FILENAME, OFUNC_SPEC }; +const struct optdesc opt_openssl_pseudo = { "openssl-pseudo", "pseudo", OPT_OPENSSL_PSEUDO, GROUP_OPENSSL, PH_SPEC, TYPE_BOOL, OFUNC_SPEC }; +#if WITH_FIPS +const struct optdesc opt_openssl_fips = { "openssl-fips", "fips", OPT_OPENSSL_FIPS, GROUP_OPENSSL, PH_SPEC, TYPE_BOOL, OFUNC_SPEC }; +#endif + + +/* If FIPS is compiled in, we need to track if the user asked for FIPS mode. + * On forks, the FIPS mode must be reset by a disable, then enable since + * FIPS tracks the process ID that initializes things. + * If FIPS is not compiled in, no tracking variable is needed + * and we make the reset code compile out. This keeps the + * rest of the code below free of FIPS related #ifs + */ +#if WITH_FIPS +static bool xio_openssl_fips = false; +int xio_reset_fips_mode(void) { + if (xio_openssl_fips) { + if(!sycFIPS_mode_set(0) || !sycFIPS_mode_set(1)) { + ERR_load_crypto_strings(); + ERR_print_errors(BIO_new_fp(stderr,BIO_NOCLOSE)); + Error("Failed to reset OpenSSL FIPS mode"); + xio_openssl_fips = false; + return -1; + } + } + return 0; +} +#else +#define xio_reset_fips_mode() 0 +#endif + +/* the open function for OpenSSL client */ +static int + xioopen_openssl_connect(int argc, + const char *argv[], /* the arguments in the address string */ + struct opt *opts, + int xioflags, /* is the open meant for reading (0), + writing (1), or both (2) ? */ + xiofile_t *xxfd, /* a xio file descriptor structure, + already allocated */ + unsigned groups, /* the matching address groups... */ + int dummy1, /* first transparent integer value from + addr_openssl */ + int dummy2, /* second transparent integer value from + addr_openssl */ + int dummy3) /* transparent pointer value from + addr_openssl */ +{ + struct single *xfd = &xxfd->stream; + struct opt *opts0 = NULL; + const char *hostname, *portname; + int pf = PF_UNSPEC; + int ipproto = IPPROTO_TCP; + int socktype = SOCK_STREAM; + bool dofork = false; + union sockaddr_union us_sa, *us = &us_sa; + union sockaddr_union them_sa, *them = &them_sa; + socklen_t uslen = sizeof(us_sa); + socklen_t themlen = sizeof(them_sa); + bool needbind = false; + bool lowport = false; + int level; + SSL_CTX* ctx; + bool opt_ver = true; /* verify peer certificate */ + char *opt_cert = NULL; /* file name of client certificate */ + int result; + + if (!(xioflags & XIO_MAYCONVERT)) { + Error("address with data processing not allowed here"); + return STAT_NORETRY; + } + xfd->flags |= XIO_DOESCONVERT; + + if (argc != 3) { + Error1("%s: 2 parameters required", argv[0]); + return STAT_NORETRY; + } + hostname = argv[1]; + portname = argv[2]; + + xfd->howtoend = END_SHUTDOWN; + if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; + applyopts(-1, opts, PH_INIT); + + retropt_bool(opts, OPT_FORK, &dofork); + + retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert); + + result = + _xioopen_openssl_prepare(opts, xfd, false, &opt_ver, opt_cert, &ctx); + if (result != STAT_OK) return STAT_NORETRY; + + result = + _xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto, + xfd->para.socket.ip.res_opts[1], + xfd->para.socket.ip.res_opts[0], + them, &themlen, us, &uslen, + &needbind, &lowport, &socktype); + if (result != STAT_OK) return STAT_NORETRY; + + if (xioopts.logopt == 'm') { + Info("starting connect loop, switching to syslog"); + diag_set('y', xioopts.syslogfac); xioopts.logopt = 'y'; + } else { + Info("starting connect loop"); + } + + do { /* loop over failed connect and SSL handshake attempts */ + +#if WITH_RETRY + if (xfd->forever || xfd->retry) { + level = E_INFO; + } else +#endif /* WITH_RETRY */ + level = E_ERROR; + + /* this cannot fork because we retrieved fork option above */ + result = + _xioopen_connect(xfd, + needbind?(struct sockaddr *)us:NULL, sizeof(*us), + (struct sockaddr *)them, themlen, + opts, pf, socktype, ipproto, lowport, level); + switch (result) { + case STAT_OK: break; +#if WITH_RETRY + case STAT_RETRYLATER: + case STAT_RETRYNOW: + if (xfd->forever || xfd->retry) { + dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); + if (result == STAT_RETRYLATER) { + Nanosleep(&xfd->intervall, NULL); + } + --xfd->retry; + continue; + } + return STAT_NORETRY; +#endif /* WITH_RETRY */ + default: + return result; + } + + /*! isn't this too early? */ + if ((result = _xio_openlate(xfd, opts)) < 0) { + return result; + } + + result = _xioopen_openssl_connect(xfd, opt_ver, ctx, level); + switch (result) { + case STAT_OK: break; +#if WITH_RETRY + case STAT_RETRYLATER: + case STAT_RETRYNOW: + if (xfd->forever || xfd->retry) { + Close(xfd->fd); + dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); + if (result == STAT_RETRYLATER) { + Nanosleep(&xfd->intervall, NULL); + } + --xfd->retry; + continue; + } +#endif /* WITH_RETRY */ + default: return STAT_NORETRY; + } + +#if WITH_RETRY + if (dofork) { + pid_t pid; + while ((pid = Fork()) < 0) { + int level = E_ERROR; + if (xfd->forever || xfd->retry) { + level = E_WARN; + } + Msg1(level, "fork(): %s", strerror(errno)); + if (xfd->forever || xfd->retry) { + Nanosleep(&xfd->intervall, NULL); + --xfd->retry; + continue; + } + return STAT_RETRYLATER; + } + if (pid == 0) { /* child process */ + Info1("just born: OpenSSL client process "F_pid, Getpid()); + + /* drop parents locks, reset FIPS... */ + if (xio_forked_inchild() != 0) { + Exit(1); + } + xfd->forever = false; + xfd->retry = 0; + break; + } + /* parent process */ + Notice1("forked off child process "F_pid, pid); + Close(xfd->fd); + sycSSL_free(xfd->para.openssl.ssl); + xfd->para.openssl.ssl = NULL; + /* with and without retry */ + Nanosleep(&xfd->intervall, NULL); + dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); + continue; /* with next socket() bind() connect() */ + } +#endif /* WITH_RETRY */ + break; + } while (true); /* drop out on success */ + + Notice1("SSL connection using %s", SSL_get_cipher(xfd->para.openssl.ssl)); + + /* fill in the fd structure */ + return STAT_OK; +} + + +/* this function is typically called within the OpenSSL client fork/retry loop. + xfd must be of type DATA_OPENSSL, and its fd must be set with a valid file + descriptor. this function then performs all SSL related step to make a valid + SSL connection from an FD and a CTX. */ +int _xioopen_openssl_connect(struct single *xfd, + bool opt_ver, + SSL_CTX *ctx, + int level) { + SSL *ssl; + unsigned long err; + int result; + + /* create a SSL object */ + if ((ssl = sycSSL_new(ctx)) == NULL) { + if (ERR_peek_error() == 0) Msg(level, "SSL_new() failed"); + while (err = ERR_get_error()) { + Msg1(level, "SSL_new(): %s", ERR_error_string(err, NULL)); + } + /*Error("SSL_new()");*/ + return STAT_RETRYLATER; + } + xfd->para.openssl.ssl = ssl; + + result = xioSSL_set_fd(xfd, level); + if (result != STAT_OK) { + sycSSL_free(xfd->para.openssl.ssl); + xfd->para.openssl.ssl = NULL; + return result; + } + + result = xioSSL_connect(xfd, opt_ver, level); + if (result != STAT_OK) { + sycSSL_free(xfd->para.openssl.ssl); + xfd->para.openssl.ssl = NULL; + return result; + } + + result = openssl_handle_peer_certificate(xfd, opt_ver, level); + if (result != STAT_OK) { + sycSSL_free(xfd->para.openssl.ssl); + xfd->para.openssl.ssl = NULL; + return result; + } + + return STAT_OK; +} + + +#if WITH_LISTEN + +static int + xioopen_openssl_listen(int argc, + const char *argv[], /* the arguments in the address string */ + struct opt *opts, + int xioflags, /* is the open meant for reading (0), + writing (1), or both (2) ? */ + xiofile_t *xxfd, /* a xio file descriptor structure, + already allocated */ + unsigned groups, /* the matching address groups... */ + int dummy1, /* first transparent integer value from + addr_openssl */ + int dummy2, /* second transparent integer value from + addr_openssl */ + int dummy3) /* transparent pointer value from + addr_openssl */ +{ + struct single *xfd = &xxfd->stream; + const char *portname; + struct opt *opts0 = NULL; + union sockaddr_union us_sa, *us = &us_sa; + socklen_t uslen = sizeof(us_sa); + int pf; + int socktype = SOCK_STREAM; + int ipproto = IPPROTO_TCP; + /*! lowport? */ + int level; + SSL_CTX* ctx; + bool opt_ver = true; /* verify peer certificate - changed with 1.6.0 */ + char *opt_cert = NULL; /* file name of server certificate */ + int result; + + if (!(xioflags & XIO_MAYCONVERT)) { + Error("address with data processing not allowed here"); + return STAT_NORETRY; + } + xfd->flags |= XIO_DOESCONVERT; + + if (argc != 2) { + Error1("%s: 1 parameter required", argv[0]); + return STAT_NORETRY; + } + +#if WITH_IP4 && WITH_IP6 + pf = xioopts.default_ip=='6'?PF_INET6:PF_INET; +#elif WITH_IP6 + pf = PF_INET6; +#else + pf = PF_INET; +#endif + + portname = argv[1]; + + xfd->howtoend = END_SHUTDOWN; + if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; + applyopts(-1, opts, PH_INIT); + + retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert); + if (opt_cert == NULL) { + Warn("no certificate given; consider option \"cert\""); + } + + applyopts(-1, opts, PH_EARLY); + + result = + _xioopen_openssl_prepare(opts, xfd, true, &opt_ver, opt_cert, &ctx); + if (result != STAT_OK) return STAT_NORETRY; + + if (_xioopen_ipapp_listen_prepare(opts, &opts0, portname, &pf, ipproto, + xfd->para.socket.ip.res_opts[1], + xfd->para.socket.ip.res_opts[0], + us, &uslen, &socktype) + != STAT_OK) { + return STAT_NORETRY; + } + + xfd->addr = &addr_openssl_listen; + xfd->dtype = XIODATA_OPENSSL; + + while (true) { /* loop over failed attempts */ + +#if WITH_RETRY + if (xfd->forever || xfd->retry) { + level = E_INFO; + } else +#endif /* WITH_RETRY */ + level = E_ERROR; + + /* tcp listen; this can fork() for us; it only returns on error or on + successful establishment of tcp connection */ + result = _xioopen_listen(xfd, xioflags, + (struct sockaddr *)us, uslen, + opts, pf, socktype, IPPROTO_TCP, +#if WITH_RETRY + (xfd->retry||xfd->forever)?E_INFO:E_ERROR +#else + E_ERROR +#endif /* WITH_RETRY */ + ); + /*! not sure if we should try again on retry/forever */ + switch (result) { + case STAT_OK: break; +#if WITH_RETRY + case STAT_RETRYLATER: + case STAT_RETRYNOW: + if (xfd->forever || xfd->retry) { + dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); + if (result == STAT_RETRYLATER) { + Nanosleep(&xfd->intervall, NULL); + } + dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); + --xfd->retry; + continue; + } + return STAT_NORETRY; +#endif /* WITH_RETRY */ + default: + return result; + } + + result = _xioopen_openssl_listen(xfd, opt_ver, ctx, level); + switch (result) { + case STAT_OK: break; +#if WITH_RETRY + case STAT_RETRYLATER: + case STAT_RETRYNOW: + if (xfd->forever || xfd->retry) { + dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); + if (result == STAT_RETRYLATER) { + Nanosleep(&xfd->intervall, NULL); + } + dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); + --xfd->retry; + continue; + } + return STAT_NORETRY; +#endif /* WITH_RETRY */ + default: + return result; + } + + Notice1("SSL connection using %s", + SSL_get_cipher(xfd->para.openssl.ssl)); + break; + + } /* drop out on success */ + + /* fill in the fd structure */ + + return STAT_OK; +} + + +int _xioopen_openssl_listen(struct single *xfd, + bool opt_ver, + SSL_CTX *ctx, + int level) { + char error_string[120]; + unsigned long err; + int errint, ret; + + /* create an SSL object */ + if ((xfd->para.openssl.ssl = sycSSL_new(ctx)) == NULL) { + if (ERR_peek_error() == 0) Msg(level, "SSL_new() failed"); + while (err = ERR_get_error()) { + Msg1(level, "SSL_new(): %s", ERR_error_string(err, NULL)); + } + /*Error("SSL_new()");*/ + return STAT_NORETRY; + } + + /* assign the network connection to the SSL object */ + if (sycSSL_set_fd(xfd->para.openssl.ssl, xfd->fd) <= 0) { + if (ERR_peek_error() == 0) Msg(level, "SSL_set_fd() failed"); + while (err = ERR_get_error()) { + Msg2(level, "SSL_set_fd(, %d): %s", + xfd->fd, ERR_error_string(err, NULL)); + } + } + +#if WITH_DEBUG + { + int i = 0; + const char *ciphers = NULL; + Debug("available ciphers:"); + do { + ciphers = SSL_get_cipher_list(xfd->para.openssl.ssl, i); + if (ciphers == NULL) break; + Debug2("CIPHERS pri=%d: %s", i, ciphers); + ++i; + } while (1); + } +#endif /* WITH_DEBUG */ + + /* connect via SSL by performing handshake */ + if ((ret = sycSSL_accept(xfd->para.openssl.ssl)) <= 0) { + /*if (ERR_peek_error() == 0) Msg(level, "SSL_accept() failed");*/ + errint = SSL_get_error(xfd->para.openssl.ssl, ret); + switch (errint) { + case SSL_ERROR_NONE: + Msg(level, "ok"); break; + case SSL_ERROR_ZERO_RETURN: + Msg(level, "connection closed (wrong version number?)"); break; + case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_CONNECT: + case SSL_ERROR_WANT_X509_LOOKUP: + Msg(level, "nonblocking operation did not complete"); break; /*!*/ + case SSL_ERROR_SYSCALL: + if (ERR_peek_error() == 0) { + if (ret == 0) { + Msg(level, "SSL_accept(): socket closed by peer"); + } else if (ret == -1) { + Msg1(level, "SSL_accept(): %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_accept(): %s / %s / %s / %s", error_string, + ERR_lib_error_string(err), ERR_func_error_string(err), + ERR_reason_error_string(err)); + } + /* Msg1(level, "SSL_connect(): %s", ERR_error_string(e, buf));*/ + } + break; + case SSL_ERROR_SSL: + /*ERR_print_errors_fp(stderr);*/ + openssl_SSL_ERROR_SSL(level, "SSL_accept"); + break; + default: + Msg(level, "unknown error"); + } + + return STAT_RETRYLATER; + } + + if (openssl_handle_peer_certificate(xfd, opt_ver, E_ERROR/*!*/) < 0) { + return STAT_NORETRY; + } + + return STAT_OK; +} + +#endif /* WITH_LISTEN */ + + +int + _xioopen_openssl_prepare(struct opt *opts, + struct single *xfd,/* a xio file descriptor + structure, already allocated + */ + bool server, /* SSL client: false */ + bool *opt_ver, + const char *opt_cert, + SSL_CTX **ctx) +{ + bool opt_fips = false; + SSL_METHOD *method; + char *me_str = NULL; /* method string */ + char *ci_str = NULL; /* cipher string */ + char *opt_key = NULL; /* file name of client private key */ + char *opt_dhparam = NULL; /* file name of DH params */ + char *opt_cafile = NULL; /* certificate authority file */ + char *opt_capath = NULL; /* certificate authority directory */ + char *opt_egd = NULL; /* entropy gathering daemon socket path */ + bool opt_pseudo = false; /* use pseudo entropy if nothing else */ + unsigned long err; + int result; + + xfd->addr = &addr_openssl; + xfd->dtype = XIODATA_OPENSSL; + + retropt_bool(opts, OPT_OPENSSL_FIPS, &opt_fips); + retropt_string(opts, OPT_OPENSSL_METHOD, &me_str); + retropt_string(opts, OPT_OPENSSL_CIPHERLIST, &ci_str); + retropt_bool(opts, OPT_OPENSSL_VERIFY, opt_ver); + retropt_string(opts, OPT_OPENSSL_CAFILE, &opt_cafile); + retropt_string(opts, OPT_OPENSSL_CAPATH, &opt_capath); + retropt_string(opts, OPT_OPENSSL_KEY, &opt_key); + retropt_string(opts, OPT_OPENSSL_DHPARAM, &opt_dhparam); + retropt_string(opts, OPT_OPENSSL_EGD, &opt_egd); + retropt_bool(opts,OPT_OPENSSL_PSEUDO, &opt_pseudo); + +#if WITH_FIPS + if (opt_fips) { + if (!sycFIPS_mode_set(1)) { + ERR_load_crypto_strings(); + ERR_print_errors(BIO_new_fp(stderr,BIO_NOCLOSE)); + Error("Failed to set FIPS mode"); + } else { + xio_openssl_fips = true; + } + } +#endif + + OpenSSL_add_all_algorithms(); + OpenSSL_add_all_ciphers(); + OpenSSL_add_all_digests(); + sycSSL_load_error_strings(); + + /* OpenSSL preparation */ + sycSSL_library_init(); + + /*! actions_to_seed_PRNG();*/ + + if (!server) { + if (me_str != 0) { + if (!strcasecmp(me_str, "SSLv2") || !strcasecmp(me_str, "SSL2")) { + method = sycSSLv2_client_method(); + } else if (!strcasecmp(me_str, "SSLv3") || !strcasecmp(me_str, "SSL3")) { + method = sycSSLv3_client_method(); + } else if (!strcasecmp(me_str, "SSLv23") || !strcasecmp(me_str, "SSL23") || + !strcasecmp(me_str, "SSL")) { + method = sycSSLv23_client_method(); + } else if (!strcasecmp(me_str, "TLSv1") || !strcasecmp(me_str, "TLS1") || + !strcasecmp(me_str, "TLS")) { + method = sycTLSv1_client_method(); + } else { + Error1("openssl-method=\"%s\": unknown method", me_str); + method = sycSSLv23_client_method()/*!*/; + } + } else { + method = sycSSLv23_client_method()/*!*/; + } + } else /* server */ { + if (me_str != 0) { + if (!strcasecmp(me_str, "SSLv2") || !strcasecmp(me_str, "SSL2")) { + method = sycSSLv2_server_method(); + } else if (!strcasecmp(me_str, "SSLv3") || !strcasecmp(me_str, "SSL3")) { + method = sycSSLv3_server_method(); + } else if (!strcasecmp(me_str, "SSLv23") || !strcasecmp(me_str, "SSL23") || + !strcasecmp(me_str, "SSL")) { + method = sycSSLv23_server_method(); + } else if (!strcasecmp(me_str, "TLSv1") || !strcasecmp(me_str, "TLS1") || + !strcasecmp(me_str, "TLS")) { + method = sycTLSv1_server_method(); + } else { + Error1("openssl-method=\"%s\": unknown method", me_str); + method = sycSSLv23_server_method()/*!*/; + } + } else { + method = sycSSLv23_server_method()/*!*/; + } + } + + if (opt_egd) { + sycRAND_egd(opt_egd); + } + + if (opt_pseudo) { + long int randdata; + /* initialize libc random from actual microseconds */ + struct timeval tv; + struct timezone tz; + tz.tz_minuteswest = 0; + tz.tz_dsttime = 0; + if ((result = Gettimeofday(&tv, &tz)) < 0) { + Warn2("gettimeofday(%p, {0,0}): %s", &tv, strerror(errno)); + } + srandom(tv.tv_sec*1000000+tv.tv_usec); + + while (!RAND_status()) { + randdata = random(); + Debug2("RAND_seed(0x{%lx}, "F_Zu")", + randdata, sizeof(randdata)); + RAND_seed(&randdata, sizeof(randdata)); + } + } + + if ((*ctx = sycSSL_CTX_new(method)) == NULL) { + if (ERR_peek_error() == 0) Error("SSL_CTX_new()"); + while (err = ERR_get_error()) { + Error1("SSL_CTX_new(): %s", ERR_error_string(err, NULL)); + } + + /*ERR_clear_error;*/ + return STAT_RETRYLATER; + } + + if (opt_cafile != NULL || opt_capath != NULL) { + if (sycSSL_CTX_load_verify_locations(*ctx, opt_cafile, opt_capath) != 1) { + int result; + + if ((result = + openssl_SSL_ERROR_SSL(E_ERROR, "SSL_CTX_load_verify_locations")) + != STAT_OK) { + /*! free ctx */ + return STAT_RETRYLATER; + } + } + } + + if (opt_cert) { + BIO *bio; + DH *dh; + + if (sycSSL_CTX_use_certificate_chain_file(*ctx, opt_cert) <= 0) { + /*! trace functions */ + /*0 ERR_print_errors_fp(stderr);*/ + if (ERR_peek_error() == 0) + Error2("SSL_CTX_use_certificate_file(%p, \"%s\", SSL_FILETYPE_PEM) failed", + *ctx, opt_cert); + while (err = ERR_get_error()) { + Error1("SSL_CTX_use_certificate_file(): %s", + ERR_error_string(err, NULL)); + } + return STAT_RETRYLATER; + } + + if (sycSSL_CTX_use_PrivateKey_file(*ctx, opt_key?opt_key:opt_cert, SSL_FILETYPE_PEM) <= 0) { + /*ERR_print_errors_fp(stderr);*/ + openssl_SSL_ERROR_SSL(E_ERROR/*!*/, "SSL_CTX_use_PrivateKey_file"); + return STAT_RETRYLATER; + } + + if (opt_dhparam == NULL) { + opt_dhparam = (char *)opt_cert; + } + if ((bio = sycBIO_new_file(opt_dhparam, "r")) == NULL) { + Warn2("BIO_new_file(\"%s\", \"r\"): %s", + opt_dhparam, strerror(errno)); + } else { + if ((dh = sycPEM_read_bio_DHparams(bio, NULL, NULL, NULL)) == NULL) { + Info1("PEM_read_bio_DHparams(%p, NULL, NULL, NULL): error", bio); + } else { + BIO_free(bio); + if (sycSSL_CTX_set_tmp_dh(*ctx, dh) == 0) { + Error2("SSL_CTX_set_tmp_dh(%p, %p): error", ctx, dh); + } + } + } + } + + /* set pre ssl-connect options */ + /* SSL_CIPHERS */ + if (ci_str != NULL) { + if (sycSSL_CTX_set_cipher_list(*ctx, ci_str) <= 0) { + if (ERR_peek_error() == 0) + Error1("SSL_set_cipher_list(, \"%s\") failed", ci_str); + while (err = ERR_get_error()) { + Error2("SSL_set_cipher_list(, \"%s\"): %s", + ci_str, ERR_error_string(err, NULL)); + } + /*Error("SSL_new()");*/ + return STAT_RETRYLATER; + } + } + + if (*opt_ver) { + sycSSL_CTX_set_verify(*ctx, + SSL_VERIFY_PEER| SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + NULL); + } else { + sycSSL_CTX_set_verify(*ctx, + SSL_VERIFY_NONE, + NULL); + } + + return STAT_OK; +} + + +/* analyses an OpenSSL error condition, prints the appropriate messages with + severity 'level' and returns one of STAT_OK, STAT_RETRYLATER, or + STAT_NORETRY */ +static int openssl_SSL_ERROR_SSL(int level, const char *funcname) { + unsigned long e; + char buf[120]; /* this value demanded by "man ERR_error_string" */ + + e = ERR_get_error(); + Debug1("ERR_get_error(): %lx", e); + if (e == ((ERR_LIB_RAND<<24)| + (RAND_F_SSLEAY_RAND_BYTES<<12)| + (RAND_R_PRNG_NOT_SEEDED)) /*0x24064064*/) { + Error("too few entropy; use options \"egd\" or \"pseudo\""); + return STAT_NORETRY; + } else { + Msg2(level, "%s(): %s", funcname, ERR_error_string(e, buf)); + return level==E_ERROR ? STAT_NORETRY : STAT_RETRYLATER; + } + return STAT_OK; +} + +static const char *openssl_verify_messages[] = { + /* 0 */ "ok", + /* 1 */ NULL, + /* 2 */ "unable to get issuer certificate", + /* 3 */ "unable to get certificate CRL", + /* 4 */ "unable to decrypt certificate's signature", + /* 5 */ "unable to decrypt CRL's signature", + /* 6 */ "unable to decode issuer public key", + /* 7 */ "certificate signature failure", + /* 8 */ "CRL signature failure", + /* 9 */ "certificate is not yet valid", + /* 10 */ "certificate has expired", + /* 11 */ "CRL is not yet valid", + /* 12 */ "CRL has expired", + /* 13 */ "format error in certificate's notBefore field", + /* 14 */ "format error in certificate's notAfter field", + /* 15 */ "format error in CRL's lastUpdate field", + /* 16 */ "format error in CRL's nextUpdate field", + /* 17 */ "out of memory", + /* 18 */ "self signed certificate", + /* 19 */ "self signed certificate in certificate chain", + /* 20 */ "unable to get local issuer certificate", + /* 21 */ "unable to verify the first certificate", + /* 22 */ "certificate chain too long", + /* 23 */ "certificate revoked", + /* 24 */ "invalid CA certificate", + /* 25 */ "path length constraint exceeded", + /* 26 */ "unsupported certificate purpose", + /* 27 */ "certificate not trusted", + /* 28 */ "certificate rejected", + /* 29 */ "subject issuer mismatch", + /* 30 */ "authority and subject key identifier mismatch", + /* 31 */ "authority and issuer serial number mismatch", + /* 32 */ "key usage does not include certificate signing", + /* 33 */ NULL, + /* 34 */ NULL, + /* 35 */ NULL, + /* 36 */ NULL, + /* 37 */ NULL, + /* 38 */ NULL, + /* 39 */ NULL, + /* 40 */ NULL, + /* 41 */ NULL, + /* 42 */ NULL, + /* 43 */ NULL, + /* 44 */ NULL, + /* 45 */ NULL, + /* 46 */ NULL, + /* 47 */ NULL, + /* 48 */ NULL, + /* 49 */ NULL, + /* 50 */ "application verification failure", +} ; + +static int openssl_handle_peer_certificate(struct single *xfd, + bool opt_ver, int level) { + X509 *peer_cert; + char *str; + char buff[2048]; /* hold peer certificate */ + int status; + + /* SSL_CTX_add_extra_chain_cert + SSL_get_verify_result + */ + if ((peer_cert = SSL_get_peer_certificate(xfd->para.openssl.ssl)) != NULL) { + Debug("peer certificate:"); + if ((str = X509_NAME_oneline(X509_get_subject_name(peer_cert), buff, sizeof(buff))) != NULL) + Debug1("\tsubject: %s", str); /*free (str); SIGSEGV*/ + if ((str = X509_NAME_oneline(X509_get_issuer_name(peer_cert), buff, sizeof(buff))) != NULL) + Debug1("\tissuer: %s", str); /*free (str); SIGSEGV*/ + } + + if (peer_cert) { + if (opt_ver) { + long verify_result; + if ((verify_result = sycSSL_get_verify_result(xfd->para.openssl.ssl)) == X509_V_OK) { + Info("accepted peer certificate"); + status = STAT_OK; + } else { + const char *message = NULL; + if (verify_result >= 0 && + (size_t)verify_result < + sizeof(openssl_verify_messages)/sizeof(char*)) + { + message = openssl_verify_messages[verify_result]; + } + if (message) { + Msg1(level, "%s", message); + } else { + Msg1(level, "rejected peer certificate with error %ld", verify_result); + } + status = STAT_RETRYLATER; + } + } else { + Notice("no check of certificate"); + status = STAT_OK; + } + } else { + if (opt_ver) { + Msg(level, "no peer certificate"); + status = STAT_RETRYLATER; + } else { + Notice("no peer certificate and no check"); + status = STAT_OK; + } + } + + X509_free(peer_cert); + return status; +} + +static int xioSSL_set_fd(struct single *xfd, int level) { + unsigned long err; + + /* assign a network connection to the SSL object */ + if (sycSSL_set_fd(xfd->para.openssl.ssl, xfd->fd) <= 0) { + Msg(level, "SSL_set_fd() failed"); + while (err = ERR_get_error()) { + Msg2(level, "SSL_set_fd(, %d): %s", + xfd->fd, ERR_error_string(err, NULL)); + } + return STAT_RETRYLATER; + } + return STAT_OK; +} + + +/* ... + in case of an error condition, this function check forever and retry + options and ev. sleeps an interval. It returns NORETRY when the caller + should not retry for any reason. */ +static int xioSSL_connect(struct single *xfd, bool opt_ver, int level) { + char error_string[120]; + int errint, status, ret; + unsigned long err; + + /* connect via SSL by performing handshake */ + if ((ret = sycSSL_connect(xfd->para.openssl.ssl)) <= 0) { + /*if (ERR_peek_error() == 0) Msg(level, "SSL_connect() failed");*/ + errint = SSL_get_error(xfd->para.openssl.ssl, ret); + switch (errint) { + case SSL_ERROR_NONE: + /* this is not an error, but I dare not continue for security reasons*/ + Msg(level, "ok"); + status = STAT_RETRYLATER; + case SSL_ERROR_ZERO_RETURN: + Msg(level, "connection closed (wrong version number?)"); + status = STAT_RETRYLATER; + break; + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_CONNECT: + case SSL_ERROR_WANT_X509_LOOKUP: + Msg(level, "nonblocking operation did not complete"); + status = STAT_RETRYLATER; + break; /*!*/ + case SSL_ERROR_SYSCALL: + if (ERR_peek_error() == 0) { + if (ret == 0) { + Msg(level, "SSL_connect(): socket closed by peer"); + } else if (ret == -1) { + 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_reason_error_string(err)); + } + } + status = STAT_RETRYLATER; + break; + case SSL_ERROR_SSL: + status = openssl_SSL_ERROR_SSL(level, "SSL_connect"); + if (openssl_handle_peer_certificate(xfd, opt_ver, level/*!*/) < 0) { + return STAT_RETRYLATER; + } + break; + default: + Msg(level, "unknown error"); + status = STAT_RETRYLATER; + break; + } + return status; + } + return STAT_OK; +} + +/* 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]; + int _errno = EIO; /* if we have no better idea about nature of error */ + int errint, ret; + + ret = sycSSL_read(pipe->para.openssl.ssl, buff, bufsiz); + if (ret < 0) { + errint = SSL_get_error(pipe->para.openssl.ssl, ret); + switch (errint) { + case SSL_ERROR_NONE: + /* this is not an error, but I dare not continue for security reasons*/ + Error("ok"); + case SSL_ERROR_ZERO_RETURN: + Error("connection closed by peer"); + break; + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_CONNECT: + case SSL_ERROR_WANT_X509_LOOKUP: + Error("nonblocking operation did not complete"); + break; /*!*/ + case SSL_ERROR_SYSCALL: + if (ERR_peek_error() == 0) { + if (ret == 0) { + Error("SSL_read(): socket closed by peer"); + } else if (ret == -1) { + _errno = errno; + Error1("SSL_read(): %s", strerror(errno)); + } + } else { + Error("I/O error"); /*!*/ + 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_reason_error_string(err)); + } + } + break; + case SSL_ERROR_SSL: + openssl_SSL_ERROR_SSL(E_ERROR, "SSL_connect"); + break; + default: + Error("unknown error"); + break; + } + errno = _errno; + return -1; + } + return ret; +} + +ssize_t xiopending_openssl(struct single *pipe) { + int bytes = sycSSL_pending(pipe->para.openssl.ssl); + return bytes; +} + +/* 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]; + int _errno = EIO; /* if we have no better idea about nature of error */ + int errint, ret; + + ret = sycSSL_write(pipe->para.openssl.ssl, buff, bufsiz); + if (ret < 0) { + errint = SSL_get_error(pipe->para.openssl.ssl, ret); + switch (errint) { + case SSL_ERROR_NONE: + /* this is not an error, but I dare not continue for security reasons*/ + Error("ok"); + case SSL_ERROR_ZERO_RETURN: + Error("connection closed by peer"); + break; + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_CONNECT: + case SSL_ERROR_WANT_X509_LOOKUP: + Error("nonblocking operation did not complete"); + break; /*!*/ + case SSL_ERROR_SYSCALL: + if (ERR_peek_error() == 0) { + if (ret == 0) { + Error("SSL_write(): socket closed by peer"); + } else if (ret == -1) { + _errno = errno; + Error1("SSL_write(): %s", strerror(errno)); + } + } else { + Error("I/O error"); /*!*/ + 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_reason_error_string(err)); + } + } + break; + case SSL_ERROR_SSL: + openssl_SSL_ERROR_SSL(E_ERROR, "SSL_connect"); + break; + default: + Error("unknown error"); + break; + } + errno = _errno; + return -1; + } + return ret; +} + + +#endif /* WITH_OPENSSL */ diff --git a/xio-openssl.h b/xio-openssl.h new file mode 100644 index 0000000..35bc6ac --- /dev/null +++ b/xio-openssl.h @@ -0,0 +1,52 @@ +/* $Id: xio-openssl.h,v 1.8 2007/02/26 21:31:40 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2002-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_openssl_included +#define __xio_openssl_included 1 + +#if WITH_OPENSSL /* make this address configure dependend */ + +#define SSLIO_BASE 0x53530000 /* "SSxx" */ +#define SSLIO_MASK 0xffff0000 + +extern const struct addrdesc addr_openssl; +extern const struct addrdesc addr_openssl_listen; + +extern const struct optdesc opt_openssl_cipherlist; +extern const struct optdesc opt_openssl_method; +extern const struct optdesc opt_openssl_verify; +extern const struct optdesc opt_openssl_certificate; +extern const struct optdesc opt_openssl_key; +extern const struct optdesc opt_openssl_dhparam; +extern const struct optdesc opt_openssl_cafile; +extern const struct optdesc opt_openssl_capath; +extern const struct optdesc opt_openssl_egd; +extern const struct optdesc opt_openssl_pseudo; +#if WITH_FIPS +extern const struct optdesc opt_openssl_fips; +#endif + +extern int + _xioopen_openssl_prepare(struct opt *opts, struct single *xfd, + bool server, bool *opt_ver, const char *opt_cert, + SSL_CTX **ctx); +extern int + _xioopen_openssl_connect(struct single *xfd, bool opt_ver, + SSL_CTX *ctx, int level); +extern int + _xioopen_openssl_listen(struct single *xfd, bool opt_ver, + SSL_CTX *ctx, int level); +extern int xioclose_openssl(xiofile_t *xfd); +extern int xioshutdown_openssl(xiofile_t *xfd, int how); +extern ssize_t xioread_openssl(struct single *file, void *buff, size_t bufsiz); +extern ssize_t xiopending_openssl(struct single *pipe); +extern ssize_t xiowrite_openssl(struct single *file, const void *buff, size_t bufsiz); + +#if WITH_FIPS +extern int xio_reset_fips_mode(void); +#endif /* WITH_FIPS */ + +#endif /* WITH_OPENSSL */ + +#endif /* !defined(__xio_openssl_included) */ diff --git a/xio-pipe.c b/xio-pipe.c new file mode 100644 index 0000000..e4f6587 --- /dev/null +++ b/xio-pipe.c @@ -0,0 +1,177 @@ +/* $Id: xio-pipe.c,v 1.24 2007/01/25 21:36:11 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for opening addresses of pipe type */ + +#include "xiosysincludes.h" +#include "xioopen.h" + +#include "xio-named.h" + + +#if WITH_PIPE + +static int xioopen_fifo(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); +static int xioopen_fifo_unnamed(xiofile_t *sock, struct opt *opts); + + +const struct addrdesc addr_pipe = { "pipe", 3, xioopen_fifo, GROUP_FD|GROUP_NAMED|GROUP_OPEN|GROUP_FIFO, 0, 0, 0 HELP(":") }; + + +/* process an unnamed bidirectional "pipe" or "fifo" or "echo" argument with + options */ +static int xioopen_fifo_unnamed(xiofile_t *sock, struct opt *opts) { + struct opt *opts2; + int filedes[2]; + int numleft; + int result; + + if (applyopts_single(&sock->stream, opts, PH_INIT) < 0) return -1; + applyopts(-1, opts, PH_INIT); + + if (Pipe(filedes) != 0) { + Error2("pipe(%p): %s", filedes, strerror(errno)); + return -1; + } + /*0 Info2("pipe({%d,%d})", filedes[0], filedes[1]);*/ + + sock->common.tag = XIO_TAG_RDWR; + sock->stream.dtype = XIODATA_PIPE; + sock->stream.fd = filedes[0]; + sock->stream.para.bipipe.fdout = filedes[1]; + applyopts_cloexec(sock->stream.fd, opts); + applyopts_cloexec(sock->stream.para.bipipe.fdout, opts); + + /* one-time and input-direction options, no second application */ + retropt_bool(opts, OPT_IGNOREEOF, &sock->stream.ignoreeof); + + /* here we copy opts! */ + if ((opts2 = copyopts(opts, GROUP_FIFO)) == NULL) { + return STAT_NORETRY; + } + + /* apply options to first FD */ + if ((result = applyopts(sock->stream.fd, opts, PH_ALL)) < 0) { + return result; + } + if ((result = applyopts_single(&sock->stream, opts, PH_ALL)) < 0) { + return result; + } + + /* apply options to second FD */ + if ((result = applyopts(sock->stream.para.bipipe.fdout, opts2, PH_ALL)) < 0) + { + return result; + } + + if ((numleft = leftopts(opts)) > 0) { + Error1("%d option(s) could not be used", numleft); + showleft(opts); + } + Notice("writing to and reading from unnamed pipe"); + return 0; +} + + +/* open a named pipe/fifo */ +static int xioopen_fifo(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3) { + const char *pipename = argv[1]; + int rw = (xioflags & XIO_ACCMODE); +#if HAVE_STAT64 + struct stat64 pipstat; +#else + struct stat pipstat; +#endif /* !HAVE_STAT64 */ + bool opt_unlink_early = false; + bool opt_unlink_close = true; + mode_t mode = 0666; + int result; + + if (argc == 1) { + return xioopen_fifo_unnamed(fd, fd->stream.opts); + } + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1); + } + + if (applyopts_single(&fd->stream, opts, PH_INIT) < 0) return -1; + applyopts(-1, opts, PH_INIT); + + retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early); + applyopts(-1, opts, PH_EARLY); + + if (opt_unlink_early) { + if (Unlink(pipename) < 0) { + if (errno == ENOENT) { + Warn2("unlink(%s): %s", pipename, strerror(errno)); + } else { + Error2("unlink(%s): %s", pipename, strerror(errno)); + return STAT_RETRYLATER; + } + } + } + + retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); + retropt_modet(opts, OPT_PERM, &mode); + if (applyopts_named(pipename, opts, PH_EARLY) < 0) { + return STAT_RETRYLATER; + } + if (applyopts_named(pipename, opts, PH_PREOPEN) < 0) { + return STAT_RETRYLATER; + } + if ( +#if HAVE_STAT64 + Stat64(pipename, &pipstat) < 0 +#else + Stat(pipename, &pipstat) < 0 +#endif /* !HAVE_STAT64 */ + ) { + if (errno != ENOENT) { + Error3("stat(\"%s\", %p): %s", pipename, &pipstat, strerror(errno)); + } else { + Debug1("xioopen_fifo(\"%s\"): does not exist, creating fifo", pipename); +#if 0 + result = Mknod(pipename, S_IFIFO|mode, 0); + if (result < 0) { + Error3("mknod(%s, %d, 0): %s", pipename, mode, strerror(errno)); + return STAT_RETRYLATER; + } +#else + result = Mkfifo(pipename, mode); + if (result < 0) { + Error3("mkfifo(%s, %d): %s", pipename, mode, strerror(errno)); + return STAT_RETRYLATER; + } +#endif + Notice2("created named pipe \"%s\" for %s", pipename, ddirection[rw]); + } + if (opt_unlink_close) { + if ((fd->stream.unlink_close = strdup(pipename)) == NULL) { + Error1("strdup(\"%s\"): out of memory", pipename); + } + fd->stream.opt_unlink_close = true; + } + } else { + /* exists */ + Debug1("xioopen_fifo(\"%s\"): already exist, opening it", pipename); + Notice3("opening %s \"%s\" for %s", + filetypenames[(pipstat.st_mode&S_IFMT)>>12], + pipename, ddirection[rw]); + /*applyopts_early(pipename, opts);*/ + applyopts_named(pipename, opts, PH_EARLY); + } + + if ((result = _xioopen_open(pipename, rw, opts)) < 0) { + return result; + } + fd->stream.fd = result; + + applyopts_named(pipename, opts, PH_FD); + applyopts(fd->stream.fd, opts, PH_FD); + applyopts_cloexec(fd->stream.fd, opts); + return _xio_openlate(&fd->stream, opts); +} + +#endif /* WITH_PIPE */ diff --git a/xio-pipe.h b/xio-pipe.h new file mode 100644 index 0000000..1d72cf8 --- /dev/null +++ b/xio-pipe.h @@ -0,0 +1,12 @@ +/* $Id: xio-pipe.h,v 1.4 2001/11/04 17:19:20 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_pipe_h_included +#define __xio_pipe_h_included 1 + +const extern struct addrdesc addr_pipe; + +extern int xioopen_fifo_unnamed(char *arg, xiofile_t *sock); + +#endif /* !defined(__xio_pipe_h_included) */ diff --git a/xio-process.c b/xio-process.c new file mode 100644 index 0000000..1b7960e --- /dev/null +++ b/xio-process.c @@ -0,0 +1,70 @@ +/* $Id: xio-process.c,v 1.9 2003/05/21 05:16:38 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2003 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file handles process related addresses options */ + +#include "xiosysincludes.h" +#include "xioopen.h" + +#include "xio-process.h" + +/****** process related options ******/ +const struct optdesc opt_setgid_early= { "setgid-early",NULL, OPT_SETGID_EARLY,GROUP_PROCESS, PH_EARLY, TYPE_GIDT, OFUNC_SPEC }; +const struct optdesc opt_setgid = { "setgid", NULL, OPT_SETGID, GROUP_PROCESS, PH_LATE2, TYPE_GIDT, OFUNC_SPEC }; +const struct optdesc opt_setuid_early= { "setuid-early",NULL, OPT_SETUID_EARLY,GROUP_PROCESS, PH_EARLY, TYPE_UIDT, OFUNC_SPEC }; +const struct optdesc opt_setuid = { "setuid", NULL, OPT_SETUID, GROUP_PROCESS, PH_LATE2, TYPE_UIDT, OFUNC_SPEC }; +const struct optdesc opt_substuser = { "substuser", "su", OPT_SUBSTUSER, GROUP_PROCESS, PH_LATE2, TYPE_UIDT, OFUNC_SPEC }; +const struct optdesc opt_substuser_delayed = { "substuser-delayed", "su-d", OPT_SUBSTUSER_DELAYED, GROUP_PROCESS, PH_INIT, TYPE_UIDT, OFUNC_SPEC }; +const struct optdesc opt_chroot_early = { "chroot-early", NULL, OPT_CHROOT_EARLY, GROUP_PROCESS, PH_EARLY, TYPE_STRING, OFUNC_SPEC }; +const struct optdesc opt_chroot = { "chroot", NULL, OPT_CHROOT, GROUP_PROCESS, PH_LATE, TYPE_STRING, OFUNC_SPEC }; +const struct optdesc opt_setsid = { "setsid", "sid", OPT_SETSID, GROUP_PROCESS, PH_LATE, TYPE_BOOL, OFUNC_SPEC }; +const struct optdesc opt_setpgid = { "setpgid", "pgid",OPT_SETPGID, GROUP_FORK, PH_LATE, TYPE_INT, OFUNC_SPEC }; + + +/* for option substuser-delayed, save info for later application */ +bool delayeduser = false; +uid_t delayeduser_uid; /* numeric user id to switch to */ +gid_t delayeduser_gid; /* numeric group id to switch to */ +gid_t delayeduser_gids[NGROUPS]; /* num.supplementary group ids */ +size_t delayeduser_ngids; /* number of suppl. gids */ +char *delayeduser_name; /* name of user to switch to */ +char *delayeduser_dir; /* home directory of user to switch to */ +char *delayeduser_shell; /* login shell of user to switch to */ + + +int _xioopen_setdelayeduser(void) { + if (delayeduser) { +#if HAVE_SETGROUPS + if ((Setgroups(delayeduser_ngids, delayeduser_gids)) != 0) { + Error3("setgroups("F_Zu", %p): %s", + delayeduser_ngids, delayeduser_gids, strerror(errno)); + } +#endif /* HAVE_SETGROUPS */ + if (Setgid(delayeduser_gid) < 0) { + Error2("setgid("F_gid"): %s", delayeduser_gid, + strerror(errno)); + } + if (Setuid(delayeduser_uid) < 0) { + Error2("setuid("F_uid"): %s", delayeduser_uid, + strerror(errno)); + } +#if 1 + if (setenv("USER", delayeduser_name, 1) < 0) + Error1("setenv(\"USER\", \"%s\", 1): insufficient space", + delayeduser_name); + if (setenv("LOGNAME", delayeduser_name, 1) < 0) + Error1("setenv(\"LOGNAME\", \"%s\", 1): insufficient space", + delayeduser_name); + if (setenv("HOME", delayeduser_dir, 1) < 0) + Error1("setenv(\"HOME\", \"%s\", 1): insufficient space", + delayeduser_dir); + if (setenv("SHELL", delayeduser_shell, 1) < 0) + Error1("setenv(\"SHELL\", \"%s\", 1): insufficient space", + delayeduser_shell); +#endif + delayeduser = false; + } + return 0; +} + diff --git a/xio-process.h b/xio-process.h new file mode 100644 index 0000000..928b6f9 --- /dev/null +++ b/xio-process.h @@ -0,0 +1,31 @@ +/* $Id: xio-process.h,v 1.7 2002/10/01 19:37:51 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001, 2002 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_process_h_included +#define __xio_process_h_included 1 + +extern const struct optdesc opt_setgid_early; +extern const struct optdesc opt_setgid; +extern const struct optdesc opt_setuid_early; +extern const struct optdesc opt_setuid; +extern const struct optdesc opt_substuser; +extern const struct optdesc opt_substuser_delayed; +extern const struct optdesc opt_chroot_early; +extern const struct optdesc opt_chroot; +extern const struct optdesc opt_setsid; +extern const struct optdesc opt_setpgid; + +/* for option substuser-delayed, save info for later application */ +extern bool delayeduser; +extern uid_t delayeduser_uid; /* numeric user id to switch to */ +extern gid_t delayeduser_gid; /* numeric group id to switch to */ +extern gid_t delayeduser_gids[NGROUPS]; /* num.supplementary group ids */ +extern size_t delayeduser_ngids; /* number of suppl. gids */ +extern char *delayeduser_name; /* name of user to switch to */ +extern char *delayeduser_dir; /* home directory of user to switch to */ +extern char *delayeduser_shell; /* login shell of user to switch to */ + +extern int _xioopen_setdelayeduser(void); + +#endif /* !defined(__xio_process_h_included) */ diff --git a/xio-progcall.c b/xio-progcall.c new file mode 100644 index 0000000..aebde1c --- /dev/null +++ b/xio-progcall.c @@ -0,0 +1,618 @@ +/* $Id: xio-progcall.c,v 1.54 2007/03/06 21:11:55 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains common code dealing with program calls (exec, system) */ + +#include "xiosysincludes.h" +#include "xioopen.h" + +#include "xio-process.h" +#include "xio-progcall.h" + +/* these options are used by address pty too */ +#if HAVE_OPENPTY +const struct optdesc opt_openpty = { "openpty", NULL, OPT_OPENPTY, GROUP_PTY, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC }; +#endif /* HAVE_OPENPTY */ +#if HAVE_DEV_PTMX || HAVE_DEV_PTC +const struct optdesc opt_ptmx = { "ptmx", NULL, OPT_PTMX, GROUP_PTY, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC }; +#endif + +#if WITH_EXEC || WITH_SYSTEM + +#define MAXPTYNAMELEN 64 + +const struct optdesc opt_fdin = { "fdin", NULL, OPT_FDIN, GROUP_FORK, PH_PASTBIGEN, TYPE_USHORT, OFUNC_SPEC }; +const struct optdesc opt_fdout = { "fdout", NULL, OPT_FDOUT, GROUP_FORK, PH_PASTBIGEN, TYPE_USHORT, OFUNC_SPEC }; +const struct optdesc opt_path = { "path", NULL, OPT_PATH, GROUP_EXEC, PH_PREEXEC, TYPE_STRING, OFUNC_SPEC }; +const struct optdesc opt_pipes = { "pipes", NULL, OPT_PIPES, GROUP_FORK, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC }; +#if HAVE_PTY +const struct optdesc opt_pty = { "pty", NULL, OPT_PTY, GROUP_FORK, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC }; +#endif +const struct optdesc opt_stderr = { "stderr", NULL, OPT_STDERR, GROUP_FORK, PH_PASTFORK, TYPE_BOOL, OFUNC_SPEC }; +const struct optdesc opt_nofork = { "nofork", NULL, OPT_NOFORK, GROUP_FORK, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC }; +const struct optdesc opt_sighup = { "sighup", NULL, OPT_SIGHUP, GROUP_PARENT, PH_LATE, TYPE_CONST, OFUNC_SIGNAL, SIGHUP }; +const struct optdesc opt_sigint = { "sigint", NULL, OPT_SIGINT, GROUP_PARENT, PH_LATE, TYPE_CONST, OFUNC_SIGNAL, SIGINT }; +const struct optdesc opt_sigquit = { "sigquit", NULL, OPT_SIGQUIT, GROUP_PARENT, PH_LATE, TYPE_CONST, OFUNC_SIGNAL, SIGQUIT }; + + +/* fork for exec/system, but return before exec'ing. + return=0: is child process + return>0: is parent process + return<0: error occurred, assume parent process and no child exists !!! + */ +int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */ + struct single *fd, + unsigned groups, + struct opt **copts /* in: opts; out: opts for child */ + ) { + struct opt *popts; /* parent process options */ + int numleft; + int d, type, protocol, sv[2], rdpip[2], wrpip[2]; + int rw = (xioflags & XIO_ACCMODE); + bool usepipes = false; +#if HAVE_PTY + int ptyfd = -1, ttyfd = -1; + bool usebestpty = false; /* use the best available way to open pty */ +#if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC) + bool useptmx = false; /* use /dev/ptmx or equivalent */ +#endif +#if HAVE_OPENPTY + bool useopenpty = false; /* try only openpty */ +#endif /* HAVE_OPENPTY */ + bool usepty = false; /* any of the pty options is selected */ + char ptyname[MAXPTYNAMELEN]; +#endif /* HAVE_PTY */ + pid_t pid = 0; /* mostly int */ + short fdi = 0, fdo = 1; + short result; + bool withstderr = false; + bool nofork = false; + bool withfork; + + popts = moveopts(*copts, GROUP_ALL); + if (applyopts_single(fd, popts, PH_INIT) < 0) return -1; + applyopts2(-1, popts, PH_INIT, PH_EARLY); + + retropt_bool(popts, OPT_NOFORK, &nofork); + withfork = !nofork; + + retropt_bool(popts, OPT_PIPES, &usepipes); +#if HAVE_PTY + retropt_bool(popts, OPT_PTY, &usebestpty); +#if HAVE_OPENPTY + retropt_bool(popts, OPT_OPENPTY, &useopenpty); +#endif +#if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC) + retropt_bool(popts, OPT_PTMX, &useptmx); +#endif + usepty = (usebestpty +#if HAVE_OPENPTY + || useopenpty +#endif +#if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC) + || useptmx +#endif + ); + if (usepipes && usepty) { + Warn("_xioopen_foxec(): options \"pipes\" and \"pty\" must not be specified together; ignoring \"pipes\""); + usepipes = false; + } +#endif /* HAVE_PTY */ + retropt_ushort(popts, OPT_FDIN, (unsigned short *)&fdi); + retropt_ushort(popts, OPT_FDOUT, (unsigned short *)&fdo); + + if (withfork) { + if (!(xioflags&XIO_MAYCHILD)) { + Error("cannot fork off child process here"); + /*!! free something */ + return -1; + } + fd->flags |= XIO_DOESCHILD; + +#if HAVE_PTY + Notice2("forking off child, using %s for %s", + &("socket\0\0pipes\0\0\0pty\0\0\0\0\0"[(usepipes<<3)|(usepty<<4)]), + ddirection[rw]); +#else + Notice2("forking off child, using %s for %s", + &("socket\0\0pipes\0\0\0"[(usepipes<<3)]), + ddirection[rw]); +#endif /* HAVE_PTY */ + } + applyopts(-1, popts, PH_PREBIGEN); + + if (!withfork) { + /*0 struct single *stream1, *stream2;*/ + + if (!(xioflags & XIO_MAYEXEC /* means exec+nofork */)) { + Error("option nofork is not allowed here"); + /*!! free something */ + return -1; + } + fd->flags |= XIO_DOESEXEC; + + free(*copts); + *copts = moveopts(popts, GROUP_ALL); + +#if 0 /*!! */ + if (sock1->tag == XIO_TAG_DUAL) { + stream1 = &sock1->dual.stream[0]->stream; + stream2 = &sock1->dual.stream[1]->stream; + } else { + stream1 = &sock1->stream; + stream2 = &sock1->stream; + } + if (stream1->dtype == DATA_READLINE || stream2->dtype == DATA_READLINE || + stream1->dtype == DATA_OPENSSL || stream2->dtype == DATA_OPENSSL + ) { + Error("with option nofork, openssl and readline in address1 do not work"); + } + if (stream1->lineterm != LINETERM_RAW || + stream2->lineterm != LINETERM_RAW || + stream1->ignoreeof || stream2->ignoreeof) { + Warn("due to option nofork, address1 options for lineterm and igoreeof do not apply"); + } +#endif + + /*! problem: when fdi==WRFD(sock[0]) or fdo==RDFD(sock[0]) */ + if (rw != XIO_WRONLY) { + if (XIO_GETRDFD(sock[0]/*!!*/) == fdi) { + if (Fcntl_l(fdi, F_SETFD, 0) < 0) { + Warn2("fcntl(%d, F_SETFD, 0): %s", fdi, strerror(errno)); + } + if (Dup2(XIO_GETRDFD(sock[0]), fdi) < 0) { + Error3("dup2(%d, %d): %s", + XIO_GETRDFD(sock[0]), fdi, strerror(errno)); + } + /*0 Info2("dup2(%d, %d)", XIO_GETRDFD(sock[0]), fdi);*/ + } else { + if (Dup2(XIO_GETRDFD(sock[0]), fdi) < 0) { + Error3("dup2(%d, %d): %s", + XIO_GETRDFD(sock[0]), fdi, strerror(errno)); + } + /*0 Info2("dup2(%d, %d)", XIO_GETRDFD(sock[0]), fdi);*/ + } + } + if (rw != XIO_RDONLY) { + if (XIO_GETWRFD(sock[0]) == fdo) { + if (Fcntl_l(fdo, F_SETFD, 0) < 0) { + Warn2("fcntl(%d, F_SETFD, 0): %s", fdo, strerror(errno)); + } + if (Dup2(XIO_GETWRFD(sock[0]), fdo) < 0) { + Error3("dup2(%d, %d): %s)", + XIO_GETWRFD(sock[0]), fdo, strerror(errno)); + } + /*0 Info2("dup2(%d, %d)", XIO_GETWRFD(sock[0]), fdo);*/ + } else { + if (Dup2(XIO_GETWRFD(sock[0]), fdo) < 0) { + Error3("dup2(%d, %d): %s)", + XIO_GETWRFD(sock[0]), fdo, strerror(errno)); + } + /*0 Info2("dup2(%d, %d)", XIO_GETWRFD(sock[0]), fdo);*/ + } + } + } else +#if HAVE_PTY + if (usepty) { + +#if defined(HAVE_DEV_PTMX) +# define PTMX "/dev/ptmx" /* Linux */ +#elif HAVE_DEV_PTC +# define PTMX "/dev/ptc" /* AIX 4.3.3 */ +#endif + fd->dtype = XIODATA_PTY; +#if HAVE_DEV_PTMX || HAVE_DEV_PTC + if (usebestpty || useptmx) { + if ((ptyfd = Open(PTMX, O_RDWR|O_NOCTTY, 0620)) < 0) { + Warn1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620): %s", + strerror(errno)); + /*!*/ + } else { + /*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", PTMX, ptyfd);*/ + } + if (ptyfd >= 0 && ttyfd < 0) { + char *tn = NULL; + /* we used PTMX before forking */ + extern char *ptsname(int); +#if HAVE_GRANTPT /* AIX, not Linux */ + if (Grantpt(ptyfd)/*!*/ < 0) { + Warn2("grantpt(%d): %s", ptyfd, strerror(errno)); + } +#endif /* HAVE_GRANTPT */ +#if HAVE_UNLOCKPT + if (Unlockpt(ptyfd)/*!*/ < 0) { + Warn2("unlockpt(%d): %s", ptyfd, strerror(errno)); + } +#endif /* HAVE_UNLOCKPT */ +#if HAVE_PTSNAME /* AIX, not Linux */ + if ((tn = Ptsname(ptyfd)) == NULL) { + Warn2("ptsname(%d): %s", ptyfd, strerror(errno)); + } +#endif /* HAVE_PTSNAME */ + if (tn == NULL) { + if ((tn = Ttyname(ptyfd)) == NULL) { + Warn2("ttyname(%d): %s", ptyfd, strerror(errno)); + } + } + strncpy(ptyname, tn, MAXPTYNAMELEN); + if ((ttyfd = Open(tn, O_RDWR|O_NOCTTY, 0620)) < 0) { + Warn2("open(\"%s\", O_RDWR|O_NOCTTY, 0620): %s", tn, strerror(errno)); + } else { + /*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", tn, ttyfd);*/ + } + +#ifdef I_PUSH + /* Linux: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> -1 EINVAL */ + /* AIX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 1 */ + /* SunOS: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */ + /* HP-UX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */ + if (Ioctl(ttyfd, I_FIND, "ldterm") == 0) { + Ioctl(ttyfd, I_PUSH, "ptem"); /* 0 */ + Ioctl(ttyfd, I_PUSH, "ldterm"); /* 0 */ + Ioctl(ttyfd, I_PUSH, "ttcompat"); /* HP-UX: -1 */ + } +#endif + +#if 0 /* the following block need not work */ + + if (ttyfd >= 0 && ((tn = Ttyname(ttyfd)) == NULL)) { + Warn2("ttyname(%d): %s", ttyfd, strerror(errno)); + } + if (tn == NULL) { + Error("could not open pty"); + return STAT_NORETRY; + } +#endif + Info1("opened pseudo terminal %s", tn); + } + } +#endif /* HAVE_DEV_PTMX || HAVE_DEV_PTC */ +#if HAVE_OPENPTY + if (ptyfd < 0) { + int result; + if ((result = Openpty(&ptyfd, &ttyfd, ptyname, NULL, NULL)) < 0) { + Error4("openpty(%p, %p, %p, NULL, NULL): %s", + &ptyfd, &ttyfd, ptyname, strerror(errno)); + return -1; + } + } +#endif /* HAVE_OPENPTY */ + free(*copts); + if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) { + return STAT_RETRYLATER; + } + applyopts_cloexec(ptyfd, popts);/*!*/ + if (fd->howtoend = END_UNSPEC) { + fd->howtoend = END_CLOSE_KILL; + } + + /* this for parent, was after fork */ + applyopts(ptyfd, popts, PH_FD); + applyopts(ptyfd, popts, PH_LATE); + if (applyopts_single(fd, popts, PH_LATE) < 0) return -1; + + fd->fd = ptyfd; + + /* this for child, was after fork */ + applyopts(ttyfd, *copts, PH_FD); + } else +#endif /* HAVE_PTY */ + if (usepipes) { + struct opt *popts2, *copts2; + + if (rw == XIO_RDWR) + fd->dtype = XIODATA_2PIPE; + if (rw != XIO_WRONLY) { + if (Pipe(rdpip) < 0) { + Error2("pipe(%p): %s", rdpip, strerror(errno)); + return STAT_RETRYLATER; + } + } + /*0 Info2("pipe({%d,%d})", rdpip[0], rdpip[1]);*/ + /* rdpip[0]: read by socat; rdpip[1]: write by child */ + free(*copts); + if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) + == NULL) { + return STAT_RETRYLATER; + } + + popts2 = copyopts(popts, GROUP_ALL); + copts2 = copyopts(*copts, GROUP_ALL); + + if (rw != XIO_WRONLY) { + applyopts_cloexec(rdpip[0], popts); + applyopts(rdpip[0], popts, PH_FD); + applyopts(rdpip[1], *copts, PH_FD); + } + + if (rw != XIO_RDONLY) { + if (Pipe(wrpip) < 0) { + Error2("pipe(%p): %s", wrpip, strerror(errno)); + return STAT_RETRYLATER; + } + } + /*0 Info2("pipe({%d,%d})", wrpip[0], wrpip[1]);*/ + + /* wrpip[1]: write by socat; wrpip[0]: read by child */ + if (rw != XIO_RDONLY) { + applyopts_cloexec(wrpip[1], popts2); + applyopts(wrpip[1], popts2, PH_FD); + applyopts(wrpip[0], copts2, PH_FD); + } + if (fd->howtoend == END_UNSPEC) { + fd->howtoend = END_CLOSE_KILL; + } + + /* this for parent, was after fork */ + switch (rw) { + case XIO_RDONLY: fd->fd = rdpip[0]; break; + case XIO_WRONLY: fd->fd = wrpip[1]; break; + case XIO_RDWR: fd->fd = rdpip[0]; + fd->para.exec.fdout = wrpip[1]; + break; + } + applyopts(fd->fd, popts, PH_FD); + applyopts(fd->fd, popts, PH_LATE); + if (applyopts_single(fd, popts, PH_LATE) < 0) return -1; + } else { + d = AF_UNIX; type = SOCK_STREAM; + protocol = 0; /* PF_UNIX does not work on AIX */ + retropt_int(popts, OPT_SO_TYPE, &type); + result = Socketpair(d, type, protocol, sv); + if (result < 0) { + Error5("socketpair(%d, %d, %d, %p): %s", + d, type, protocol, sv, strerror(errno)); + return STAT_RETRYLATER; + } + /*0 Info5("socketpair(%d, %d, %d, {%d,%d})", + d, type, protocol, sv[0], sv[1]);*/ + free(*copts); + if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) { + return STAT_RETRYLATER; + } + applyopts(sv[0], *copts, PH_PASTSOCKET); + applyopts(sv[1], popts, PH_PASTSOCKET); + + applyopts_cloexec(sv[0], *copts); + applyopts(sv[0], *copts, PH_FD); + applyopts(sv[1], popts, PH_FD); + + applyopts(sv[0], *copts, PH_PREBIND); + applyopts(sv[0], *copts, PH_BIND); + applyopts(sv[0], *copts, PH_PASTBIND); + applyopts(sv[1], popts, PH_PREBIND); + applyopts(sv[1], popts, PH_BIND); + applyopts(sv[1], popts, PH_PASTBIND); + + if (fd->howtoend == END_UNSPEC) { + fd->howtoend = END_SHUTDOWN_KILL; + } + + /* this for parent, was after fork */ + fd->fd = sv[0]; + applyopts(fd->fd, popts, PH_FD); + applyopts(fd->fd, popts, PH_LATE); + if (applyopts_single(fd, popts, PH_LATE) < 0) return -1; + } + /*0 if ((optpr = copyopts(*copts, GROUP_PROCESS)) == NULL) + return STAT_RETRYLATER;*/ + retropt_bool(*copts, OPT_STDERR, &withstderr); + if (Signal(SIGCHLD, childdied) == SIG_ERR) { + Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno)); + } + + if (withfork) { + const char *forkwaitstring; + int forkwaitsecs = 0; + + pid = Fork(); + if (pid < 0) { + Error1("fork(): %s", strerror(errno)); + return STAT_RETRYLATER; + } + /* gdb recommends to have env controlled sleep after fork */ + if (forkwaitstring = getenv("SOCAT_FORK_WAIT")) { + forkwaitsecs = atoi(forkwaitstring); + Sleep(forkwaitsecs); + } + + if (pid == 0) { /* child */ + /* drop parents locks, reset FIPS... */ + if (xio_forked_inchild() != 0) { + Exit(1); + } + } + } + if (!withfork || pid == 0) { /* child */ + uid_t user; + gid_t group; + + if (withfork) { + if (Signal(SIGCHLD, SIG_IGN) == SIG_ERR) { + Warn1("signal(SIGCHLD, SIG_IGN): %s", strerror(errno)); + } + +#if HAVE_PTY + if (usepty) { + if (rw != XIO_RDONLY && fdi != ttyfd) { + if (Dup2(ttyfd, fdi) < 0) { + Error3("dup2(%d, %d): %s", ttyfd, fdi, strerror(errno)); + return STAT_RETRYLATER; } + /*0 Info2("dup2(%d, %d)", ttyfd, fdi);*/ + } + if (rw != XIO_WRONLY && fdo != ttyfd) { + if (Dup2(ttyfd, fdo) < 0) { + Error3("dup2(%d, %d): %s", ttyfd, fdo, strerror(errno)); + return STAT_RETRYLATER; } + /*0 Info2("dup2(%d, %d)", ttyfd, fdo);*/ + } + if ((rw == XIO_RDONLY || fdi != ttyfd) && + (rw == XIO_WRONLY || fdo != ttyfd)) { + applyopts_cloexec(ttyfd, *copts); + } + + applyopts(ttyfd, *copts, PH_LATE); + + applyopts(ttyfd, *copts, PH_LATE2); + } else +#endif /* HAVE_PTY */ + if (usepipes) { + /* we might have a temporary conflict between what FDs are + currently allocated, and which are to be used. We try to find + a graceful solution via temporary descriptors */ + int tmpi, tmpo; + + if (fdi == rdpip[1]) { /* a conflict here */ + if ((tmpi = Dup(wrpip[0])) < 0) { + Error2("dup(%d): %s", wrpip[0], strerror(errno)); + return STAT_RETRYLATER; + } + /*0 Info2("dup(%d) -> %d", wrpip[0], tmpi);*/ + rdpip[1] = tmpi; + } + if (fdo == wrpip[0]) { /* a conflict here */ + if ((tmpo = Dup(rdpip[1])) < 0) { + Error2("dup(%d): %s", rdpip[1], strerror(errno)); + return STAT_RETRYLATER; + } + /*0 Info2("dup(%d) -> %d", rdpip[1], tmpo);*/ + wrpip[0] = tmpo; + } + + if (rw != XIO_WRONLY && rdpip[1] != fdo) { + if (Dup2(rdpip[1], fdo) < 0) { + Error3("dup2(%d, %d): %s", rdpip[1], fdo, strerror(errno)); + return STAT_RETRYLATER; + } + Close(rdpip[1]); + /*0 Info2("dup2(%d, %d)", rdpip[1], fdo);*/ + /*0 applyopts_cloexec(fdo, *copts);*/ + } + if (rw != XIO_RDONLY && wrpip[0] != fdi) { + if (Dup2(wrpip[0], fdi) < 0) { + Error3("dup2(%d, %d): %s", wrpip[0], fdi, strerror(errno)); + return STAT_RETRYLATER; + } + Close(wrpip[0]); + /*0 Info2("dup2(%d, %d)", wrpip[0], fdi);*/ + /*0 applyopts_cloexec(wrpip[0], *copts);*/ /* option is already consumed! */ + /* applyopts_cloexec(fdi, *copts);*/ /* option is already consumed! */ + } + + applyopts(fdi, *copts, PH_LATE); + applyopts(fdo, *copts, PH_LATE); + applyopts(fdi, *copts, PH_LATE2); + applyopts(fdo, *copts, PH_LATE2); + + } else { /* socketpair */ + if (rw != XIO_RDONLY && fdi != sv[1]) { + if (Dup2(sv[1], fdi) < 0) { + Error3("dup2(%d, %d): %s", sv[1], fdi, strerror(errno)); + return STAT_RETRYLATER; } + /*0 Info2("dup2(%d, %d)", sv[1], fdi);*/ + } + if (rw != XIO_WRONLY && fdo != sv[1]) { + if (Dup2(sv[1], fdo) < 0) { + Error3("dup2(%d, %d): %s", sv[1], fdo, strerror(errno)); + return STAT_RETRYLATER; } + /*0 Info2("dup2(%d, %d)", sv[1], fdo);*/ + } + if (fdi != sv[1] && fdo != sv[1]) { + applyopts_cloexec(sv[1], *copts); + } + + applyopts(fdi, *copts, PH_LATE); + applyopts(fdi, *copts, PH_LATE2); + } + } /* withfork */ + else { + applyopts(-1, *copts, PH_LATE); + applyopts(-1, *copts, PH_LATE2); + } + + /* what to do with stderr? */ + if (withstderr) { + /* handle it just like ordinary process output, i.e. copy output fd */ + if (!withfork) { + if (Dup2(fdo, 2) < 0) { + Error2("dup2(%d, 2): %s", fdo, strerror(errno)); + } + /*0 Info1("dup2(%d, 2)", fdo);*/ + } else +#if HAVE_PTY + if (usepty) { + if (Dup2(ttyfd, 2) < 0) { + Error2("dup2(%d, 2): %s", ttyfd, strerror(errno)); + } + /*0 Info1("dup2(%d, 2)", ttyfd);*/ + } else +#endif /* HAVE_PTY */ + if (usepipes) { + if (Dup2(/*rdpip[1]*/ fdo, 2) < 0) { + Error2("dup2(%d, 2): %s", /*rdpip[1]*/ fdo, strerror(errno)); + } + /*0 Info1("dup2(%d, 2)", rdpip[1]);*/ + } else { + if (Dup2(sv[1], 2) < 0) { + Error2("dup2(%d, 2): %s", sv[1], strerror(errno)); + } + /*0 Info1("dup2(%d, 2)", sv[1]);*/ + } + } + _xioopen_setdelayeduser(); + /* set group before user - maybe you are not permitted afterwards */ + if (retropt_gidt(*copts, OPT_SETGID, &group) >= 0) { + Setgid(group); + } + if (retropt_uidt(*copts, OPT_SETUID, &user) >= 0) { + Setuid(user); + } + return 0; /* indicate child process */ + } + + /* for parent (this is our socat process) */ + Notice1("forked off child process "F_pid, pid); + +#if 0 + if ((popts = copyopts(*copts, + GROUP_FD|GROUP_TERMIOS|GROUP_FORK|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_FIFO)) == NULL) + return STAT_RETRYLATER; +#endif + +#if HAVE_PTY + if (usepty) { + if (Close(ttyfd) < 0) { + Info2("close(%d): %s", ttyfd, strerror(errno)); + } + } /*0 else*/ +#endif /* HAVE_PTY */ +#if 0 + if (usepipes) { + } else { + } +#endif + fd->para.exec.pid = pid; + + if (applyopts_single(fd, popts, PH_LATE) < 0) return -1; + applyopts_signal(fd, popts); + if ((numleft = leftopts(popts)) > 0) { + Error1("%d option(s) could not be used", numleft); + showleft(popts); + return STAT_NORETRY; + } + + return pid; /* indicate parent (main) process */ +} +#endif /* WITH_EXEC || WITH_SYSTEM */ + + +int setopt_path(struct opt *opts, char **path) { + if (retropt_string(opts, OPT_PATH, path) >= 0) { + if (setenv("PATH", *path, 1) < 0) { + Error1("setenv(\"PATH\", \"%s\", 1): insufficient space", *path); + return -1; + } + } + return 0; +} diff --git a/xio-progcall.h b/xio-progcall.h new file mode 100644 index 0000000..d89ce31 --- /dev/null +++ b/xio-progcall.h @@ -0,0 +1,28 @@ +/* $Id: xio-progcall.h,v 1.13 2006/02/08 19:37:15 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_progcall_h_included +#define __xio_progcall_h_included 1 + +extern const struct optdesc opt_fdin; +extern const struct optdesc opt_fdout; +extern const struct optdesc opt_path; +extern const struct optdesc opt_pipes; +extern const struct optdesc opt_pty; +extern const struct optdesc opt_openpty; +extern const struct optdesc opt_ptmx; +extern const struct optdesc opt_stderr; +extern const struct optdesc opt_nofork; +extern const struct optdesc opt_sighup; +extern const struct optdesc opt_sigint; +extern const struct optdesc opt_sigquit; + +extern int _xioopen_foxec(int rw, /* O_RDONLY etc. */ + struct single *fd, + unsigned groups, + struct opt **opts + ); +extern int setopt_path(struct opt *opts, char **path); + +#endif /* !defined(__xio_progcall_h_included) */ diff --git a/xio-proxy.c b/xio-proxy.c new file mode 100644 index 0000000..df673f2 --- /dev/null +++ b/xio-proxy.c @@ -0,0 +1,561 @@ +/* $Id: xio-proxy.c,v 1.28 2006/12/28 14:02:54 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2002-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for opening addresses of HTTP proxy CONNECT + type */ + +#include "xiosysincludes.h" + +#if WITH_PROXY + +#include "xioopen.h" +#include "xio-socket.h" +#include "xio-ipapp.h" +#include "xio-ascii.h" /* for base64 encoding of authentication */ + +#include "xio-proxy.h" + + +#define PROXYPORT "8080" + +static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *fd, + unsigned groups, int dummy1, int dummy2, + int dummy3); + +const struct optdesc opt_proxyport = { "proxyport", NULL, OPT_PROXYPORT, GROUP_HTTP, PH_LATE, TYPE_STRING, OFUNC_SPEC }; +const struct optdesc opt_ignorecr = { "ignorecr", NULL, OPT_IGNORECR, GROUP_HTTP, PH_LATE, TYPE_BOOL, OFUNC_SPEC }; +const struct optdesc opt_proxy_resolve = { "proxy-resolve", "resolve", OPT_PROXY_RESOLVE, GROUP_HTTP, PH_LATE, TYPE_BOOL, OFUNC_SPEC }; +const struct optdesc opt_proxy_authorization = { "proxy-authorization", "proxyauth", OPT_PROXY_AUTHORIZATION, GROUP_HTTP, PH_LATE, TYPE_STRING, OFUNC_SPEC }; + +const struct addrdesc addr_proxy_connect = { "proxy", 3, xioopen_proxy_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_HTTP|GROUP_CHILD|GROUP_RETRY, 0, 0, 0 HELP(":::") }; + + +/*0#define CONNLEN 40*/ /* "CONNECT 123.156.189.123:65432 HTTP/1.0\r\n\0" */ +#define CONNLEN 281 /* "CONNECT <255bytes>:65432 HTTP/1.0\r\n\0" */ + +/* states during receiving answer */ +enum { + XIOSTATE_HTTP1, /* 0 or more bytes of first line received, no \r */ + XIOSTATE_HTTP2, /* first line received including \r */ + XIOSTATE_HTTP3, /* received status and \r\n */ + XIOSTATE_HTTP4, /* within header */ + XIOSTATE_HTTP5, /* within header, \r */ + XIOSTATE_HTTP6, /* received status and 1 or more headers, \r\n */ + XIOSTATE_HTTP7, /* received status line, ev. headers, \r\n\r */ + XIOSTATE_HTTP8, /* complete answer received */ + XIOSTATE_ERROR /* error during HTTP headers */ +} ; + + +/* get buflen bytes from proxy server; + handles EINTR; + returns <0 when error occurs +*/ +static ssize_t + xioproxy_recvbytes(struct single *xfd, char *buff, size_t buflen, int level) { + ssize_t result; + do { + /* we need at least buflen bytes... */ + result = Read(xfd->fd, buff, buflen); + } while (result < 0 && errno == EINTR); /*! EAGAIN? */ + if (result < 0) { + Msg4(level, "read(%d, %p, "F_Zu"): %s", + xfd->fd, buff, buflen, strerror(errno)); + return result; + } + if (result == 0) { + Msg(level, "proxy_connect: connection closed by proxy"); + } + return result; +} + + +#define BUFLEN 2048 + + +static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xxfd, + unsigned groups, int dummy1, int dummy2, + int dummy3) { + /* we expect the form: host:host:port */ + struct single *xfd = &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 pf = PF_UNSPEC; + union sockaddr_union us_sa, *us = &us_sa; + union sockaddr_union them_sa, *them = &them_sa; + socklen_t uslen = sizeof(us_sa); + socklen_t themlen = sizeof(them_sa); + const char *proxyname; char *proxyport = NULL; + const char *targetname, *targetport; + int ipproto = IPPROTO_TCP; + bool needbind = false; + bool lowport = false; + int socktype = SOCK_STREAM; + int level; + int result; + + if (argc != 4) { + Error1("%s: 3 parameters required", argv[0]); + return STAT_NORETRY; + } + proxyname = argv[1]; + targetname = argv[2]; + targetport = argv[3]; + + xfd->howtoend = END_SHUTDOWN; + if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; + applyopts(-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); + if (result != STAT_OK) return result; + + result = + _xioopen_ipapp_prepare(opts, &opts0, proxyname, proxyport, + &pf, ipproto, + xfd->para.socket.ip.res_opts[1], + xfd->para.socket.ip.res_opts[0], + them, &themlen, us, &uslen, + &needbind, &lowport, &socktype); + if (result != STAT_OK) return result; + + Notice4("opening connection to %s:%u via proxy %s:%s", + proxyvars->targetaddr, proxyvars->targetport, proxyname, proxyport); + + do { /* loop over failed connect and proxy connect attempts */ + +#if WITH_RETRY + if (xfd->forever || xfd->retry) { + level = E_INFO; + } else +#endif /* WITH_RETRY */ + level = E_ERROR; + + result = + _xioopen_connect(xfd, + needbind?(struct sockaddr *)us:NULL, sizeof(*us), + (struct sockaddr *)them, themlen, + opts, pf, socktype, IPPROTO_TCP, lowport, level); + switch (result) { + case STAT_OK: break; +#if WITH_RETRY + case STAT_RETRYLATER: + case STAT_RETRYNOW: + if (xfd->forever || xfd->retry--) { + if (result == STAT_RETRYLATER) Nanosleep(&xfd->intervall, NULL); + continue; + } +#endif /* WITH_RETRY */ + default: + return result; + } + + applyopts(xfd->fd, opts, PH_ALL); + + if ((result = _xio_openlate(xfd, opts)) < 0) + return result; + + result = _xioopen_proxy_connect(xfd, proxyvars, level); + switch (result) { + case STAT_OK: break; +#if WITH_RETRY + case STAT_RETRYLATER: + case STAT_RETRYNOW: + if (xfd->forever || xfd->retry--) { + if (result == STAT_RETRYLATER) Nanosleep(&xfd->intervall, NULL); + continue; + } +#endif /* WITH_RETRY */ + default: + return result; + } + +#if WITH_RETRY + if (dofork) { + pid_t pid; + while ((pid = Fork()) < 0) { + int level = E_ERROR; + if (xfd->forever || xfd->retry) { + level = E_WARN; + } + Msg1(level, "fork(): %s", strerror(errno)); + if (xfd->forever || xfd->retry--) { + Nanosleep(&xfd->intervall, NULL); + continue; + } + return STAT_RETRYLATER; + } + if (pid == 0) { /* child process */ + Info1("just born: proxy client process "F_pid, Getpid()); + + /* drop parents locks, reset FIPS... */ + if (xio_forked_inchild() != 0) { + Exit(1); + } + xfd->forever = false; xfd->retry = 0; + break; + } + /* parent process */ + Notice1("forked off child process "F_pid, pid); + Close(xfd->fd); + Nanosleep(&xfd->intervall, NULL); + dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); + continue; + } else +#endif /* WITH_RETRY */ + { + break; + } + + } while (true); /* end of complete open loop - drop out on success */ + + Notice4("successfully connected to %s:%u via proxy %s:%s", + proxyvars->targetaddr, proxyvars->targetport, + proxyname, proxyport); + + return 0; +} + + +int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts, + const char *targetname, const char *targetport) { + struct hostent *host; + + retropt_bool(opts, OPT_IGNORECR, &proxyvars->ignorecr); + retropt_bool(opts, OPT_PROXY_RESOLVE, &proxyvars->doresolve); + retropt_string(opts, OPT_PROXY_AUTHORIZATION, &proxyvars->authstring); + + 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 + represented in CONNECT commands this code might be extended */ + host = Gethostbyname(targetname); + if (host == NULL) { + int level = E_WARN; + Msg2(level, "gethostbyname(\"%s\"): %s", targetname, + h_errno == NETDB_INTERNAL ? strerror(errno) : + hstrerror(h_errno)/*0 h_messages[h_errno-1]*/); + proxyvars->targetaddr = strdup(targetname); + } else { +#define LEN 16 /* www.xxx.yyy.zzz\0 */ + if ((proxyvars->targetaddr = Malloc(LEN)) == NULL) { + return STAT_RETRYLATER; + } + snprintf(proxyvars->targetaddr, LEN, "%u.%u.%u.%u", + (unsigned char)host->h_addr_list[0][0], + (unsigned char)host->h_addr_list[0][1], + (unsigned char)host->h_addr_list[0][2], + (unsigned char)host->h_addr_list[0][3]); +#undef LEN + } + } else { + proxyvars->targetaddr = strdup(targetname); + } + + proxyvars->targetport = htons(parseport(targetport, IPPROTO_TCP)); + + return STAT_OK; +} + +int _xioopen_proxy_connect(struct single *xfd, + struct proxyvars *proxyvars, + int level) { + size_t offset; + char request[CONNLEN]; + char buff[BUFLEN+1]; +#if CONNLEN > BUFLEN +#error not enough buffer space +#endif + char textbuff[2*BUFLEN+1]; /* just for sanitizing print data */ + char *eol = buff; + int state; + ssize_t sresult; + + /* generate proxy request header - points to final target */ + sprintf(request, "CONNECT %s:%u HTTP/1.0\r\n", + proxyvars->targetaddr, proxyvars->targetport); + + /* send proxy CONNECT request (target addr+port) */ + * xiosanitize(request, strlen(request), textbuff) = '\0'; + Info1("sending \"%s\"", textbuff); + /* write errors are assumed to always be hard errors, no retry */ + do { + sresult = Write(xfd->fd, request, strlen(request)); + } while (sresult < 0 && errno == EINTR); + if (sresult < 0) { + Msg4(level, "write(%d, %p, "F_Zu"): %s", + xfd->fd, request, strlen(request), strerror(errno)); + if (Close(xfd->fd) < 0) { + Info2("close(%d): %s", xfd->fd, strerror(errno)); + } + return STAT_RETRYLATER; + } + + if (proxyvars->authstring) { + /* send proxy authentication header */ +# define XIOAUTHHEAD "Proxy-authorization: Basic " +# define XIOAUTHLEN 27 + static const char *authhead = XIOAUTHHEAD; +# define HEADLEN 256 + char *header, *next; + + /* ...\r\n\0 */ + if ((header = + Malloc(XIOAUTHLEN+((strlen(proxyvars->authstring)+2)/3)*4+3)) + == NULL) { + return -1; + } + strcpy(header, authhead); + next = xiob64encodeline(proxyvars->authstring, + strlen(proxyvars->authstring), + strchr(header, '\0')); + *next = '\0'; + Info1("sending \"%s\\r\\n\"", header); + *next++ = '\r'; *next++ = '\n'; *next++ = '\0'; + do { + sresult = Write(xfd->fd, header, strlen(header)); + } while (sresult < 0 && errno == EINTR); + if (sresult < 0) { + Msg4(level, "write(%d, %p, "F_Zu"): %s", + xfd->fd, header, strlen(header), strerror(errno)); + if (Close(xfd->fd) < 0) { + Info2("close(%d): %s", xfd->fd, strerror(errno)); + } + return STAT_RETRYLATER; + } + + free(header); + } + + Info("sending \"\\r\\n\""); + do { + sresult = Write(xfd->fd, "\r\n", 2); + } while (sresult < 0 && errno == EINTR); + /*! */ + + /* request is kept for later error messages */ + *strstr(request, " HTTP") = '\0'; + + /* receive proxy answer; looks like "HTTP/1.0 200 .*\r\nHeaders..\r\n\r\n" */ + /* socat version 1 depends on a valid fd for data transfer; address + therefore cannot buffer data. So, to prevent reading beyond the end of + the answer headers, only single bytes are read. puh. */ + state = XIOSTATE_HTTP1; + offset = 0; /* up to where the buffer is filled (relative) */ + /*eol;*/ /* points to the first lineterm of the current line */ + do { + sresult = xioproxy_recvbytes(xfd, buff+offset, 1, level); + if (sresult <= 0) { + state = XIOSTATE_ERROR; + break; /* leave read cycles */ + } + + switch (state) { + + case XIOSTATE_HTTP1: + /* 0 or more bytes of first line received, no '\r' yet */ + if (*(buff+offset) == '\r') { + eol = buff+offset; + state = XIOSTATE_HTTP2; + break; + } + if (proxyvars->ignorecr && *(buff+offset) == '\n') { + eol = buff+offset; + state = XIOSTATE_HTTP3; + break; + } + break; + + case XIOSTATE_HTTP2: + /* first line received including '\r' */ + if (*(buff+offset) != '\n') { + state = XIOSTATE_HTTP1; + break; + } + state = XIOSTATE_HTTP3; + break; + + case XIOSTATE_HTTP3: + /* received status (first line) and "\r\n" */ + if (*(buff+offset) == '\r') { + state = XIOSTATE_HTTP7; + break; + } + if (proxyvars->ignorecr && *(buff+offset) == '\n') { + state = XIOSTATE_HTTP8; + break; + } + state = XIOSTATE_HTTP4; + break; + + case XIOSTATE_HTTP4: + /* within header */ + if (*(buff+offset) == '\r') { + eol = buff+offset; + state = XIOSTATE_HTTP5; + break; + } + if (proxyvars->ignorecr && *(buff+offset) == '\n') { + eol = buff+offset; + state = XIOSTATE_HTTP6; + break; + } + break; + + case XIOSTATE_HTTP5: + /* within header, '\r' received */ + if (*(buff+offset) != '\n') { + state = XIOSTATE_HTTP4; + break; + } + state = XIOSTATE_HTTP6; + break; + + case XIOSTATE_HTTP6: + /* received status (first line) and 1 or more headers, "\r\n" */ + if (*(buff+offset) == '\r') { + state = XIOSTATE_HTTP7; + break; + } + if (proxyvars->ignorecr && *(buff+offset) == '\n') { + state = XIOSTATE_HTTP8; + break; + } + state = XIOSTATE_HTTP4; + break; + + case XIOSTATE_HTTP7: + /* received status (first line), 0 or more headers, "\r\n\r" */ + if (*(buff+offset) == '\n') { + state = XIOSTATE_HTTP8; + break; + } + if (*(buff+offset) == '\r') { + if (proxyvars->ignorecr) { + break; /* ignore it, keep waiting for '\n' */ + } else { + state = XIOSTATE_HTTP5; + } + break; + } + state = XIOSTATE_HTTP4; + break; + + } + ++offset; + + /* end of status line reached */ + if (state == XIOSTATE_HTTP3) { + char *ptr; + /* set a terminating null - on or after CRLF? */ + *(buff+offset) = '\0'; + + * xiosanitize(buff, Min(offset, (sizeof(textbuff)-1)>>1), textbuff) + = '\0'; + Info1("proxy_connect: received answer \"%s\"", textbuff); + *eol = '\0'; + * xiosanitize(buff, Min(strlen(buff), (sizeof(textbuff)-1)>>1), + textbuff) = '\0'; + if (strncmp(buff, "HTTP/1.0 ", 9) && + strncmp(buff, "HTTP/1.1 ", 9)) { + /* invalid answer */ + Msg1(level, "proxy: invalid answer \"%s\"", textbuff); + return STAT_RETRYLATER; + } + ptr = buff+9; + + /* skip multiple spaces */ + while (*ptr == ' ') ++ptr; + + /* HTTP answer */ + if (strncmp(ptr, "200", 3)) { + /* not ok */ + /* CERN: + "HTTP/1.0 200 Connection established" + "HTTP/1.0 400 Invalid request "CONNECT 10.244.9.3:8080 HTTP/1.0" (unknown method)" + "HTTP/1.0 403 Forbidden - by rule" + "HTTP/1.0 407 Proxy Authentication Required" + Proxy-Authenticate: Basic realm="Squid proxy-caching web server" +> 50 72 6f 78 79 2d 61 75 74 68 6f 72 69 7a 61 74 Proxy-authorizat +> 69 6f 6e 3a 20 42 61 73 69 63 20 61 57 4e 6f 63 ion: Basic aWNoc +> 32 56 73 59 6e 4e 30 4f 6e 4e 30 63 6d 56 75 5a 2VsYnN0OnN0cmVuZ +> 32 64 6c 61 47 56 70 62 51 3d 3d 0d 0a 2dlaGVpbQ==.. + b64encode("username:password") + "HTTP/1.0 500 Can't connect to host" + */ + /* Squid: + "HTTP/1.0 400 Bad Request" + "HTTP/1.0 403 Forbidden" + "HTTP/1.0 503 Service Unavailable" + interesting header: "X-Squid-Error: ERR_CONNECT_FAIL 111" */ + /* Apache: + "HTTP/1.0 400 Bad Request" + "HTTP/1.1 405 Method Not Allowed" + */ + /* WTE: + "HTTP/1.1 200 Connection established" + "HTTP/1.1 404 Host not found or not responding, errno: 79" + "HTTP/1.1 404 Host not found or not responding, errno: 32" + "HTTP/1.1 404 Host not found or not responding, errno: 13" + */ + /* IIS: + "HTTP/1.1 404 Object Not Found" + */ + ptr += 3; + while (*ptr == ' ') ++ptr; + + Msg2(level, "%s: %s", request, ptr); + return STAT_RETRYLATER; + } + + /* ok!! */ + /* "HTTP/1.0 200 Connection established" */ + /*Info1("proxy: \"%s\"", textbuff+13);*/ + offset = 0; + + } else if (state == XIOSTATE_HTTP6) { + /* end of a header line reached */ + char *endp; + + /* set a terminating null */ + *(buff+offset) = '\0'; + + endp = + xiosanitize(buff, Min(offset, (sizeof(textbuff)-1)>>1), + textbuff); + *endp = '\0'; + Info1("proxy_connect: received header \"%s\"", textbuff); + offset = 0; + } + + } while (state != XIOSTATE_HTTP8 && offset < BUFLEN); + + if (state == XIOSTATE_ERROR) { + return STAT_RETRYLATER; + } + + if (offset >= BUFLEN) { + Msg1(level, "proxy answer exceeds "F_Zu" bytes, aborting", BUFLEN); + return STAT_NORETRY; + } + + return STAT_OK; +} + +#endif /* WITH_PROXY */ + diff --git a/xio-proxy.h b/xio-proxy.h new file mode 100644 index 0000000..bcaa054 --- /dev/null +++ b/xio-proxy.h @@ -0,0 +1,30 @@ +/* $Id: xio-proxy.h,v 1.6 2006/05/31 19:17:57 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2002-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_proxy_h_included +#define __xio_proxy_h_included 1 + + +struct proxyvars { + bool ignorecr; + bool doresolve; + char *authstring; + char *targetaddr; /* name/address of host, in malloced string */ + uint16_t targetport; +} ; + +extern const struct optdesc opt_proxyport; +extern const struct optdesc opt_ignorecr; +extern const struct optdesc opt_proxy_resolve; +extern const struct optdesc opt_proxy_authorization; + +extern const struct addrdesc addr_proxy_connect; + +int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts, + const char *targetname, const char *targetport); +int _xioopen_proxy_connect(struct single *xfd, + struct proxyvars *proxyvars, + int level); + +#endif /* !defined(__xio_proxy_h_included) */ diff --git a/xio-pty.c b/xio-pty.c new file mode 100644 index 0000000..c56f17e --- /dev/null +++ b/xio-pty.c @@ -0,0 +1,212 @@ +/* $Id: xio-pty.c,v 1.20 2007/01/25 21:36:11 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2002-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for creating pty addresses */ + +#include "xiosysincludes.h" +#include "xioopen.h" + +#include "xio-named.h" +#include "xio-termios.h" + + +#if WITH_PTY + +/* here define the preferred polling intervall, in seconds */ +#define PTY_INTERVALL 1,0 /* for struct timespec */ + +#define MAXPTYNAMELEN 64 + +static int xioopen_pty(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); + +const struct addrdesc addr_pty = { "pty", 3, xioopen_pty, GROUP_NAMED|GROUP_FD|GROUP_TERMIOS|GROUP_PTY, 0, 0, 0 HELP("") }; + +const struct optdesc opt_symbolic_link = { "symbolic-link", "link", OPT_SYMBOLIC_LINK, GROUP_PTY, PH_LATE, TYPE_FILENAME, OFUNC_SPEC, 0, 0 }; +#if HAVE_POLL +const struct optdesc opt_pty_wait_slave = { "pty-wait-slave", "wait-slave", OPT_PTY_WAIT_SLAVE, GROUP_PTY, PH_EARLY, TYPE_BOOL, OFUNC_SPEC, 0, 0 }; +const struct optdesc opt_pty_intervall = { "pty-intervall", NULL, OPT_PTY_INTERVALL, GROUP_PTY, PH_EARLY, TYPE_TIMESPEC, OFUNC_SPEC, 0, 0 }; +#endif /* HAVE_POLL */ + +static int xioopen_pty(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3) { + /* we expect the form: filename */ + int ptyfd = -1, ttyfd = -1; +#if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC) + bool useptmx = false; /* use /dev/ptmx or equivalent */ +#endif +#if HAVE_OPENPTY + bool useopenpty = false; /* try only openpty */ +#endif /* HAVE_OPENPTY */ + char ptyname[MAXPTYNAMELEN]; + char *tn = NULL; + char *linkname = NULL; + bool opt_unlink_close = true; /* remove symlink afterwards */ + bool wait_slave = false; /* true would be better for many platforms, but + some OSes cannot handle this, and for common + default behaviour as well as backward + compatibility we choose "no" as default */ + struct timespec pollintv = { PTY_INTERVALL }; + + xfd->stream.howtoend = END_CLOSE; + + applyopts(-1, opts, PH_INIT); + if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1; + + retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); + + /* trying to set user-early, perm-early etc. here might be useless because + file system entry is eventually available only past pty creation */ + /* name not yet known; umask should not be handled with this function! */ + /* umask does not affect resulting mode, on Linux 2.4 */ + applyopts_named("", opts, PH_EARLY); /* umask! */ + +#if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC) + retropt_bool(opts, OPT_PTMX, &useptmx); +#endif +#if HAVE_OPENPTY + retropt_bool(opts, OPT_OPENPTY, &useopenpty); +#endif + +#if (defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)) +# if HAVE_OPENPTY + useopenpty = !useptmx; +# else /* !HAVE_OPENPTY */ + useptmx = true; +# endif /* !HAVE_OPENPTY */ +#else + useopenpty = true; +#endif /* ! (defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)) */ + +#if HAVE_POLL + retropt_bool(opts, OPT_PTY_WAIT_SLAVE, &wait_slave); + retropt_timespec(opts, OPT_PTY_INTERVALL, &pollintv); +#endif /* HAVE_POLL */ + + applyopts2(-1, opts, PH_INIT, PH_EARLY); + if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1; + + applyopts(-1, opts, PH_PREBIGEN); + +#if defined(HAVE_DEV_PTMX) +# define PTMX "/dev/ptmx" /* Linux */ +#elif HAVE_DEV_PTC +# define PTMX "/dev/ptc" /* AIX 4.3.3 */ +#endif +#if HAVE_DEV_PTMX || HAVE_DEV_PTC + if (useptmx) { + if ((ptyfd = Open(PTMX, O_RDWR|O_NOCTTY, 0620)) < 0) { + Warn1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620): %s", + strerror(errno)); + /*!*/ + } else { + ;/*0 Info1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620) -> %d", ptyfd);*/ + } + if (ptyfd >= 0 && ttyfd < 0) { + /* we used PTMX before forking */ + /*0 extern char *ptsname(int);*/ +#if HAVE_GRANTPT /* AIX, not Linux */ + if (Grantpt(ptyfd)/*!*/ < 0) { + Warn2("grantpt(%d): %s", ptyfd, strerror(errno)); + } +#endif /* HAVE_GRANTPT */ +#if HAVE_UNLOCKPT + if (Unlockpt(ptyfd)/*!*/ < 0) { + Warn2("unlockpt(%d): %s", ptyfd, strerror(errno)); + } +#endif /* HAVE_UNLOCKPT */ +#if HAVE_PTSNAME /* AIX, not Linux */ + if ((tn = Ptsname(ptyfd)) == NULL) { + Warn2("ptsname(%d): %s", ptyfd, strerror(errno)); + } else { + Notice1("PTY is %s", tn); + } +#endif /* HAVE_PTSNAME */ + if (tn == NULL) { + if ((tn = Ttyname(ptyfd)) == NULL) { + Warn2("ttyname(%d): %s", ptyfd, strerror(errno)); + } + } + strncpy(ptyname, tn, MAXPTYNAMELEN); + } + } +#endif /* HAVE_DEV_PTMX || HAVE_DEV_PTC */ +#if HAVE_OPENPTY + if (ptyfd < 0) { + int result; + if ((result = Openpty(&ptyfd, &ttyfd, ptyname, NULL, NULL)) < 0) { + Error4("openpty(%p, %p, %p, NULL, NULL): %s", + &ptyfd, &ttyfd, ptyname, strerror(errno)); + return -1; + } + Notice1("PTY is %s", ptyname); + } +#endif /* HAVE_OPENPTY */ + + if (!retropt_string(opts, OPT_SYMBOLIC_LINK, &linkname)) { + if (Unlink(linkname) < 0 && errno != ENOENT) { + Error2("unlink(\"%s\"): %s", linkname, strerror(errno)); + } + if (Symlink(ptyname, linkname) < 0) { + Error3("symlink(\"%s\", \"%s\"): %s", + ptyname, linkname, strerror(errno)); + } + if (opt_unlink_close) { + if ((xfd->stream.unlink_close = strdup(linkname)) == NULL) { + Error1("strdup(\"%s\"): out of memory", linkname); + } + xfd->stream.opt_unlink_close = true; + } + } + + applyopts_named(ptyname, opts, PH_PASTOPEN); + applyopts_named(ptyname, opts, PH_FD); + + applyopts_cloexec(ptyfd, opts);/*!*/ + xfd->stream.dtype = XIODATA_PTY; + + applyopts(ptyfd, opts, PH_FD); + + xfd->stream.fd = ptyfd; + applyopts(ptyfd, opts, PH_LATE); + if (applyopts_single(&xfd->stream, opts, PH_LATE) < 0) return -1; + +#if HAVE_POLL + /* if you can and wish: */ + if (wait_slave) { + /* try to wait until someone opens the slave side of the pty */ + /* we want to get a HUP (hangup) condition on the pty */ +#if HAVE_DEV_PTMX || HAVE_DEV_PTC + if (useptmx) { + ttyfd = Open(tn, O_RDWR|O_NOCTTY, 0620); + Close(ttyfd); + } +#endif +#if HAVE_OPENPTY + if (useopenpty) { + Close(ttyfd); + } +#endif /* HAVE_OPENPTY */ + + /* now we poll until the HUP vanishes - this indicates a slave conn. */ + while (true) { + struct pollfd ufd; + ufd.fd = ptyfd; + ufd.events = (POLLHUP); + if (Poll(&ufd, 1, 0) < 0) { + Error3("poll({%d, 0x%04hu,}, 1, 0): %s", + ufd.fd, ufd.events, strerror(errno)); + /*! close something */ + return -1; + } + if (!(ufd.revents & POLLHUP)) { + break; + } + Nanosleep(&pollintv, NULL); + continue; + } + } +#endif /* HAVE_POLL */ + + return STAT_OK; +} +#endif /* WITH_PTY */ diff --git a/xio-pty.h b/xio-pty.h new file mode 100644 index 0000000..1d77414 --- /dev/null +++ b/xio-pty.h @@ -0,0 +1,16 @@ +/* $Id: xio-pty.h,v 1.2 2004/10/24 13:49:53 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2002-2004 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_pty_h_included +#define __xio_pty_h_included 1 + +extern const struct addrdesc addr_pty; + +extern const struct optdesc opt_symbolic_link; +#if HAVE_POLL +extern const struct optdesc opt_pty_wait_slave; +extern const struct optdesc opt_pty_intervall; +#endif /* HAVE_POLL */ + +#endif /* !defined(__xio_pty_h_included) */ diff --git a/xio-rawip.c b/xio-rawip.c new file mode 100644 index 0000000..187942f --- /dev/null +++ b/xio-rawip.c @@ -0,0 +1,303 @@ +/* $Id: xio-rawip.c,v 1.32 2007/02/05 19:56:34 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for opening addresses of raw IP type */ + +#include "xiosysincludes.h" + +#if (WITH_IP4 || WITH_IP6) && WITH_RAWIP + +#include "xioopen.h" +#include "xio-socket.h" +#include "xio-ip.h" +#include "xio-ip6.h" +#include "xio-tcpwrap.h" + +#include "xio-rawip.h" + + + +static +int xioopen_rawip_sendto(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *fd, unsigned groups, int pf, + int dummy2, int dummy3); +static +int xioopen_rawip_datagram(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *fd, unsigned groups, int pf, + int dummy2, int dummy3); +static +int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xfd, unsigned groups, + int pf, int dummy2, int dummy3); +static +int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xfd, unsigned groups, + int pf, int socktype, int ipproto); + +static +int _xioopen_rawip_sendto(const char *hostname, const char *protname, + struct opt *opts, int xioflags, + xiofile_t *xxfd, unsigned groups, int pf); + +const struct addrdesc addr_rawip_sendto = { "ip-sendto", 3, xioopen_rawip_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6, PF_UNSPEC, 0, 0 HELP("::") }; +const struct addrdesc addr_rawip_datagram= { "ip-datagram", 3, xioopen_rawip_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_RANGE, PF_UNSPEC, 0, 0 HELP("::") }; +const struct addrdesc addr_rawip_recvfrom= { "ip-recvfrom", 3, xioopen_rawip_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_CHILD|GROUP_RANGE, PF_UNSPEC, SOCK_RAW, 0 HELP(":") }; +const struct addrdesc addr_rawip_recv = { "ip-recv", 1, xioopen_rawip_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_RANGE, PF_UNSPEC, SOCK_RAW, 0 HELP(":") }; + +#if WITH_IP4 +const struct addrdesc addr_rawip4_sendto = { "ip4-sendto", 3, xioopen_rawip_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4, PF_INET, 0, 0 HELP("::") }; +const struct addrdesc addr_rawip4_datagram= { "ip4-datagram", 3, xioopen_rawip_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_RANGE, PF_INET, 0, 0 HELP("::") }; +const struct addrdesc addr_rawip4_recvfrom= { "ip4-recvfrom", 3, xioopen_rawip_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_CHILD|GROUP_RANGE, PF_INET, SOCK_RAW, 0 HELP(":") }; +const struct addrdesc addr_rawip4_recv = { "ip4-recv", 1, xioopen_rawip_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_RANGE, PF_INET, SOCK_RAW, 0 HELP(":") }; +#endif + +#if WITH_IP6 +const struct addrdesc addr_rawip6_sendto = { "ip6-sendto", 3, xioopen_rawip_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6, PF_INET6, 0, 0 HELP("::") }; +const struct addrdesc addr_rawip6_datagram= { "ip6-datagram", 3, xioopen_rawip_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_RANGE, PF_INET6, 0, 0 HELP("::") }; +const struct addrdesc addr_rawip6_recvfrom= { "ip6-recvfrom", 3, xioopen_rawip_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_CHILD|GROUP_RANGE, PF_INET6, SOCK_RAW, 0 HELP(":") }; +const struct addrdesc addr_rawip6_recv = { "ip6-recv", 1, xioopen_rawip_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_RANGE, PF_INET6, SOCK_RAW, 0 HELP(":") }; +#endif + + +/* we expect the form: host:protocol */ +/* struct sockaddr_in sa;*/ +/* socklen_t salen;*/ +static +int xioopen_rawip_sendto(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xxfd, unsigned groups, + int pf, int dummy2, int dummy3) { + int result; + + if (argc != 3) { + Error2("%s: wrong number of parameters (%d instead of 2)", + argv[0], argc-1); + return STAT_NORETRY; + } + if ((result = _xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd, + groups, pf)) != STAT_OK) { + return result; + } + _xio_openlate(&xxfd->stream, opts); + return STAT_OK; +} + +static +int _xioopen_rawip_sendto(const char *hostname, const char *protname, + struct opt *opts, int xioflags, xiofile_t *xxfd, + unsigned groups, int pf) { + char *garbage; + xiosingle_t *xfd = &xxfd->stream; + union sockaddr_union us; + socklen_t uslen; + int feats = 1; /* option bind supports only address, not port */ + int socktype = SOCK_RAW; + int ipproto; + bool needbind = false; + int result; + + if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) { + Error3("xioopen_rawip_sendto(\"%s:%s\",,): protocol number exceeds 255 (%u)", + hostname, protname, ipproto); + return STAT_NORETRY; + } else if (*garbage) { + Warn2("xioopen_rawip_sendto(\"%s:%s\",,): trailing garbage in protocol specification", + hostname, protname); + /*return STAT_NORETRY;*/ + } + + xfd->howtoend = END_SHUTDOWN; + retropt_int(opts, OPT_SO_TYPE, &socktype); + + /* ...res_opts[] */ + if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; + applyopts(-1, opts, PH_INIT); + + xfd->salen = sizeof(xfd->peersa); + if ((result = + xiogetaddrinfo(hostname, NULL, pf, socktype, ipproto, + &xfd->peersa, &xfd->salen, + xfd->para.socket.ip.res_opts[0], + xfd->para.socket.ip.res_opts[1])) + != STAT_OK) { + return result; + } + if (pf == PF_UNSPEC) { + pf = xfd->peersa.soa.sa_family; + } + + uslen = socket_init(pf, &us); + + xfd->dtype = XIODATA_RECVFROM_SKIPIP; + + if (retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, feats, + xfd->para.socket.ip.res_opts[0], + xfd->para.socket.ip.res_opts[1]) != STAT_NOACTION) { + needbind = true; + } + return + _xioopen_dgram_sendto(needbind?&us:NULL, uslen, + opts, xioflags, xfd, groups, pf, socktype, ipproto); +} + + +/* we expect the form: address:protocol */ +static +int xioopen_rawip_datagram(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xxfd, unsigned groups, + int pf, int dummy2, int dummy3) { + xiosingle_t *xfd = &xxfd->stream; + char *rangename; + int result; + + if (argc != 3) { + Error2("%s: wrong number of parameters (%d instead of 2)", + argv[0], argc-1); + return STAT_NORETRY; + } + if ((result = + _xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd, + groups, pf)) != STAT_OK) { + return result; + } + + xfd->dtype = XIOREAD_RECV|XIOWRITE_SENDTO; + if (pf == PF_INET) { + xfd->dtype |= XIOREAD_RECV_SKIPIP; + } + + xfd->para.socket.la.soa.sa_family = xfd->peersa.soa.sa_family; + + /* which reply packets will be accepted - determine by range option */ + if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { + if (parserange(rangename, pf, &xfd->para.socket.range) < 0) { + free(rangename); + return STAT_NORETRY; + } + xfd->para.socket.dorange = true; + xfd->dtype |= XIOREAD_RECV_CHECKRANGE; + free(rangename); + } + +#if WITH_LIBWRAP + xio_retropt_tcpwrap(xfd, opts); +#endif /* WITH_LIBWRAP */ + + _xio_openlate(xfd, opts); + return STAT_OK; +} + + +static +int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xfd, unsigned groups, + int pf, int socktype, int dummy3) { + const char *protname = argv[1]; + char *garbage; + union sockaddr_union us; + socklen_t uslen = sizeof(us); + int ipproto; + bool needbind = false; + int result; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", + argv[0], argc-1); + return STAT_NORETRY; + } + + if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) { + Error2("xioopen_rawip_recvfrom(\"%s\",,): protocol number exceeds 255 (%u)", + protname, ipproto); + return STAT_NORETRY; + } else if (*garbage) { + Warn1("xioopen_rawip_recvfrom(\"%s\",,): trailing garbage in protocol specification", + protname); + /*return STAT_NORETRY;*/ + } + xfd->stream.howtoend = END_NONE; + retropt_int(opts, OPT_SO_TYPE, &socktype); + + retropt_socket_pf(opts, &pf); + if (pf == PF_UNSPEC) { +#if WITH_IP4 && WITH_IP6 + pf = xioopts.default_ip=='6'?PF_INET6:PF_INET; +#elif WITH_IP6 + pf = PF_INET6; +#else + pf = PF_INET; +#endif + } + + if (retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, 1, + xfd->stream.para.socket.ip.res_opts[0], + xfd->stream.para.socket.ip.res_opts[1]) != STAT_NOACTION) { + needbind = true; + } + + xfd->stream.dtype = XIODATA_RECVFROM_SKIPIP_ONE; + if ((result = + _xioopen_dgram_recvfrom(&xfd->stream, xioflags, needbind?&us.soa:NULL, + uslen, opts, pf, socktype, ipproto, E_ERROR)) + != STAT_OK) { + return result; + } + _xio_openlate(&xfd->stream, opts); + return STAT_OK; +} + + +static +int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xfd, unsigned groups, + int pf, int socktype, int ipproto) { + const char *protname = argv[1]; + char *garbage; + union sockaddr_union us; + socklen_t uslen = sizeof(us); + int result; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", + argv[0], argc-1); + return STAT_NORETRY; + } + + if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) { + Error2("xioopen_rawip_recvfrom(\"%s\",,): protocol number exceeds 255 (%u)", + protname, ipproto); + return STAT_NORETRY; + } else if (*garbage) { + Warn1("xioopen_rawip_recvfrom(\"%s\",,): trailing garbage in protocol specification", + protname); + /*return STAT_NORETRY;*/ + } + retropt_int(opts, OPT_SO_TYPE, &socktype); + + retropt_socket_pf(opts, &pf); + if (pf == PF_UNSPEC) { +#if WITH_IP4 && WITH_IP6 + pf = xioopts.default_ip=='6'?PF_INET6:PF_INET; +#elif WITH_IP6 + pf = PF_INET6; +#else + pf = PF_INET; +#endif + } + + if (retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, 1, + xfd->stream.para.socket.ip.res_opts[0], + xfd->stream.para.socket.ip.res_opts[1]) != + STAT_OK) { + /* pf is required during xioread checks */ + xfd->stream.para.socket.la.soa.sa_family = pf; + } + + xfd->stream.dtype = XIODATA_RECV_SKIPIP; + result = _xioopen_dgram_recv(&xfd->stream, xioflags, NULL/*&us.soa*/, uslen, + opts, pf, socktype, ipproto, E_ERROR); + _xio_openlate(&xfd->stream, opts); + return result; +} + +#endif /* (WITH_IP4 || WITH_IP6) && WITH_RAWIP */ diff --git a/xio-rawip.h b/xio-rawip.h new file mode 100644 index 0000000..0c57a02 --- /dev/null +++ b/xio-rawip.h @@ -0,0 +1,21 @@ +/* $Id: xio-rawip.h,v 1.13 2007/02/05 19:56:34 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_rawip_h_included +#define __xio_rawip_h_included 1 + +extern const struct addrdesc addr_rawip_sendto; +extern const struct addrdesc addr_rawip_datagram; +extern const struct addrdesc addr_rawip_recvfrom; +extern const struct addrdesc addr_rawip_recv; +extern const struct addrdesc addr_rawip4_sendto; +extern const struct addrdesc addr_rawip4_datagram; +extern const struct addrdesc addr_rawip4_recvfrom; +extern const struct addrdesc addr_rawip4_recv; +extern const struct addrdesc addr_rawip6_sendto; +extern const struct addrdesc addr_rawip6_datagram; +extern const struct addrdesc addr_rawip6_recvfrom; +extern const struct addrdesc addr_rawip6_recv; + +#endif /* !defined(__xio_rawip_h_included) */ diff --git a/xio-readline.c b/xio-readline.c new file mode 100644 index 0000000..584543f --- /dev/null +++ b/xio-readline.c @@ -0,0 +1,244 @@ +/* $Id: xio-readline.c,v 1.17 2007/01/25 21:36:11 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2002-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for opening the readline address */ + +#include "xiosysincludes.h" +#include "xioopen.h" + +#include "xio-termios.h" +#include "xio-readline.h" + + +#if WITH_READLINE + +/* +options: history file + prompt + mode=vi? + inputrc=? + +uses stdin!! +*/ + +/* length of buffer for dynamic prompt */ +#define READLINE_MAXPROMPT 512 + +static int xioopen_readline(int argc, const char *argv[], struct opt *opts, + int rw, xiofile_t *xfd, unsigned groups, + int dummy1, int dummy2, int dummy3); + + +const struct addrdesc addr_readline = { + "readline", 3, xioopen_readline, GROUP_FD|GROUP_TERMIOS|GROUP_READLINE, 0, 0, 0 HELP(NULL) }; + +const struct optdesc opt_history_file = { "history-file", "history", OPT_HISTORY_FILE, GROUP_READLINE, PH_LATE, TYPE_STRING, OFUNC_OFFSET, (int)&((xiofile_t *)0)->stream.para.readline.history_file }; +const struct optdesc opt_prompt = { "prompt", NULL, OPT_PROMPT, GROUP_READLINE, PH_LATE, TYPE_STRING, OFUNC_OFFSET, (int)&((xiofile_t *)0)->stream.para.readline.prompt }; +const struct optdesc opt_noprompt = { "noprompt", NULL, OPT_NOPROMPT, GROUP_READLINE, PH_LATE, TYPE_BOOL, OFUNC_SPEC, 0 }; +const struct optdesc opt_noecho = { "noecho", NULL, OPT_NOECHO, GROUP_READLINE, PH_LATE, TYPE_STRING, OFUNC_SPEC, 0 }; + +static int xioopen_readline(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xfd, unsigned groups, + int dummy1, int dummy2, int dummy3) { + int rw = (xioflags & XIO_ACCMODE); + char msgbuf[256], *cp = msgbuf; + bool noprompt = false; + char *noecho = NULL; + + if (argc != 1) { + Error1("%s: 0 parameters required", argv[0]); + return STAT_NORETRY; + } + + if (!(xioflags & XIO_MAYCONVERT)) { + Error("address with data processing not allowed here"); + return STAT_NORETRY; + } + xfd->common.flags |= XIO_DOESCONVERT; + + strcpy(cp, "using "); cp = strchr(cp, '\0'); + if ((rw+1)&1) { + strcpy(cp, "readline on stdin for reading"); cp = strchr(cp, '\0'); + + if ((rw+1)&2) + strcpy(cp, " and "); cp = strchr(cp, '\0'); + } + if ((rw+1)&2) { + strcpy(cp, "stdio for writing"); cp = strchr(cp, '\0'); + } + Notice(msgbuf); + + xfd->stream.fd = 0; /* stdin */ + xfd->stream.howtoend = END_NONE; + xfd->stream.dtype = XIODATA_READLINE; + +#if WITH_TERMIOS + if (Isatty(xfd->stream.fd)) { + if (Tcgetattr(xfd->stream.fd, &xfd->stream.savetty) < 0) { + Warn2("cannot query current terminal settings on fd %d. %s", + xfd->stream.fd, strerror(errno)); + } else { + xfd->stream.ttyvalid = true; + } + } +#endif /* WITH_TERMIOS */ + + if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1; + applyopts(-1, opts, PH_INIT); + + applyopts2(xfd->stream.fd, opts, PH_INIT, PH_FD); + + Using_history(); + applyopts_offset(&xfd->stream, opts); + retropt_bool(opts, OPT_NOPROMPT, &noprompt); + if (!noprompt && !xfd->stream.para.readline.prompt) { + xfd->stream.para.readline.dynbytes = READLINE_MAXPROMPT; + xfd->stream.para.readline.dynprompt = + Malloc(xfd->stream.para.readline.dynbytes+1); + xfd->stream.para.readline.dynend = + xfd->stream.para.readline.dynprompt; + } + +#if HAVE_REGEX_H + retropt_string(opts, OPT_NOECHO, &noecho); + if (noecho) { + int errcode; + char errbuf[128]; + if ((errcode = regcomp(&xfd->stream.para.readline.noecho, noecho, + REG_EXTENDED|REG_NOSUB)) + != 0) { + regerror(errcode, &xfd->stream.para.readline.noecho, + errbuf, sizeof(errbuf)); + Error3("regcomp(%p, \"%s\", REG_EXTENDED|REG_NOSUB): %s", + &xfd->stream.para.readline.noecho, noecho, errbuf); + return -1; + } + xfd->stream.para.readline.hasnoecho = true; + } +#endif /* HAVE_REGEX_H */ + if (xfd->stream.para.readline.history_file) { + Read_history(xfd->stream.para.readline.history_file); + } + xiotermios_clrflag(xfd->stream.fd, 3, ICANON); + xiotermios_clrflag(xfd->stream.fd, 3, ECHO); + return _xio_openlate(&xfd->stream, opts); +} + + +ssize_t xioread_readline(struct single *pipe, void *buff, size_t bufsiz) { + /*! indent */ + ssize_t bytes; + char *line; + int _errno; + +#if HAVE_REGEX_H + if (pipe->para.readline.dynprompt && + pipe->para.readline.hasnoecho && + !regexec(&pipe->para.readline.noecho, + pipe->para.readline.dynprompt, 0, NULL, 0)) { + /* under these conditions, we do not echo input, thus we circumvent + readline */ + struct termios saveterm, setterm; + *pipe->para.readline.dynend = '\0'; + Tcgetattr(pipe->fd, &saveterm); /*! error */ + setterm = saveterm; + setterm.c_lflag |= ICANON; + Tcsetattr(pipe->fd, TCSANOW, &setterm); /*!*/ + do { + bytes = Read(pipe->fd, buff, bufsiz); + } while (bytes < 0 && errno == EINTR); + if (bytes < 0) { + _errno = errno; + Error4("read(%d, %p, "F_Zu"): %s", + pipe->fd, buff, bufsiz, strerror(_errno)); + errno = _errno; + return -1; + } + setterm.c_lflag &= ~ICANON; + Tcgetattr(pipe->fd, &setterm); /*! error */ + Tcsetattr(pipe->fd, TCSANOW, &saveterm); /*!*/ + pipe->para.readline.dynend = pipe->para.readline.dynprompt; + /*Write(pipe->fd, "\n", 1);*/ /*!*/ + return bytes; + } +#endif /* HAVE_REGEX_H */ + + xiotermios_setflag(pipe->fd, 3, ECHO); + if (pipe->para.readline.prompt || pipe->para.readline.dynprompt) { + /* we must carriage return, because readline will first print the + prompt */ + ssize_t writt; + do { + writt = Write(pipe->fd, "\r", 1); + } while (writt < 0 && errno == EINTR); + if (writt < 0) { + Warn2("write(%d, \"\\r\", 1): %s", + pipe->fd, strerror(errno)); + } else if (writt < 1) { + Warn1("write() only wrote "F_Zu" of 1 byte", writt); + } + } + + if (pipe->para.readline.dynprompt) { + *pipe->para.readline.dynend = '\0'; + line = Readline(pipe->para.readline.dynprompt); + pipe->para.readline.dynend = pipe->para.readline.dynprompt; + } else { + line = Readline(pipe->para.readline.prompt); + } + /* GNU readline defines no error return */ + if (line == NULL) { + return 0; /* EOF */ + } + xiotermios_clrflag(pipe->fd, 3, ECHO); + Add_history(line); + bytes = strlen(line); + strncpy(buff, line, bufsiz); + free(line); + if ((size_t)bytes < bufsiz) { + strcat(buff, "\n"); ++bytes; + } + return bytes; +} + +void xioscan_readline(struct single *pipe, const void *buff, size_t bytes) { + if (pipe->dtype == XIODATA_READLINE && pipe->para.readline.dynprompt) { + /* we save the last part of the output as possible prompt */ + const void *ptr = buff; + const void *pcr = memrchr(buff, '\r', bytes); + const void *plf = memrchr(buff, '\n', bytes); + size_t len; + if (bytes > pipe->para.readline.dynbytes) { + ptr = (const char *)buff + bytes - pipe->para.readline.dynbytes; + } + if (pcr) { + /* forget old prompt */ + pipe->para.readline.dynend = pipe->para.readline.dynprompt; + /* new prompt starts here */ + ptr = (const char *)pcr+1; + } + if (plf && plf >= ptr) { + /* forget old prompt */ + pipe->para.readline.dynend = pipe->para.readline.dynprompt; + /* new prompt starts here */ + ptr = (const char *)plf+1; + } + len = (const char *)buff-(const char *)ptr+bytes; + if (pipe->para.readline.dynend - pipe->para.readline.dynprompt + len > + pipe->para.readline.dynbytes) { + memmove(pipe->para.readline.dynprompt, + pipe->para.readline.dynend - + (pipe->para.readline.dynbytes - len), + pipe->para.readline.dynbytes - len); + pipe->para.readline.dynend = + pipe->para.readline.dynprompt + pipe->para.readline.dynbytes - len; + } + memcpy(pipe->para.readline.dynend, ptr, len); + /*pipe->para.readline.dynend = pipe->para.readline.dynprompt + len;*/ + pipe->para.readline.dynend = pipe->para.readline.dynend + len; + } + return; +} + +#endif /* WITH_READLINE */ diff --git a/xio-readline.h b/xio-readline.h new file mode 100644 index 0000000..921d605 --- /dev/null +++ b/xio-readline.h @@ -0,0 +1,17 @@ +/* $Id: xio-readline.h,v 1.4 2003/12/23 21:38:59 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2002, 2003 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_readline_h_included +#define __xio_readline_h_included 1 + +extern const struct addrdesc addr_readline; + +extern const struct optdesc opt_history_file; +extern const struct optdesc opt_prompt; +extern const struct optdesc opt_noprompt; +extern const struct optdesc opt_noecho; + +extern ssize_t xioread_readline(struct single *pipe, void *buff, size_t bufsiz);extern void xioscan_readline(struct single *pipe, const void *buff, size_t bytes); + +#endif /* !defined(__xio_readline_h_included) */ diff --git a/xio-socket.c b/xio-socket.c new file mode 100644 index 0000000..c9b3d3e --- /dev/null +++ b/xio-socket.c @@ -0,0 +1,1091 @@ +/* $Id: xio-socket.c,v 1.45 2007/03/06 21:12:09 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for socket related functions */ + +#include "xiosysincludes.h" + +#if _WITH_SOCKET + +#include "xioopen.h" +#include "xio-socket.h" +#include "xio-named.h" +#if WITH_IP4 +#include "xio-ip4.h" +#endif /* WITH_IP4 */ +#if WITH_IP6 +#include "xio-ip6.h" +#endif /* WITH_IP6 */ +#include "xio-ip.h" +#include "xio-ipapp.h" /*! not clean */ +#include "xio-tcpwrap.h" + +const struct optdesc opt_so_debug = { "so-debug", "debug", OPT_SO_DEBUG, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_DEBUG }; +#ifdef SO_ACCEPTCONN /* AIX433 */ +const struct optdesc opt_so_acceptconn={ "so-acceptconn","acceptconn",OPT_SO_ACCEPTCONN,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_ACCEPTCONN}; +#endif /* SO_ACCEPTCONN */ +const struct optdesc opt_so_broadcast= { "so-broadcast", "broadcast", OPT_SO_BROADCAST,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_BROADCAST}; +const struct optdesc opt_so_reuseaddr= { "so-reuseaddr", "reuseaddr", OPT_SO_REUSEADDR,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_REUSEADDR}; +const struct optdesc opt_so_keepalive= { "so-keepalive", "keepalive", OPT_SO_KEEPALIVE,GROUP_SOCKET, PH_FD, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_KEEPALIVE}; +#if HAVE_STRUCT_LINGER +const struct optdesc opt_so_linger = { "so-linger", "linger", OPT_SO_LINGER, GROUP_SOCKET, PH_PASTSOCKET, TYPE_LINGER,OFUNC_SOCKOPT,SOL_SOCKET, SO_LINGER }; +#else /* !HAVE_STRUCT_LINGER */ +const struct optdesc opt_so_linger = { "so-linger", "linger", OPT_SO_LINGER, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_LINGER }; +#endif /* !HAVE_STRUCT_LINGER */ +const struct optdesc opt_so_oobinline= { "so-oobinline", "oobinline", OPT_SO_OOBINLINE,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_OOBINLINE}; +const struct optdesc opt_so_sndbuf = { "so-sndbuf", "sndbuf", OPT_SO_SNDBUF, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_SNDBUF}; +const struct optdesc opt_so_sndbuf_late={ "so-sndbuf-late","sndbuf-late",OPT_SO_SNDBUF_LATE,GROUP_SOCKET,PH_LATE,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_SNDBUF }; +const struct optdesc opt_so_rcvbuf = { "so-rcvbuf", "rcvbuf", OPT_SO_RCVBUF, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_RCVBUF}; +const struct optdesc opt_so_rcvbuf_late={"so-rcvbuf-late","rcvbuf-late",OPT_SO_RCVBUF_LATE,GROUP_SOCKET,PH_LATE,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_RCVBUF }; +const struct optdesc opt_so_error = { "so-error", "error", OPT_SO_ERROR, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_ERROR}; +const struct optdesc opt_so_type = { "so-type", "type", OPT_SO_TYPE, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_TYPE }; +const struct optdesc opt_so_dontroute= { "so-dontroute", "dontroute", OPT_SO_DONTROUTE,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_DONTROUTE }; +#ifdef SO_RCVLOWAT +const struct optdesc opt_so_rcvlowat = { "so-rcvlowat", "rcvlowat", OPT_SO_RCVLOWAT, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_RCVLOWAT }; +#endif +#ifdef SO_RCVTIMEO +const struct optdesc opt_so_rcvtimeo = { "so-rcvtimeo", "rcvtimeo", OPT_SO_RCVTIMEO, GROUP_SOCKET, PH_PASTSOCKET, TYPE_TIMEVAL,OFUNC_SOCKOPT,SOL_SOCKET,SO_RCVTIMEO }; +#endif +#ifdef SO_SNDLOWAT +const struct optdesc opt_so_sndlowat = { "so-sndlowat", "sndlowat", OPT_SO_SNDLOWAT, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_SNDLOWAT }; +#endif +#ifdef SO_SNDTIMEO +const struct optdesc opt_so_sndtimeo = { "so-sndtimeo", "sndtimeo", OPT_SO_SNDTIMEO, GROUP_SOCKET, PH_PASTSOCKET, TYPE_TIMEVAL,OFUNC_SOCKOPT,SOL_SOCKET,SO_SNDTIMEO }; +#endif +/* end of setsockopt options of UNIX98 standard */ + +#ifdef SO_AUDIT /* AIX 4.3.3 */ +const struct optdesc opt_so_audit = { "so-audit", "audit", OPT_SO_AUDIT, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_AUDIT }; +#endif /* SO_AUDIT */ +#ifdef SO_ATTACH_FILTER +const struct optdesc opt_so_attach_filter={"so-attach-filter","attachfilter",OPT_SO_ATTACH_FILTER,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_ATTACH_FILTER}; +#endif +#ifdef SO_DETACH_FILTER +const struct optdesc opt_so_detach_filter={"so-detach-filter","detachfilter",OPT_SO_DETACH_FILTER,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_DETACH_FILTER}; +#endif +#ifdef SO_BINDTODEVICE /* Linux: man 7 socket */ +const struct optdesc opt_so_bindtodevice={"so-bindtodevice","if",OPT_SO_BINDTODEVICE,GROUP_SOCKET,PH_PASTSOCKET,TYPE_NAME,OFUNC_SOCKOPT,SOL_SOCKET,SO_BINDTODEVICE}; +#endif +#ifdef SO_BSDCOMPAT +const struct optdesc opt_so_bsdcompat= { "so-bsdcompat","bsdcompat",OPT_SO_BSDCOMPAT,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_BSDCOMPAT }; +#endif +#ifdef SO_CKSUMRECV +const struct optdesc opt_so_cksumrecv= { "so-cksumrecv","cksumrecv",OPT_SO_CKSUMRECV,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_CKSUMRECV }; +#endif /* SO_CKSUMRECV */ +#ifdef SO_KERNACCEPT /* AIX 4.3.3 */ +const struct optdesc opt_so_kernaccept={ "so-kernaccept","kernaccept",OPT_SO_KERNACCEPT,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_KERNACCEPT}; +#endif /* SO_KERNACCEPT */ +#ifdef SO_NO_CHECK +const struct optdesc opt_so_no_check = { "so-no-check", "nocheck",OPT_SO_NO_CHECK, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_NO_CHECK }; +#endif +#ifdef SO_NOREUSEADDR /* AIX 4.3.3 */ +const struct optdesc opt_so_noreuseaddr={"so-noreuseaddr","noreuseaddr",OPT_SO_NOREUSEADDR,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET, SO_NOREUSEADDR}; +#endif /* SO_NOREUSEADDR */ +#ifdef SO_PASSCRED +const struct optdesc opt_so_passcred = { "so-passcred", "passcred", OPT_SO_PASSCRED, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_PASSCRED}; +#endif +#ifdef SO_PEERCRED +const struct optdesc opt_so_peercred = { "so-peercred", "peercred", OPT_SO_PEERCRED, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT3,OFUNC_SOCKOPT, SOL_SOCKET, SO_PEERCRED}; +#endif +#ifdef SO_PRIORITY +const struct optdesc opt_so_priority = { "so-priority", "priority", OPT_SO_PRIORITY, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_PRIORITY}; +#endif +#ifdef SO_REUSEPORT /* AIX 4.3.3, BSD, HP-UX */ +const struct optdesc opt_so_reuseport= { "so-reuseport","reuseport",OPT_SO_REUSEPORT,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_REUSEPORT }; +#endif /* defined(SO_REUSEPORT) */ +#ifdef SO_SECURITY_AUTHENTICATION +const struct optdesc opt_so_security_authentication={"so-security-authentication","securityauthentication",OPT_SO_SECURITY_AUTHENTICATION,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_SECURITY_AUTHENTICATION}; +#endif +#ifdef SO_SECURITY_ENCRYPTION_NETWORK +const struct optdesc opt_so_security_encryption_network={"so-security-encryption-network","securityencryptionnetwork",OPT_SO_SECURITY_ENCRYPTION_NETWORK,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_SECURITY_ENCRYPTION_NETWORK}; +#endif +#ifdef SO_SECURITY_ENCRYPTION_TRANSPORT +const struct optdesc opt_so_security_encryption_transport={"so-security-encryption-transport","securityencryptiontransport",OPT_SO_SECURITY_ENCRYPTION_TRANSPORT,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_SECURITY_ENCRYPTION_TRANSPORT}; +#endif +#ifdef SO_USE_IFBUFS +const struct optdesc opt_so_use_ifbufs={ "so-use-ifbufs","useifbufs",OPT_SO_USE_IFBUFS,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_USE_IFBUFS}; +#endif /* SO_USE_IFBUFS */ +#ifdef SO_USELOOPBACK /* AIX433, Solaris, HP-UX */ +const struct optdesc opt_so_useloopback={"so-useloopback","useloopback",OPT_SO_USELOOPBACK,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT, SOL_SOCKET, SO_USELOOPBACK}; +#endif /* SO_USELOOPBACK */ +#ifdef SO_DGRAM_ERRIND /* Solaris */ +const struct optdesc opt_so_dgram_errind={"so-dgram-errind","dgramerrind",OPT_SO_DGRAM_ERRIND,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_DGRAM_ERRIND}; +#endif /* SO_DGRAM_ERRIND */ +#ifdef SO_DONTLINGER /* Solaris */ +const struct optdesc opt_so_dontlinger = {"so-dontlinger", "dontlinger", OPT_SO_DONTLINGER, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_DONTLINGER }; +#endif +#ifdef SO_PROTOTYPE /* Solaris, HP-UX */ +const struct optdesc opt_so_prototype = {"so-prototype", "prototype", OPT_SO_PROTOTYPE, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_PROTOTYPE }; +#endif +#ifdef FIOSETOWN +const struct optdesc opt_fiosetown = { "fiosetown", NULL, OPT_FIOSETOWN, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_IOCTL, FIOSETOWN }; +#endif +#ifdef SIOCSPGRP +const struct optdesc opt_siocspgrp = { "siocspgrp", NULL, OPT_SIOCSPGRP, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_IOCTL, SIOCSPGRP }; +#endif +const struct optdesc opt_bind = { "bind", NULL, OPT_BIND, GROUP_SOCKET, PH_BIND, TYPE_STRING,OFUNC_SPEC }; +const struct optdesc opt_connect_timeout = { "connect-timeout", NULL, OPT_CONNECT_TIMEOUT, GROUP_SOCKET, PH_PASTSOCKET, TYPE_TIMEVAL, OFUNC_OFFSET, (int)&((xiofile_t *)0)->stream.para.socket.connect_timeout }; +const struct optdesc opt_protocol_family = { "protocol-family", "pf", OPT_PROTOCOL_FAMILY, GROUP_SOCKET, PH_PRESOCKET, TYPE_STRING, OFUNC_SPEC }; + +/* a subroutine that is common to all socket addresses that want to connect + to a peer address. + might fork. + returns 0 on success. +*/ +int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen, + struct sockaddr *them, size_t themlen, + struct opt *opts, int pf, int stype, int proto, + bool alt, int level) { + int fcntl_flags = 0; + char infobuff[256]; + union sockaddr_union la; + socklen_t lalen = themlen; + int _errno; + int result; + + if ((xfd->fd = Socket(pf, stype, proto)) < 0) { + Msg4(level, + "socket(%d, %d, %d): %s", pf, stype, proto, strerror(errno)); + return STAT_RETRYLATER; + } + + applyopts_offset(xfd, opts); + applyopts(xfd->fd, opts, PH_PASTSOCKET); + applyopts(xfd->fd, opts, PH_FD); + + applyopts_cloexec(xfd->fd, opts); + + applyopts(xfd->fd, opts, PH_PREBIND); + applyopts(xfd->fd, opts, PH_BIND); +#if WITH_TCP || WITH_UDP + if (alt) { + union sockaddr_union sin, *sinp; + unsigned short *port, i, N; + div_t dv; + bool problem; + + /* prepare sockaddr for bind probing */ + if (us) { + sinp = (union sockaddr_union *)us; + } else { + if (them->sa_family == AF_INET) { + socket_in_init(&sin.ip4); +#if WITH_IP6 + } else { + socket_in6_init(&sin.ip6); +#endif + } + sinp = &sin; + } + if (them->sa_family == AF_INET) { + port = &sin.ip4.sin_port; +#if WITH_IP6 + } else if (them->sa_family == AF_INET6) { + port = &sin.ip6.sin6_port; +#endif + } else { + port = 0; /* just to make compiler happy */ + } + /* combine random+step variant to quickly find a free port when only + few are in use, and certainly find a free port in defined time even + if there are almost all in use */ + /* dirt 1: having tcp/udp code in socket function */ + /* dirt 2: using a time related system call for init of random */ + { + /* generate a random port, with millisecond random init */ +#if 0 + struct timeb tb; + ftime(&tb); + srandom(tb.time*1000+tb.millitm); +#else + struct timeval tv; + struct timezone tz; + tz.tz_minuteswest = 0; + tz.tz_dsttime = 0; + if ((result = Gettimeofday(&tv, &tz)) < 0) { + Warn2("gettimeofday(%p, {0,0}): %s", &tv, strerror(errno)); + } + srandom(tv.tv_sec*1000000+tv.tv_usec); +#endif + } + dv = div(random(), IPPORT_RESERVED-XIO_IPPORT_LOWER); + i = N = XIO_IPPORT_LOWER + dv.rem; + problem = false; + do { /* loop over lowport bind() attempts */ + *port = htons(i); + if (Bind(xfd->fd, (struct sockaddr *)sinp, sizeof(*sinp)) < 0) { + Msg4(errno==EADDRINUSE?E_INFO:level, + "bind(%d, {%s}, "F_Zd"): %s", xfd->fd, + sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)), + sizeof(*sinp), strerror(errno)); + if (errno != EADDRINUSE) { + Close(xfd->fd); + return STAT_RETRYLATER; + } + } else { + break; /* could bind to port, good, continue past loop */ + } + --i; if (i < XIO_IPPORT_LOWER) i = IPPORT_RESERVED-1; + if (i == N) { + Msg(level, "no low port available"); + /*errno = EADDRINUSE; still assigned */ + Close(xfd->fd); + return STAT_RETRYLATER; + } + } while (i != N); + } else +#endif /* WITH_TCP || WITH_UDP */ + + if (us) { + if (Bind(xfd->fd, us, uslen) < 0) { + Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", + xfd->fd, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), + uslen, strerror(errno)); + Close(xfd->fd); + return STAT_RETRYLATER; + } + } + + applyopts(xfd->fd, opts, PH_PASTBIND); + + applyopts(xfd->fd, opts, PH_CONNECT); + + if (xfd->para.socket.connect_timeout.tv_sec != 0 || + xfd->para.socket.connect_timeout.tv_usec != 0) { + fcntl_flags = Fcntl(xfd->fd, F_GETFL); + Fcntl_l(xfd->fd, F_SETFL, fcntl_flags|O_NONBLOCK); + } + + result = Connect(xfd->fd, (struct sockaddr *)them, themlen); + _errno = errno; + la.soa.sa_family = them->sa_family; lalen = sizeof(la); + if (Getsockname(xfd->fd, &la.soa, &lalen) < 0) { + Msg4(level-1, "getsockname(%d, %p, {%d}): %s", + xfd->fd, &la.soa, lalen, strerror(errno)); + } + errno = _errno; + if (result < 0) { + if (errno == EINPROGRESS) { + if (xfd->para.socket.connect_timeout.tv_sec != 0 || + xfd->para.socket.connect_timeout.tv_usec != 0) { + struct timeval timeout; + fd_set readfds, writefds, exceptfds; + int result; + Info4("connect(%d, %s, "F_Zd"): %s", + xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), + themlen, strerror(errno)); + timeout = xfd->para.socket.connect_timeout; + FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); + FD_SET(xfd->fd, &readfds); FD_SET(xfd->fd, &writefds); + result = + Select(xfd->fd+1, &readfds, &writefds, &exceptfds, &timeout); + if (result < 0) { + Msg2(level, "select(%d,,,,): %s", xfd->fd+1, strerror(errno)); + return STAT_RETRYLATER; + } + if (result == 0) { + Msg2(level, "connecting to %s: %s", + sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), + strerror(ETIMEDOUT)); + return STAT_RETRYLATER; + } + if (FD_ISSET(xfd->fd, &readfds)) { +#if 0 + unsigned char dummy[1]; + Read(xfd->fd, &dummy, 1); /* get error message */ + Msg2(level, "connecting to %s: %s", + sockaddr_info(them, infobuff, sizeof(infobuff)), + strerror(errno)); +#else + Connect(xfd->fd, them, themlen); /* get error message */ + Msg4(level, "connect(%d, %s, "F_Zd"): %s", + xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), + themlen, strerror(errno)); +#endif + return STAT_RETRYLATER; + } + /* otherwise OK */ + Fcntl_l(xfd->fd, F_SETFL, fcntl_flags); + } else { + Warn4("connect(%d, %s, "F_Zd"): %s", + xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), + themlen, strerror(errno)); + } + } else if (pf == PF_UNIX && errno == EPROTOTYPE) { + /* this is for UNIX domain sockets: a connect attempt seems to be + the only way to distinguish stream and datagram sockets */ + int _errno = errno; + Info4("connect(%d, %s, "F_Zd"): %s", + xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), + themlen, strerror(errno)); +#if 0 + Info("assuming datagram socket"); + xfd->dtype = DATA_RECVFROM; + xfd->salen = themlen; + memcpy(&xfd->peersa.soa, them, xfd->salen); +#endif + /*!!! and remove bind socket */ + Close(xfd->fd); xfd->fd = -1; + errno = _errno; + return -1; + } else { + Msg4(level, "connect(%d, %s, "F_Zd"): %s", + xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), + themlen, strerror(errno)); + Close(xfd->fd); + return STAT_RETRYLATER; + } + } + + applyopts_fchown(xfd->fd, opts); + applyopts(xfd->fd, opts, PH_CONNECTED); + applyopts(xfd->fd, opts, PH_LATE); + + Notice1("successfully connected from local address %s", + sockaddr_info(&la.soa, themlen, infobuff, sizeof(infobuff))); + + return STAT_OK; +} + + +/* a subroutine that is common to all socket addresses that want to connect + to a peer address. + might fork. + returns 0 on success. +*/ +int xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen, + struct sockaddr *them, size_t themlen, + struct opt *opts, int pf, int stype, int proto, + bool alt) { + bool dofork = false; + struct opt *opts0; + char infobuff[256]; + int level; + int result; + + retropt_bool(opts, OPT_FORK, &dofork); + retropt_int(opts, OPT_SO_TYPE, &stype); + + opts0 = copyopts(opts, GROUP_ALL); + + Notice1("opening connection to %s", + sockaddr_info(them, themlen, infobuff, sizeof(infobuff))); + + do { /* loop over retries and forks */ + +#if WITH_RETRY + if (xfd->forever || xfd->retry) { + level = E_INFO; + } else +#endif /* WITH_RETRY */ + level = E_ERROR; + result = + _xioopen_connect(xfd, us, uslen, them, themlen, opts, + pf, stype, proto, alt, level); + switch (result) { + case STAT_OK: break; +#if WITH_RETRY + case STAT_RETRYLATER: + if (xfd->forever || xfd->retry) { + --xfd->retry; + if (result == STAT_RETRYLATER) { + Nanosleep(&xfd->intervall, NULL); + } + dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); + continue; + } + return STAT_NORETRY; +#endif /* WITH_RETRY */ + default: + return result; + } + +#if WITH_RETRY + if (dofork) { + pid_t pid; + while ((pid = Fork()) < 0) { + int level = E_ERROR; + if (xfd->forever || --xfd->retry) { + level = E_WARN; /* most users won't expect a problem here, + so Notice is too weak */ + } + Msg1(level, "fork(): %s", strerror(errno)); + if (xfd->forever || xfd->retry) { + dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); + Nanosleep(&xfd->intervall, NULL); continue; + } + return STAT_RETRYLATER; + } + if (pid == 0) { /* child process */ + Info1("just born: TCP client process "F_pid, Getpid()); + + /* drop parents locks, reset FIPS... */ + if (xio_forked_inchild() != 0) { + Exit(1); + } + break; + } + /* parent process */ + Notice1("forked off child process "F_pid, pid); + Close(xfd->fd); + /* with and without retry */ + Nanosleep(&xfd->intervall, NULL); + dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); + continue; /* with next socket() bind() connect() */ + } else +#endif /* WITH_RETRY */ + { + break; + } +#if 0 + if ((result = _xio_openlate(fd, opts)) < 0) + return result; +#endif + } while (true); + + return 0; +} + + +/* common to xioopen_udp_sendto, ..unix_sendto, ..rawip */ +int _xioopen_dgram_sendto(/* them is already in xfd->peersa */ + union sockaddr_union *us, socklen_t uslen, + struct opt *opts, + int xioflags, xiosingle_t *xfd, unsigned groups, + int pf, int socktype, int ipproto) { + int level = E_ERROR; + union sockaddr_union la; socklen_t lalen = sizeof(la); + char infobuff[256]; + + if ((xfd->fd = Socket(pf, socktype, ipproto)) < 0) { + Msg4(level, + "socket(%d, %d, %d): %s", pf, socktype, ipproto, strerror(errno)); + return STAT_RETRYLATER; + } + + applyopts_offset(xfd, opts); + applyopts_single(xfd, opts, PH_PASTSOCKET); + applyopts(xfd->fd, opts, PH_PASTSOCKET); + applyopts(xfd->fd, opts, PH_FD); + + applyopts_cloexec(xfd->fd, opts); + + applyopts(xfd->fd, opts, PH_PREBIND); + applyopts(xfd->fd, opts, PH_BIND); + + if (us) { + if (Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) { + Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", + xfd->fd, sockaddr_info((struct sockaddr *)us, uslen, infobuff, sizeof(infobuff)), + uslen, strerror(errno)); + Close(xfd->fd); + return STAT_RETRYLATER; + } + } + + applyopts(xfd->fd, opts, PH_PASTBIND); + + /*applyopts(xfd->fd, opts, PH_CONNECT);*/ + + if (Getsockname(xfd->fd, &la.soa, &lalen) < 0) { + Warn4("getsockname(%d, %p, {%d}): %s", + xfd->fd, &la.soa, lalen, strerror(errno)); + } + + applyopts_fchown(xfd->fd, opts); + applyopts(xfd->fd, opts, PH_CONNECTED); + applyopts(xfd->fd, opts, PH_LATE); + + /* xfd->dtype = DATA_RECVFROM; *//* no, the caller must set this (ev _SKIPIP) */ + Notice1("successfully prepared local socket %s", + sockaddr_info(&la.soa, lalen, infobuff, sizeof(infobuff))); + + return STAT_OK; +} + + +static pid_t xio_waitingfor; +static bool xio_hashappened; +void xiosigaction_hasread(int signum, siginfo_t *siginfo, void *ucontext) { + Debug5("xiosigaction_hasread(%d, {%d,%d,%d,"F_pid"}, )", + signum, siginfo->si_signo, siginfo->si_errno, siginfo->si_code, + siginfo->si_pid); + if (xio_waitingfor == siginfo->si_pid) { + xio_hashappened = true; + } + Debug("xiosigaction_hasread() ->"); + return; +} + + +/* waits for incoming packet, checks its source address and port. Depending + on fork option, it may fork a subprocess. + Returns STAT_OK if a the packet was accepted; with fork option, this is already in + a new subprocess! + Other return values indicate a problem; this can happen in the master + process or in a subprocess. + This function does not retry. If you need retries, handle this is a + loop in the calling function. + after fork, we set the forever/retry of the child process to 0 + */ +int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags, + struct sockaddr *us, socklen_t uslen, + struct opt *opts, + int pf, int socktype, int proto, int level) { + char *rangename; + socklen_t salen; + bool dofork = false; + pid_t pid; /* mostly int; only used with fork */ + char infobuff[256]; + char lisname[256]; + bool drop = false; /* true if current packet must be dropped */ + int result; + + retropt_bool(opts, OPT_FORK, &dofork); + + if (dofork) { + if (!(xioflags & XIO_MAYFORK)) { + Error("option fork not allowed here"); + return STAT_NORETRY; + } + xfd->flags |= XIO_DOESFORK; + } + + if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY; + +#if 1 + if (dofork) { +#if HAVE_SIGACTION + struct sigaction act; + memset(&act, 0, sizeof(struct sigaction)); + act.sa_flags = SA_NOCLDSTOP|SA_RESTART +#ifdef SA_NOMASK + |SA_NOMASK +#endif + ; + act.sa_handler = childdied; + if (Sigaction(SIGCHLD, &act, NULL) < 0) { + /*! man does not say that errno is defined */ + Warn2("sigaction(SIGCHLD, %p, NULL): %s", childdied, strerror(errno)); + } +#else /* HAVE_SIGACTION */ + if (Signal(SIGCHLD, childdied) == SIG_ERR) { + Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno)); + } +#endif /* !HAVE_SIGACTION */ + } +#endif /* 1 */ + + if ((xfd->fd = Socket(pf, socktype, proto)) < 0) { + Msg4(level, + "socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno)); + return STAT_RETRYLATER; + } + + applyopts_single(xfd, opts, PH_PASTSOCKET); + applyopts(xfd->fd, opts, PH_PASTSOCKET); + + applyopts_cloexec(xfd->fd, opts); + + applyopts(xfd->fd, opts, PH_PREBIND); + applyopts(xfd->fd, opts, PH_BIND); + if ((us != NULL) && Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) { + Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd, + sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen, + strerror(errno)); + Close(xfd->fd); + return STAT_RETRYLATER; + } + +#if WITH_UNIX + if (pf == AF_UNIX && us != NULL) { + applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD); + } +#endif + + applyopts(xfd->fd, opts, PH_PASTBIND); +#if WITH_UNIX + if (pf == AF_UNIX && us != NULL) { + /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/ + applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_EARLY); + applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_PREOPEN); + } +#endif /* WITH_UNIX */ + +#if WITH_IP4 /*|| WITH_IP6*/ + if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { + if (parserange(rangename, pf, &xfd->para.socket.range) + < 0) { + free(rangename); + return STAT_NORETRY; + } + free(rangename); + xfd->para.socket.dorange = true; + } +#endif + +#if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP + xio_retropt_tcpwrap(xfd, opts); +#endif /* && (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */ + + if (xioopts.logopt == 'm') { + Info("starting recvfrom loop, switching to syslog"); + diag_set('y', xioopts.syslogfac); xioopts.logopt = 'y'; + } else { + Info("starting recvfrom loop"); + } + + if (dofork) { +#if HAVE_SIGACTION + { + struct sigaction act; + memset(&act, 0, sizeof(struct sigaction)); + act.sa_flags = SA_NOCLDSTOP|SA_RESTART +#ifdef SA_SIGINFO /* not on Linux 2.0(.33) */ + |SA_SIGINFO +#endif +#ifdef SA_NOMASK + |SA_NOMASK +#endif + ; +#if 1 || HAVE_SIGACTION_SASIGACTION + act.sa_sigaction = xiosigaction_hasread; +#else /* Linux 2.0(.33) does not have sigaction.sa_sigaction */ + act.sa_handler = xiosighandler_hasread; +#endif + if (Sigaction(SIGUSR1, &act, NULL) < 0) { + /*! Linux man does not explicitely say that errno is defined */ + Warn1("sigaction(SIGUSR1, {&xiosigaction_subaddr_ok}, NULL): %s", strerror(errno)); + } + if (Sigaction(SIGCHLD, &act, NULL) < 0) { + /*! Linux man does not explicitely say that errno is defined */ + Warn1("sigaction(SIGCHLD, {&xiosigaction_subaddr_ok}, NULL): %s", strerror(errno)); + } + } +#else /* !HAVE_SIGACTION */ + /*!!!*/ + if (Signal(SIGUSR1, xiosigaction_hasread) == SIG_ERR) { + Warn1("signal(SIGUSR1, xiosigaction_hasread): %s", strerror(errno)); + } + if (Signal(SIGCHLD, xiosigaction_hasread) == SIG_ERR) { + Warn1("signal(SIGCHLD, xiosigaction_hasread): %s", strerror(errno)); + } +#endif /* !HAVE_SIGACTION */ + } + + while (true) { /* but we only loop if fork option is set */ + char peername[256]; + union sockaddr_union _peername; + union sockaddr_union _sockname; + union sockaddr_union *pa = &_peername; /* peer address */ + union sockaddr_union *la = &_sockname; /* local address */ + socklen_t palen = sizeof(_peername); /* peer address size */ + + socket_init(pf, pa); + salen = sizeof(struct sockaddr); + + if (drop) { + char *dummy[2]; + + Recv(xfd->fd, dummy, sizeof(dummy), 0); + drop = true; + } + + /* loop until select() returns valid */ + do { + fd_set in, out, expt; + /*? int level = E_ERROR;*/ + if (us != NULL) { + Notice1("receiving on %s", sockaddr_info(us, uslen, lisname, sizeof(lisname))); + } else { + Notice1("receiving IP protocol %u", proto); + } + FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt); + FD_SET(xfd->fd, &in); + if (Select(xfd->fd+1, &in, &out, &expt, NULL) > 0) { + break; + } + + if (errno == EINTR) { + continue; + } + + Msg2(level, "select(, {%d}): %s", xfd->fd, strerror(errno)); + Close(xfd->fd); + return STAT_RETRYLATER; + } while (true); + + if (xiogetpacketsrc(xfd->fd, pa, &palen) < 0) { + return STAT_RETRYLATER; + } + + Notice1("receiving packet from %s"/*"src"*/, + sockaddr_info((struct sockaddr *)pa, palen, peername, sizeof(peername))/*, + sockaddr_info(&la->soa, sockname, sizeof(sockname))*/); + + if (xiocheckpeer(xfd, pa, la) < 0) { + /* drop packet */ + char buff[512]; + Recv(xfd->fd, buff, sizeof(buff), 0); + continue; + } + Info1("permitting packet from %s", + sockaddr_info((struct sockaddr *)pa, palen, + infobuff, sizeof(infobuff))); + + applyopts(xfd->fd, opts, PH_FD); + + applyopts(xfd->fd, opts, PH_CONNECTED); + + xfd->peersa = *(union sockaddr_union *)pa; + xfd->salen = palen; + + if (dofork) { + sigset_t mask_sigchldusr1; + const char *forkwaitstring; + int forkwaitsecs = 0; + + /* we must prevent that the current packet triggers another fork; + therefore we wait for a signal from the recent child: USR1 + indicates that is has consumed the last packet; CHLD means it has + terminated */ + /* block SIGCHLD and SIGUSR1 until parent is ready to react */ + sigemptyset(&mask_sigchldusr1); + sigaddset(&mask_sigchldusr1, SIGCHLD); + sigaddset(&mask_sigchldusr1, SIGUSR1); + Sigprocmask(SIG_BLOCK, &mask_sigchldusr1, NULL); + + if ((pid = Fork()) < 0) { + Msg1(level, "fork(): %s", strerror(errno)); + Close(xfd->fd); + Sigprocmask(SIG_UNBLOCK, &mask_sigchldusr1, NULL); + return STAT_RETRYLATER; + } + /* gdb recommends to have env controlled sleep after fork */ + if (forkwaitstring = getenv("SOCAT_FORK_WAIT")) { + forkwaitsecs = atoi(forkwaitstring); + Sleep(forkwaitsecs); + } + + if (pid == 0) { /* child */ + /* no reason to block SIGCHLD in child process */ + Sigprocmask(SIG_UNBLOCK, &mask_sigchldusr1, NULL); + xfd->ppid = Getppid(); /* send parent a signal when packet has + been consumed */ + +#if WITH_RETRY + /* !? */ + xfd->retry = 0; + xfd->forever = 0; + level = E_ERROR; +#endif /* WITH_RETRY */ + + /* drop parents locks, reset FIPS... */ + if (xio_forked_inchild() != 0) { + Exit(1); + } + +#if WITH_UNIX + /* with UNIX sockets: only listening parent is allowed to remove + the socket file */ + xfd->opt_unlink_close = false; +#endif /* WITH_UNIX */ + + break; + } + + /* server: continue loop with listen */ + Notice1("forked off child process "F_pid, pid); + + xio_waitingfor = pid; + /* now we are ready to handle signals */ + Sigprocmask(SIG_UNBLOCK, &mask_sigchldusr1, NULL); + + while (!xio_hashappened) { + Sleep(UINT_MAX); /* any signal lets us continue */ + } + xio_waitingfor = 0; /* so this child will not set hashappened again */ + xio_hashappened = false; + + Info("continue listening"); + } else { + break; + } + } + if ((result = _xio_openlate(xfd, opts)) != 0) + return STAT_NORETRY; + + return STAT_OK; +} + + +/* returns STAT_* */ +int _xioopen_dgram_recv(struct single *xfd, int xioflags, + struct sockaddr *us, socklen_t uslen, + struct opt *opts, int pf, int socktype, int proto, + int level) { + char *rangename; + char infobuff[256]; + + if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY; + + if ((xfd->fd = Socket(pf, socktype, proto)) < 0) { + Msg4(level, + "socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno)); + return STAT_RETRYLATER; + } + + applyopts_single(xfd, opts, PH_PASTSOCKET); + applyopts(xfd->fd, opts, PH_PASTSOCKET); + + applyopts_cloexec(xfd->fd, opts); + + applyopts(xfd->fd, opts, PH_PREBIND); + applyopts(xfd->fd, opts, PH_BIND); + if ((us != NULL) && Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) { + Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->fd, + sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen, + strerror(errno)); + Close(xfd->fd); + return STAT_RETRYLATER; + } + +#if WITH_UNIX + if (pf == AF_UNIX && us != NULL) { + applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD); + } +#endif + + applyopts(xfd->fd, opts, PH_PASTBIND); +#if WITH_UNIX + if (pf == AF_UNIX && us != NULL) { + /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/ + applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_EARLY); + applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_PREOPEN); + } +#endif /* WITH_UNIX */ + +#if WITH_IP4 /*|| WITH_IP6*/ + if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { + if (parserange(rangename, pf, &xfd->para.socket.range) + < 0) { + free(rangename); + return STAT_NORETRY; + } + free(rangename); + xfd->para.socket.dorange = true; + } +#endif + +#if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP + xio_retropt_tcpwrap(xfd, opts); +#endif /* && (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */ + + if (xioopts.logopt == 'm') { + Info("starting recvfrom loop, switching to syslog"); + diag_set('y', xioopts.syslogfac); xioopts.logopt = 'y'; + } else { + Info("starting recvfrom loop"); + } + + return STAT_OK; +} + + +int retropt_socket_pf(struct opt *opts, int *pf) { + char *pfname; + + if (retropt_string(opts, OPT_PROTOCOL_FAMILY, &pfname) >= 0) { + if (false) { + ; +#if WITH_IP4 + } else if (!strcasecmp("inet", pfname) || + !strcasecmp("inet4", pfname) || + !strcasecmp("ip4", pfname) || + !strcasecmp("ipv4", pfname) || + !strcasecmp("2", pfname)) { + *pf = PF_INET; +#endif /* WITH_IP4 */ +#if WITH_IP6 + } else if (!strcasecmp("inet6", pfname) || + !strcasecmp("ip6", pfname) || + !strcasecmp("ipv6", pfname) || + !strcasecmp("10", pfname)) { + *pf = PF_INET6; +#endif /* WITH_IP6 */ + } else { + Error1("unknown protocol family \"%s\"", pfname); + /*! Warn("falling back to INET");*/ + } + free(pfname); + return 0; + } + return -1; +} + + + +int xiogetpacketsrc(int fd, union sockaddr_union *pa, socklen_t *palen) { + char infobuff[256]; + char peekbuff[1]; + +#if 0 + + struct msghdr msgh = {0}; +#if HAVE_STRUCT_IOVEC + struct iovec iovec; +#endif + char ctrlbuff[5120]; + + msgh.msg_name = pa; + msgh.msg_namelen = *palen; +#if HAVE_STRUCT_IOVEC + iovec.iov_base = peekbuff; + iovec.iov_len = sizeof(peekbuff); + msgh.msg_iov = &iovec; + msgh.msg_iovlen = 1; +#endif +#if HAVE_STRUCT_MSGHDR_MSGCONTROL + msgh.msg_control = ctrlbuff; +#endif +#if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN + msgh.msg_controllen = sizeof(ctrlbuff); +#endif +#if HAVE_STRUCT_MSGHDR_MSGFLAGS + msgh.msg_flags = 0; +#endif + if (Recvmsg(fd, &msgh, MSG_PEEK +#ifdef MSG_TRUNC + |MSG_TRUNC +#endif + ) < 0) { + Notice1("packet from %s", + sockaddr_info(&pa->soa, infobuff, sizeof(infobuff))); + Warn1("recvmsg(): %s", strerror(errno)); + return STAT_RETRYLATER; + } + *palen = msgh.msg_namelen; + return STAT_OK; + +#else + + if (Recvfrom(fd, peekbuff, sizeof(peekbuff), MSG_PEEK +#ifdef MSG_TRUNC + |MSG_TRUNC +#endif + , + &pa->soa, palen) < 0) { + Notice1("packet from %s", + sockaddr_info(&pa->soa, *palen, infobuff, sizeof(infobuff))); + Warn1("recvfrom(): %s", strerror(errno)); + return STAT_RETRYLATER; + } + return STAT_OK; + +#endif +} + + +int xiocheckrange(union sockaddr_union *sa, union xiorange_union *range) { + switch (sa->soa.sa_family) { +#if WITH_IP4 + case PF_INET: + return + xiocheckrange_ip4(&sa->ip4, &range->ip4); +#endif /* WITH_IP4 */ +#if WITH_IP6 + case PF_INET6: + return + xiocheckrange_ip6(&sa->ip6, &range->ip6); +#endif /* WITH_IP6 */ + } + return -1; +} + +int xiocheckpeer(xiosingle_t *xfd, + union sockaddr_union *pa, union sockaddr_union *la) { + char infobuff[256]; + int result; + +#if WITH_IP4 + if (xfd->para.socket.dorange) { + if (xiocheckrange(pa, &xfd->para.socket.range) < 0) { + char infobuff[256]; + Warn1("refusing connection from %s due to range option", + sockaddr_info((struct sockaddr *)pa, 0, + infobuff, sizeof(infobuff))); + return -1; + } + Info1("permitting connection from %s due to range option", + sockaddr_info((struct sockaddr *)pa, 0, + infobuff, sizeof(infobuff))); + } +#endif /* WITH_IP4 */ + +#if WITH_TCP || WITH_UDP + if (xfd->para.socket.ip.dosourceport) { +#if WITH_IP4 + if (pa->soa.sa_family == AF_INET && + ntohs(((struct sockaddr_in *)pa)->sin_port) != xfd->para.socket.ip.sourceport) { + Warn1("refusing connection from %s due to wrong sourceport", + sockaddr_info((struct sockaddr *)pa, 0, + infobuff, sizeof(infobuff))); + return -1; + } +#endif /* WITH_IP4 */ +#if WITH_IP6 + if (pa->soa.sa_family == AF_INET6 && + ntohs(((struct sockaddr_in6 *)pa)->sin6_port) != xfd->para.socket.ip.sourceport) { + Warn1("refusing connection from %s due to sourceport option", + sockaddr_info((struct sockaddr *)pa, 0, + infobuff, sizeof(infobuff))); + return -1; + } +#endif /* WITH_IP6 */ + Info1("permitting connection from %s due to sourceport option", + sockaddr_info((struct sockaddr *)pa, 0, + infobuff, sizeof(infobuff))); + } else if (xfd->para.socket.ip.lowport) { + if (pa->soa.sa_family == AF_INET && + ntohs(((struct sockaddr_in *)pa)->sin_port) >= IPPORT_RESERVED) { + Warn1("refusing connection from %s due to lowport option", + sockaddr_info((struct sockaddr *)pa, 0, + infobuff, sizeof(infobuff))); + return -1; + } +#if WITH_IP6 + else if (pa->soa.sa_family == AF_INET6 && + ntohs(((struct sockaddr_in6 *)pa)->sin6_port) >= + IPPORT_RESERVED) { + Warn1("refusing connection from %s due to lowport option", + sockaddr_info((struct sockaddr *)pa, 0, + infobuff, sizeof(infobuff))); + return -1; + } +#endif /* WITH_IP6 */ + Info1("permitting connection from %s due to lowport option", + sockaddr_info((struct sockaddr *)pa, 0, + infobuff, sizeof(infobuff))); + } +#endif /* WITH_TCP || WITH_UDP */ + +#if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP + result = xio_tcpwrap_check(xfd, la, pa); + if (result < 0) { + char infobuff[256]; + Warn1("refusing connection from %s due to tcpwrapper option", + sockaddr_info((struct sockaddr *)pa, 0, + infobuff, sizeof(infobuff))); + return -1; + } else if (result > 0) { + Info1("permitting connection from %s due to tcpwrapper option", + sockaddr_info((struct sockaddr *)pa, 0, + infobuff, sizeof(infobuff))); + } +#endif /* (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */ + + return 0; /* permitted */ +} + +#endif /* _WITH_SOCKET */ diff --git a/xio-socket.h b/xio-socket.h new file mode 100644 index 0000000..1bccf1f --- /dev/null +++ b/xio-socket.h @@ -0,0 +1,90 @@ +/* $Id: xio-socket.h,v 1.16 2006/12/30 23:04:21 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_socket_h_included +#define __xio_socket_h_included 1 + +extern const struct optdesc opt_connect_timeout; +extern const struct optdesc opt_so_debug; +extern const struct optdesc opt_so_acceptconn; +extern const struct optdesc opt_so_broadcast; +extern const struct optdesc opt_so_reuseaddr; +extern const struct optdesc opt_so_keepalive; +extern const struct optdesc opt_so_linger; +extern const struct optdesc opt_so_linger; +extern const struct optdesc opt_so_oobinline; +extern const struct optdesc opt_so_sndbuf; +extern const struct optdesc opt_so_sndbuf_late; +extern const struct optdesc opt_so_rcvbuf; +extern const struct optdesc opt_so_rcvbuf_late; +extern const struct optdesc opt_so_error; +extern const struct optdesc opt_so_type; +extern const struct optdesc opt_so_dontroute; +extern const struct optdesc opt_so_rcvlowat; +extern const struct optdesc opt_so_rcvtimeo; +extern const struct optdesc opt_so_sndlowat; +extern const struct optdesc opt_so_sndtimeo; +extern const struct optdesc opt_so_audit; +extern const struct optdesc opt_so_attach_filter; +extern const struct optdesc opt_so_detach_filter; +extern const struct optdesc opt_so_bindtodevice; +extern const struct optdesc opt_so_bsdcompat; +extern const struct optdesc opt_so_cksumrecv; +extern const struct optdesc opt_so_kernaccept; +extern const struct optdesc opt_so_no_check; +extern const struct optdesc opt_so_noreuseaddr; +extern const struct optdesc opt_so_passcred; +extern const struct optdesc opt_so_peercred; +extern const struct optdesc opt_so_priority; +extern const struct optdesc opt_so_reuseport; +extern const struct optdesc opt_so_security_authentication; +extern const struct optdesc opt_so_security_encryption_network; +extern const struct optdesc opt_so_security_encryption_transport; +extern const struct optdesc opt_so_use_ifbufs; +extern const struct optdesc opt_so_useloopback; +extern const struct optdesc opt_so_dgram_errind; +extern const struct optdesc opt_so_dontlinger; +extern const struct optdesc opt_so_prototype; +extern const struct optdesc opt_fiosetown; +extern const struct optdesc opt_siocspgrp; +extern const struct optdesc opt_bind; +extern const struct optdesc opt_protocol_family; + +extern int retropt_socket_pf(struct opt *opts, int *pf); + +extern int xioopen_connect(struct single *fd, + struct sockaddr *us, size_t uslen, + struct sockaddr *them, size_t themlen, + struct opt *opts, int pf, int stype, int proto, + bool alt); +extern int _xioopen_connect(struct single *fd, + struct sockaddr *us, size_t uslen, + struct sockaddr *them, size_t themlen, + struct opt *opts, int pf, int stype, int proto, + bool alt, int level); + +/* common to xioopen_udp_sendto, ..unix_sendto, ..rawip */ +extern +int _xioopen_dgram_sendto(/* them is already in xfd->peersa */ + union sockaddr_union *us, socklen_t uslen, + struct opt *opts, + int xioflags, xiosingle_t *xfd, unsigned groups, + int pf, int socktype, int ipproto); +extern +int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags, + struct sockaddr *us, socklen_t uslen, + struct opt *opts, + int pf, int socktype, int proto, int level); +extern +int _xioopen_dgram_recv(struct single *xfd, int xioflags, + struct sockaddr *us, socklen_t uslen, + struct opt *opts, int pf, int socktype, int proto, + int level); +extern +int xiogetpacketsrc(int fd, union sockaddr_union *pa, socklen_t *palen); +extern +int xiocheckpeer(xiosingle_t *xfd, + union sockaddr_union *pa, union sockaddr_union *la); + +#endif /* !defined(__xio_socket_h_included) */ diff --git a/xio-socks.c b/xio-socks.c new file mode 100644 index 0000000..8e990de --- /dev/null +++ b/xio-socks.c @@ -0,0 +1,430 @@ +/* $Id: xio-socks.c,v 1.33 2006/12/28 14:06:37 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for opening addresses of socks4 type */ + +#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" + +#include "xio-socks.h" + + +enum { + SOCKS_CD_GRANTED = 90, + SOCKS_CD_FAILED, + SOCKS_CD_NOIDENT, + 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, + unsigned groups, int dummy1, int dummy2, + int dummy3); + +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 addrdesc addr_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(":::") }; + +const struct addrdesc addr_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(":::") }; + +static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xxfd, + unsigned groups, int socks4a, int dummy2, + int dummy3) { + /* we expect the form: host:host:port */ + struct single *xfd = &xxfd->stream; + struct opt *opts0 = NULL; + const char *sockdname; char *socksport; + const char *targetname, *targetport; + int pf = PF_UNSPEC; + int ipproto = IPPROTO_TCP; + bool dofork = false; + union sockaddr_union us_sa, *us = &us_sa; + union sockaddr_union them_sa, *them = &them_sa; + socklen_t uslen = sizeof(us_sa); + socklen_t themlen = sizeof(them_sa); + bool needbind = false; + bool lowport = false; + unsigned char buff[BUFF_LEN]; + struct socks4 *sockhead = (struct socks4 *)buff; + size_t buflen = sizeof(buff); + int socktype = SOCK_STREAM; + int level; + int result; + + if (argc != 4) { + Error1("%s: 3 parameters required", argv[0]); + return STAT_NORETRY; + } + sockdname = argv[1]; + targetname = argv[2]; + targetport = argv[3]; + + xfd->howtoend = END_SHUTDOWN; + if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; + applyopts(-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); + if (result != STAT_OK) return result; + result = + _xioopen_ipapp_prepare(opts, &opts0, sockdname, socksport, + &pf, ipproto, + xfd->para.socket.ip.res_opts[1], + xfd->para.socket.ip.res_opts[0], + them, &themlen, us, &uslen, + &needbind, &lowport, &socktype); + + Notice5("opening connection to %s:%u via socks4 server %s:%s as user \"%s\"", + targetname, + ntohs(sockhead->port), + sockdname, socksport, sockhead->userid); + + do { /* loop over failed connect and socks-request attempts */ + +#if WITH_RETRY + if (xfd->forever || xfd->retry) { + level = E_INFO; + } else +#endif /* WITH_RETRY */ + level = E_ERROR; + + /* we try to resolve the target address _before_ connecting to the socks + server: this avoids unnecessary socks connects and timeouts */ + result = + _xioopen_socks4_connect0(xfd, targetname, socks4a, sockhead, + (ssize_t *)&buflen, level); + switch (result) { + case STAT_OK: break; +#if WITH_RETRY + case STAT_RETRYLATER: + case STAT_RETRYNOW: + if (xfd->forever || xfd->retry--) { + if (result == STAT_RETRYLATER) Nanosleep(&xfd->intervall, NULL); + continue; + } +#endif /* WITH_RETRY */ + default: + return result; + } + + /* this cannot fork because we retrieved fork option above */ + result = + _xioopen_connect (xfd, + needbind?(struct sockaddr *)us:NULL, sizeof(*us), + (struct sockaddr *)them, themlen, + opts, pf, socktype, IPPROTO_TCP, lowport, level); + switch (result) { + case STAT_OK: break; +#if WITH_RETRY + case STAT_RETRYLATER: + case STAT_RETRYNOW: + if (xfd->forever || xfd->retry--) { + if (result == STAT_RETRYLATER) Nanosleep(&xfd->intervall, NULL); + continue; + } +#endif /* WITH_RETRY */ + default: + return result; + } + + applyopts(xfd->fd, opts, PH_ALL); + + if ((result = _xio_openlate(xfd, opts)) < 0) + return result; + + result = _xioopen_socks4_connect(xfd, sockhead, buflen, level); + switch (result) { + case STAT_OK: break; +#if WITH_RETRY + case STAT_RETRYLATER: + case STAT_RETRYNOW: + if (xfd->forever || xfd->retry--) { + if (result == STAT_RETRYLATER) Nanosleep(&xfd->intervall, NULL); + continue; + } +#endif /* WITH_RETRY */ + default: + return result; + } + +#if WITH_RETRY + if (dofork) { + pid_t pid; + while ((pid = Fork()) < 0) { + int level = E_ERROR; + if (xfd->forever || xfd->retry) { + level = E_WARN; + } + Msg1(level, "fork(): %s", strerror(errno)); + if (xfd->forever || xfd->retry--) { + Nanosleep(&xfd->intervall, NULL); + continue; + } + return STAT_RETRYLATER; + } + if (pid == 0) { /* child process */ + Info1("just born: socks client process "F_pid, Getpid()); + + /* drop parents locks, reset FIPS... */ + if (xio_forked_inchild() != 0) { + Exit(1); + } + xfd->forever = false; xfd->retry = 0; + break; + } + /* parent process */ + Notice1("forked off child process "F_pid, pid); + Close(xfd->fd); + Nanosleep(&xfd->intervall, NULL); + dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); + continue; + } else +#endif /* WITH_RETRY */ + { + break; + } + + } while (true); /* end of complete open loop - drop out on success */ + return 0; +} + + +int _xioopen_socks4_prepare(const char *targetport, struct opt *opts, char **socksport, struct socks4 *sockhead, size_t *headlen) { + struct servent *se; + char *userid; + + /* generate socks header - points to final target */ + sockhead->version = 4; + sockhead->action = 1; + sockhead->port = parseport(targetport, IPPROTO_TCP); + + 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 (retropt_string(opts, OPT_SOCKSUSER, &userid) < 0) { + if ((userid = getenv("LOGNAME")) == NULL) { + if ((userid = getenv("USER")) == NULL) { + userid = "anonymous"; + } + } + } + strncpy(sockhead->userid, userid, *headlen-SIZEOF_STRUCT_SOCKS4); + *headlen = SIZEOF_STRUCT_SOCKS4+strlen(userid)+1; + return STAT_OK; +} + + +/* called within retry/fork loop, before connect() */ +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) { + int result; + + if (!socks4a) { + union sockaddr_union sau; + socklen_t saulen = sizeof(sau); + + if ((result = xiogetaddrinfo(hostname, NULL, + PF_INET, SOCK_STREAM, IPPROTO_TCP, + &sau, &saulen, + xfd->para.socket.ip.res_opts[1], + xfd->para.socket.ip.res_opts[0])) + != STAT_OK) { + return result; /*! STAT_RETRY? */ + } + memcpy(&sockhead->dest, &sau.ip4.sin_addr, 4); + } +#if WITH_SOCKS4A + else { + /*! noresolve */ + sockhead->dest = htonl(0x00000001); /* three bytes zero */ + } +#endif /* WITH_SOCKS4A */ +#if WITH_SOCKS4A + if (socks4a) { + /* SOCKS4A requires us to append the host name to resolve + after the user name's trailing 0 byte. */ + char* insert_position = (char*) sockhead + *headlen; + + strncpy(insert_position, hostname, BUFF_LEN-*headlen); + ((char *)sockhead)[BUFF_LEN-1] = 0; + *headlen += strlen(hostname) + 1; + if (*headlen > BUFF_LEN) { + *headlen = BUFF_LEN; + } + } +#endif /* WITH_SOCKS4A */ + return STAT_OK; +} + + +/* perform socks4 client dialog on existing FD. + Called within fork/retry loop, after connect() */ +int _xioopen_socks4_connect(struct single *xfd, + struct socks4 *sockhead, + size_t headlen, + int level) { + ssize_t bytes; + int result; + unsigned char buff[SIZEOF_STRUCT_SOCKS4]; + struct socks4 *replyhead = (struct socks4 *)buff; + char *destdomname = NULL; + + /* send socks header (target addr+port, +auth) */ +#if WITH_MSGLEVEL <= E_INFO + if (ntohl(sockhead->dest) <= 0x000000ff) { + destdomname = strchr(sockhead->userid, '\0')+1; + } + Info11("sending socks4%s request VN=%d DC=%d DSTPORT=%d DSTIP=%d.%d.%d.%d USERID=%s%s%s", + destdomname?"a":"", + sockhead->version, sockhead->action, sockhead->port, + ((unsigned char *)&sockhead->dest)[0], + ((unsigned char *)&sockhead->dest)[1], + ((unsigned char *)&sockhead->dest)[2], + ((unsigned char *)&sockhead->dest)[3], + sockhead->userid, + destdomname?" DESTNAME=":"", + destdomname?destdomname:""); +#endif /* WITH_MSGLEVEL <= E_INFO */ +#if WITH_MSGLEVEL <= E_DEBUG + { + char *msgbuff; + if ((msgbuff = Malloc(3*headlen)) != NULL) { + xiohexdump((const unsigned char *)sockhead, headlen, msgbuff); + Debug1("sending socks4(a) request data %s", msgbuff); + } + } +#endif /* WITH_MSGLEVEL <= E_DEBUG */ + do { + result = Write(xfd->fd, sockhead, headlen); + } while (result < 0 && errno == EINTR); + if (result < 0) { + Msg4(level, "write(%d, %p, "F_Zu"): %s", + xfd->fd, sockhead, headlen, strerror(errno)); + if (Close(xfd->fd) < 0) { + Info2("close(%d): %s", xfd->fd, strerror(errno)); + } + return STAT_RETRYLATER; /* retry complete open cycle */ + } + + bytes = 0; + Info("waiting for socks reply"); + while (bytes >= 0) { /* loop over answer chunks until complete or error */ + /* receive socks answer */ + do { + result = Read(xfd->fd, buff+bytes, SIZEOF_STRUCT_SOCKS4-bytes); + } while (result < 0 && errno == EINTR); + if (result < 0) { + Msg4(level, "read(%d, %p, "F_Zu"): %s", + xfd->fd, buff+bytes, SIZEOF_STRUCT_SOCKS4-bytes, + strerror(errno)); + if (Close(xfd->fd) < 0) { + Info2("close(%d): %s", xfd->fd, strerror(errno)); + } + } + if (result == 0) { + Msg(level, "read(): EOF during read of socks reply, peer might not be a socks4 server"); + if (Close(xfd->fd) < 0) { + Info2("close(%d): %s", xfd->fd, strerror(errno)); + } + return STAT_RETRYLATER; + } +#if WITH_MSGLEVEL <= E_DEBUG + { + char msgbuff[3*SIZEOF_STRUCT_SOCKS4]; + * xiohexdump((const unsigned char *)replyhead+bytes, result, msgbuff) + = '\0'; + Debug2("received socks4 reply data (offset %u): %s", bytes, msgbuff); + } +#endif /* WITH_MSGLEVEL <= E_DEBUG */ + bytes += result; + if (bytes == SIZEOF_STRUCT_SOCKS4) { + Debug1("received all "F_Zd" bytes", bytes); + break; + } + Debug2("received "F_Zd" bytes, waiting for "F_Zu" more bytes", + result, SIZEOF_STRUCT_SOCKS4-bytes); + } + if (result <= 0) { /* we had a problem while reading socks answer */ + return STAT_RETRYLATER; /* retry complete open cycle */ + } + + Info7("received socks reply VN=%u CD=%u DSTPORT=%u DSTIP=%u.%u.%u.%u", + replyhead->version, replyhead->action, ntohs(replyhead->port), + ((uint8_t *)&replyhead->dest)[0], + ((uint8_t *)&replyhead->dest)[1], + ((uint8_t *)&replyhead->dest)[2], + ((uint8_t *)&replyhead->dest)[3]); + if (replyhead->version != 0) { + Warn1("socks: reply code version is not 0 (%d)", + replyhead->version); + } + + switch (replyhead->action) { + case SOCKS_CD_GRANTED: + /* Notice("socks: connect request succeeded"); */ +#if 0 + if (Getsockname(xfd->fd, (struct sockaddr *)&us, &uslen) < 0) { + Warn4("getsockname(%d, %p, {%d}): %s", + xfd->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: + Msg(level, "socks: connect request rejected or failed"); + return STAT_RETRYLATER; + + case SOCKS_CD_NOIDENT: + Msg(level, "socks: ident refused by client"); + return STAT_RETRYLATER; + + case SOCKS_CD_IDENTFAILED: + Msg(level, "socks: ident failed"); + return STAT_RETRYLATER; + + default: + Msg1(level, "socks: undefined status %u", replyhead->action); + } + + return STAT_OK; +} +#endif /* WITH_SOCKS4 || WITH_SOCKS4A */ + diff --git a/xio-socks.h b/xio-socks.h new file mode 100644 index 0000000..5b97b11 --- /dev/null +++ b/xio-socks.h @@ -0,0 +1,37 @@ +/* $Id: xio-socks.h,v 1.6 2004/06/06 19:03:28 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2004 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_socks_h_included +#define __xio_socks_h_included 1 + +struct socks4 { + uint8_t version; + uint8_t action; + uint16_t port; + uint32_t dest; + char userid[1]; /* just to have access via this struct */ +} ; +#define SIZEOF_STRUCT_SOCKS4 8 + +extern const struct optdesc opt_socksport; +extern const struct optdesc opt_socksuser; + +extern const struct addrdesc addr_socks4_connect; +extern const struct addrdesc addr_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_socks4_connect(struct single *xfd, + struct socks4 *sockhead, + size_t headlen, + int level); + +#endif /* !defined(__xio_socks_h_included) */ diff --git a/xio-stdio.c b/xio-stdio.c new file mode 100644 index 0000000..64cc4ee --- /dev/null +++ b/xio-stdio.c @@ -0,0 +1,150 @@ +/* $Id: xio-stdio.c,v 1.18 2006/12/28 14:07:01 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for opening addresses stdio type */ + +#include "xiosysincludes.h" +#include "xioopen.h" + +#include "xio-fdnum.h" +#include "xio-stdio.h" + + +#if WITH_STDIO + +static int xioopen_stdio(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); +static int xioopen_stdfd(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int fd, int dummy2, int dummy3); + + +/* we specify all option groups that we can imagine for a FD, becasue the + changed parsing mechanism does not allow us to check the type of FD before + applying the options */ +const struct addrdesc addr_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) }; +const struct addrdesc addr_stdin = { "stdin", 1, xioopen_stdfd, 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) }; +const struct addrdesc addr_stdout = { "stdout", 2, xioopen_stdfd, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, 1, 0, 0 HELP(NULL) }; +const struct addrdesc addr_stderr = { "stderr", 2, xioopen_stdfd, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, 2, 0, 0 HELP(NULL) }; + + +/* process a bidirectional "stdio" or "-" argument with options. + generate a dual address. */ +int xioopen_stdio_bi(xiofile_t *sock) { + struct opt *opts1, *opts2, *optspr; + unsigned int groups1 = addr_stdio.groups, groups2 = addr_stdio.groups; + int result; + + if (xioopen_makedual(sock) < 0) { + return -1; + } + + sock->dual.stream[0]->tag = XIO_TAG_RDONLY; + sock->dual.stream[0]->fd = 0 /*stdin*/; + sock->dual.stream[1]->tag = XIO_TAG_WRONLY; + sock->dual.stream[1]->fd = 1 /*stdout*/; + sock->dual.stream[0]->howtoend = + sock->dual.stream[1]->howtoend = END_NONE; + +#if WITH_TERMIOS + if (Isatty(sock->dual.stream[0]->fd)) { + if (Tcgetattr(sock->dual.stream[0]->fd, + &sock->dual.stream[0]->savetty) + < 0) { + Warn2("cannot query current terminal settings on fd %d: %s", + sock->dual.stream[0]->fd, strerror(errno)); + } else { + sock->dual.stream[0]->ttyvalid = true; + } + } + if (Isatty(sock->dual.stream[1]->fd)) { + if (Tcgetattr(sock->dual.stream[1]->fd, + &sock->dual.stream[1]->savetty) + < 0) { + Warn2("cannot query current terminal settings on fd %d: %s", + sock->dual.stream[1]->fd, strerror(errno)); + } else { + sock->dual.stream[1]->ttyvalid = true; + } + } +#endif /* WITH_TERMIOS */ + + if (applyopts_single(&sock->stream, sock->stream.opts, PH_INIT) < 0) return -1; + applyopts(-1, sock->stream.opts, PH_INIT); + + /* options here are one-time and one-direction, no second use */ + retropt_bool(sock->stream.opts, OPT_IGNOREEOF, &sock->dual.stream[0]->ignoreeof); + + /* extract opts that should be applied only once */ + if ((optspr = copyopts(sock->stream.opts, GROUP_PROCESS)) == NULL) { + return -1; + } + if ((result = applyopts(-1, optspr, PH_EARLY)) < 0) + return result; + if ((result = applyopts(-1, optspr, PH_PREOPEN)) < 0) + return result; + + /* here we copy opts, because most have to be applied twice! */ + if ((opts1 = copyopts(sock->stream.opts, GROUP_FD|GROUP_APPL|(groups1&~GROUP_PROCESS))) == NULL) { + return -1; + } + + /* apply options to first FD */ + if ((result = applyopts(sock->dual.stream[0]->fd, opts1, PH_ALL)) < 0) { + return result; + } + if ((result = _xio_openlate(sock->dual.stream[0], opts1)) < 0) { + return result; + } + + if ((opts2 = copyopts(sock->stream.opts, GROUP_FD|GROUP_APPL|(groups2&~GROUP_PROCESS))) == NULL) { + return -1; + } + /* apply options to second FD */ + if ((result = applyopts(sock->dual.stream[1]->fd, opts2, PH_ALL)) < 0) { + return result; + } + if ((result = _xio_openlate(sock->dual.stream[1], opts2)) < 0) { + return result; + } + + if ((result = _xio_openlate(sock->dual.stream[1], optspr)) < 0) { + return result; + } + + Notice("reading from and writing to stdio"); + return 0; +} + + +/* wrap around unidirectional xioopensingle and xioopen_fd to automatically determine stdin or stdout fd depending on rw. + Do not set FD_CLOEXEC flag. */ +static int xioopen_stdio(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3) { + int rw = (xioflags&XIO_ACCMODE); + + if (argc != 1) { + Error2("%s: wrong number of parameters (%d instead of 0)", argv[0], argc-1); + } + + if (rw == XIO_RDWR) { + return xioopen_stdio_bi(fd); + } + + Notice2("using %s for %s", + &("stdin\0\0\0stdout"[rw<<3]), + ddirection[rw]); + return xioopen_fd(opts, rw, &fd->stream, rw, dummy2, dummy3); +} + +/* wrap around unidirectional xioopensingle and xioopen_fd to automatically determine stdin or stdout fd depending on rw. + Do not set FD_CLOEXEC flag. */ +static int xioopen_stdfd(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int fd, int dummy2, int dummy3) { + int rw = (xioflags&XIO_ACCMODE); + + if (argc != 1) { + Error2("%s: wrong number of parameters (%d instead of 0)", argv[0], argc-1); + } + Notice2("using %s for %s", + &("stdin\0\0\0stdout\0\0stderr"[fd<<3]), + ddirection[rw]); + return xioopen_fd(opts, rw, &xfd->stream, fd, dummy2, dummy3); +} +#endif /* WITH_STDIO */ diff --git a/xio-stdio.h b/xio-stdio.h new file mode 100644 index 0000000..b75c17b --- /dev/null +++ b/xio-stdio.h @@ -0,0 +1,17 @@ +/* $Id: xio-stdio.h,v 1.5 2006/02/08 19:47:03 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_stdio_h_included +#define __xio_stdio_h_included 1 + + + +extern int xioopen_stdio_bi(xiofile_t *sock); + +extern const struct addrdesc addr_stdio; +extern const struct addrdesc addr_stdin; +extern const struct addrdesc addr_stdout; +extern const struct addrdesc addr_stderr; + +#endif /* !defined(__xio_stdio_h_included) */ diff --git a/xio-system.c b/xio-system.c new file mode 100644 index 0000000..3297870 --- /dev/null +++ b/xio-system.c @@ -0,0 +1,65 @@ +/* $Id: xio-system.c,v 1.13 2006/03/21 20:53:38 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for opening addresses of system type */ + +#include "xiosysincludes.h" +#include "xioopen.h" + +#include "xio-progcall.h" +#include "xio-system.h" + + +#if WITH_SYSTEM + +static int xioopen_system(int arg, const char *argv[], struct opt *opts, + int xioflags, /* XIO_RDONLY etc. */ + xiofile_t *fd, + unsigned groups, + int dummy1, int dummy2, int dummy3 + ); + +const struct addrdesc addr_system = { "system", 3, xioopen_system, GROUP_FD|GROUP_FORK|GROUP_EXEC|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_TERMIOS|GROUP_FIFO|GROUP_PTY|GROUP_PARENT, 1, 0, 0 HELP(":") }; + + +static int xioopen_system(int argc, const char *argv[], struct opt *opts, + int xioflags, /* XIO_RDONLY etc. */ + xiofile_t *fd, + unsigned groups, + int dummy1, int dummy2, int dummy3 + ) { + int status; + char *path = NULL; + int result; + const char *string = argv[1]; + + status = _xioopen_foxec(xioflags, &fd->stream, groups, &opts); + if (status < 0) return status; + if (status == 0) { /* child */ + int numleft; + + if (setopt_path(opts, &path) < 0) { + /* this could be dangerous, so let us abort this child... */ + Exit(1); + } + + if ((numleft = leftopts(opts)) > 0) { + Error1("%d option(s) could not be used", numleft); + showleft(opts); + return STAT_NORETRY; + } + + Info1("executing shell command \"%s\"", string); + result = System(string); + if (result != 0) { + Warn2("system(\"%s\") returned with status %d", string, result); + } + Exit(0); /* this child process */ + } + + /* parent */ + return 0; +} + +#endif /* WITH_SYSTEM */ diff --git a/xio-system.h b/xio-system.h new file mode 100644 index 0000000..31f3fce --- /dev/null +++ b/xio-system.h @@ -0,0 +1,10 @@ +/* $Id: xio-system.h,v 1.4 2001/11/04 17:19:20 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_system_h_included +#define __xio_system_h_included 1 + +extern const struct addrdesc addr_system; + +#endif /* !defined(__xio_system_h_included) */ diff --git a/xio-tcp.c b/xio-tcp.c new file mode 100644 index 0000000..24fa5ae --- /dev/null +++ b/xio-tcp.c @@ -0,0 +1,119 @@ +/* $Id: xio-tcp.c,v 1.24 2006/07/13 06:48:47 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for TCP related functions and options */ + +#include "xiosysincludes.h" + +#if WITH_TCP + +#include "xioopen.h" +#include "xio-listen.h" +#include "xio-ip4.h" +#include "xio-ipapp.h" +#include "xio-tcp.h" + +/****** TCP addresses ******/ + +#if WITH_IP4 || WITH_IP6 +const struct addrdesc addr_tcp_connect = { "tcp-connect", 1+XIO_RDWR, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_CHILD|GROUP_RETRY, SOCK_STREAM, IPPROTO_TCP, PF_UNSPEC HELP("::") }; +#if WITH_LISTEN +const struct addrdesc addr_tcp_listen = { "tcp-listen", 1+XIO_RDWR, xioopen_ipapp_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, SOCK_STREAM, IPPROTO_TCP, PF_UNSPEC HELP(":") }; +#endif +#endif + +#if WITH_IP4 +const struct addrdesc addr_tcp4_connect = { "tcp4-connect", 1+XIO_RDWR, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_TCP|GROUP_CHILD|GROUP_RETRY, SOCK_STREAM, IPPROTO_TCP, PF_INET HELP("::") }; +#if WITH_LISTEN +const struct addrdesc addr_tcp4_listen = { "tcp4-listen", 1+XIO_RDWR, xioopen_ipapp_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, SOCK_STREAM, IPPROTO_TCP, PF_INET HELP(":") }; +#endif +#endif /* WITH_IP4 */ + +#if WITH_IP6 +const struct addrdesc addr_tcp6_connect = { "tcp6-connect", 1+XIO_RDWR, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_CHILD|GROUP_RETRY, SOCK_STREAM, IPPROTO_TCP, PF_INET6 HELP("::") }; +#if WITH_LISTEN +const struct addrdesc addr_tcp6_listen = { "tcp6-listen", 1+XIO_RDWR, xioopen_ipapp_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, SOCK_STREAM, IPPROTO_TCP, PF_INET6 HELP(":") }; +#endif +#endif /* WITH_IP6 */ + +/****** TCP address options ******/ + +#ifdef TCP_NODELAY +const struct optdesc opt_tcp_nodelay = { "tcp-nodelay", "nodelay", OPT_TCP_NODELAY, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_NODELAY }; +#endif +#ifdef TCP_MAXSEG +const struct optdesc opt_tcp_maxseg = { "tcp-maxseg", "mss", OPT_TCP_MAXSEG, GROUP_IP_TCP, PH_PASTSOCKET,TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_MAXSEG }; +const struct optdesc opt_tcp_maxseg_late={"tcp-maxseg-late","mss-late",OPT_TCP_MAXSEG_LATE,GROUP_IP_TCP,PH_CONNECTED,TYPE_INT,OFUNC_SOCKOPT, SOL_TCP, TCP_MAXSEG}; +#endif +#ifdef TCP_CORK +const struct optdesc opt_tcp_cork = { "tcp-cork", "cork", OPT_TCP_CORK, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_CORK }; +#endif +#ifdef TCP_STDURG +const struct optdesc opt_tcp_stdurg = { "tcp-stdurg", "stdurg", OPT_TCP_STDURG, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_STDURG }; +#endif +#ifdef TCP_RFC1323 +const struct optdesc opt_tcp_rfc1323= { "tcp-rfc1323", "rfc1323", OPT_TCP_RFC1323, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_RFC1323}; +#endif +#ifdef TCP_KEEPIDLE +const struct optdesc opt_tcp_keepidle={ "tcp-keepidle", "keepidle",OPT_TCP_KEEPIDLE,GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP,TCP_KEEPIDLE}; +#endif +#ifdef TCP_KEEPINTVL +const struct optdesc opt_tcp_keepintvl={"tcp-keepintvl","keepintvl",OPT_TCP_KEEPINTVL,GROUP_IP_TCP,PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP,TCP_KEEPINTVL}; +#endif +#ifdef TCP_KEEPCNT +const struct optdesc opt_tcp_keepcnt= { "tcp-keepcnt", "keepcnt", OPT_TCP_KEEPCNT, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_KEEPCNT }; +#endif +#ifdef TCP_SYNCNT +const struct optdesc opt_tcp_syncnt = { "tcp-syncnt", "syncnt", OPT_TCP_SYNCNT, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_SYNCNT }; +#endif +#ifdef TCP_LINGER2 +const struct optdesc opt_tcp_linger2= { "tcp-linger2", "linger2", OPT_TCP_LINGER2, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_LINGER2 }; +#endif +#ifdef TCP_DEFER_ACCEPT +const struct optdesc opt_tcp_defer_accept={"tcp-defer-accept","defer-accept",OPT_TCP_DEFER_ACCEPT,GROUP_IP_TCP,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_TCP,TCP_DEFER_ACCEPT }; +#endif +#ifdef TCP_WINDOW_CLAMP +const struct optdesc opt_tcp_window_clamp={"tcp-window-clamp","window-clamp",OPT_TCP_WINDOW_CLAMP,GROUP_IP_TCP,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_TCP,TCP_WINDOW_CLAMP }; +#endif +#ifdef TCP_INFO +const struct optdesc opt_tcp_info = { "tcp-info", "info", OPT_TCP_INFO, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_INFO }; +#endif +#ifdef TCP_QUICKACK +const struct optdesc opt_tcp_quickack = { "tcp-quickack", "quickack", OPT_TCP_QUICKACK, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_QUICKACK }; +#endif +#ifdef TCP_NOOPT +const struct optdesc opt_tcp_noopt = { "tcp-noopt", "noopt", OPT_TCP_NOOPT, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_NOOPT }; +#endif +#ifdef TCP_NOPUSH +const struct optdesc opt_tcp_nopush = { "tcp-nopush", "nopush", OPT_TCP_NOPUSH, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_NOPUSH }; +#endif +#ifdef TCP_MD5SIG +const struct optdesc opt_tcp_md5sig = { "tcp-md5sig", "md5sig", OPT_TCP_MD5SIG, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_MD5SIG }; +#endif +#ifdef TCP_SACK_DISABLE +const struct optdesc opt_tcp_sack_disable = { "tcp-sack-disable", "sack-disable", OPT_TCP_SACK_DISABLE, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_SACK_DISABLE }; +#endif +#ifdef TCP_SIGNATURE_ENABLE +const struct optdesc opt_tcp_signature_enable = { "tcp-signature-enable", "signature-enable", OPT_TCP_SIGNATURE_ENABLE, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_SIGNATURE_ENABLE }; +#endif +#ifdef TCP_ABORT_THRESHOLD /* HP-UX */ +const struct optdesc opt_tcp_abort_threshold = { "tcp-abort-threshold", "abort-threshold", OPT_TCP_ABORT_THRESHOLD, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_ABORT_THRESHOLD }; +#endif +#ifdef TCP_CONN_ABORT_THRESHOLD /* HP-UX */ +const struct optdesc opt_tcp_conn_abort_threshold = { "tcp-conn-abort-threshold", "conn-abort-threshold", OPT_TCP_CONN_ABORT_THRESHOLD, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_CONN_ABORT_THRESHOLD }; +#endif +#ifdef TCP_KEEPINIT /* OSF1 aka Tru64 */ +const struct optdesc opt_tcp_keepinit = { "tcp-keepinit", "keepinit", OPT_TCP_KEEPINIT, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_TCP, TCP_KEEPINIT }; +#endif +#ifdef TCP_PAWS /* OSF1 aka Tru64 */ +const struct optdesc opt_tcp_paws = { "tcp-paws", "paws", OPT_TCP_PAWS, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_BOOL, OFUNC_SOCKOPT, SOL_TCP, TCP_PAWS }; +#endif +#ifdef TCP_SACKENA /* OSF1 aka Tru64 */ +const struct optdesc opt_tcp_sackena = { "tcp-sackena", "sackena", OPT_TCP_SACKENA, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_BOOL, OFUNC_SOCKOPT, SOL_TCP, TCP_SACKENA }; +#endif +#ifdef TCP_TSOPTENA /* OSF1 aka Tru64 */ +const struct optdesc opt_tcp_tsoptena = { "tcp-tsoptena", "tsoptena", OPT_TCP_TSOPTENA, GROUP_IP_TCP, PH_PASTSOCKET, TYPE_BOOL, OFUNC_SOCKOPT, SOL_TCP, TCP_TSOPTENA }; +#endif + +#endif /* WITH_TCP */ diff --git a/xio-tcp.h b/xio-tcp.h new file mode 100644 index 0000000..041c601 --- /dev/null +++ b/xio-tcp.h @@ -0,0 +1,42 @@ +/* $Id: xio-tcp.h,v 1.12 2006/03/21 20:59:34 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_tcp_h_included +#define __xio_tcp_h_included 1 + +extern const struct addrdesc addr_tcp_connect; +extern const struct addrdesc addr_tcp_listen; +extern const struct addrdesc addr_tcp4_connect; +extern const struct addrdesc addr_tcp4_listen; +extern const struct addrdesc addr_tcp6_connect; +extern const struct addrdesc addr_tcp6_listen; + +extern const struct optdesc opt_tcp_nodelay; +extern const struct optdesc opt_tcp_maxseg; +extern const struct optdesc opt_tcp_maxseg_late; +extern const struct optdesc opt_tcp_cork; +extern const struct optdesc opt_tcp_stdurg; +extern const struct optdesc opt_tcp_rfc1323; +extern const struct optdesc opt_tcp_keepidle; +extern const struct optdesc opt_tcp_keepintvl; +extern const struct optdesc opt_tcp_keepcnt; +extern const struct optdesc opt_tcp_syncnt; +extern const struct optdesc opt_tcp_linger2; +extern const struct optdesc opt_tcp_defer_accept; +extern const struct optdesc opt_tcp_window_clamp; +extern const struct optdesc opt_tcp_info; +extern const struct optdesc opt_tcp_quickack; +extern const struct optdesc opt_tcp_noopt; +extern const struct optdesc opt_tcp_nopush; +extern const struct optdesc opt_tcp_md5sig; +extern const struct optdesc opt_tcp_sack_disable; +extern const struct optdesc opt_tcp_signature_enable; +extern const struct optdesc opt_tcp_abort_threshold; +extern const struct optdesc opt_tcp_conn_abort_threshold; +extern const struct optdesc opt_tcp_keepinit; +extern const struct optdesc opt_tcp_paws; +extern const struct optdesc opt_tcp_sackena; +extern const struct optdesc opt_tcp_tsoptena; + +#endif /* !defined(__xio_tcp_h_included) */ diff --git a/xio-tcpwrap.c b/xio-tcpwrap.c new file mode 100644 index 0000000..4ab19c2 --- /dev/null +++ b/xio-tcpwrap.c @@ -0,0 +1,165 @@ +/* $Id: xio-tcpwrap.c,v 1.4 2007/02/05 19:48:00 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2006-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for tcpwrapper handling stuff */ + +#include "xiosysincludes.h" +#if WITH_LIBWRAP +#include "tcpd.h" +#endif +#include "xioopen.h" + +#include "xio-tcpwrap.h" + + +#if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP + +const struct optdesc opt_tcpwrappers = { "tcpwrappers", "tcpwrap", OPT_TCPWRAPPERS, GROUP_RANGE, PH_ACCEPT, TYPE_STRING_NULL, OFUNC_SPEC }; +const struct optdesc opt_tcpwrap_etc = { "tcpwrap-etc", "tcpwrap-dir", OPT_TCPWRAP_ETC, GROUP_RANGE, PH_ACCEPT, TYPE_FILENAME, OFUNC_SPEC }; +#if defined(HAVE_HOSTS_ALLOW_TABLE) +const struct optdesc opt_tcpwrap_hosts_allow_table = { "tcpwrap-hosts-allow-table", "allow-table", OPT_TCPWRAP_HOSTS_ALLOW_TABLE, GROUP_RANGE, PH_ACCEPT, TYPE_FILENAME, OFUNC_SPEC }; +#endif +#if defined(HAVE_HOSTS_DENY_TABLE) +const struct optdesc opt_tcpwrap_hosts_deny_table = { "tcpwrap-hosts-deny-table", "deny-table", OPT_TCPWRAP_HOSTS_DENY_TABLE, GROUP_RANGE, PH_ACCEPT, TYPE_FILENAME, OFUNC_SPEC }; +#endif + + +/* they are declared only externally with libwrap and would be unresolved + without these definitions */ +int allow_severity=10, deny_severity=10; + +/* returns 0 if option was found and could be applied + returns 1 if option was not found + returns -1 if option was found but failed */ +int xio_retropt_tcpwrap(xiosingle_t *xfd, struct opt *opts) { + bool dolibwrap = false; + dolibwrap = + retropt_string(opts, OPT_TCPWRAPPERS, + &xfd->para.socket.ip.libwrapname) >= 0 || dolibwrap; + dolibwrap = + retropt_string(opts, OPT_TCPWRAP_ETC, + &xfd->para.socket.ip.tcpwrap_etc) >= 0 || dolibwrap; +#if defined(HAVE_HOSTS_ALLOW_TABLE) + dolibwrap = + retropt_string(opts, OPT_TCPWRAP_HOSTS_ALLOW_TABLE, + &xfd->para.socket.ip.hosts_allow_table) >= 0 || dolibwrap; +#endif +#if defined(HAVE_HOSTS_DENY_TABLE) + dolibwrap = + retropt_string(opts, OPT_TCPWRAP_HOSTS_DENY_TABLE, + &xfd->para.socket.ip.hosts_deny_table) >= 0 || dolibwrap; +#endif + if (dolibwrap) { + xfd->para.socket.ip.dolibwrap = true; + if (xfd->para.socket.ip.libwrapname == NULL) { + xfd->para.socket.ip.libwrapname = (char *)diag_get_string('p'); + } +#if defined(HAVE_HOSTS_ALLOW_TABLE) || defined(HAVE_HOSTS_DENY_TABLE) + if (xfd->para.socket.ip.tcpwrap_etc) { + if (xfd->para.socket.ip.hosts_allow_table == NULL) { + xfd->para.socket.ip.hosts_allow_table = + Malloc(strlen(xfd->para.socket.ip.tcpwrap_etc)+1+11+1); + sprintf(xfd->para.socket.ip.hosts_allow_table, "%s/hosts.allow", + xfd->para.socket.ip.tcpwrap_etc); + } + if (xfd->para.socket.ip.hosts_deny_table == NULL) { + xfd->para.socket.ip.hosts_deny_table = + Malloc(strlen(xfd->para.socket.ip.tcpwrap_etc)+1+10+1); + sprintf(xfd->para.socket.ip.hosts_deny_table, "%s/hosts.deny", + xfd->para.socket.ip.tcpwrap_etc); + } + } +#endif /* defined(HAVE_HOSTS_ALLOW_TABLE) || defined(HAVE_HOSTS_DENY_TABLE) */ + return 0; + } + return 1; +} + + +/* returns -1 if forbidden, 0 if no tcpwrap check, or 1 if explicitely allowed + */ +int xio_tcpwrap_check(xiosingle_t *xfd, union sockaddr_union *us, + union sockaddr_union *them) { + char *save_hosts_allow_table, *save_hosts_deny_table; + struct request_info ri; +#if WITH_IP6 + char clientaddr[INET6_ADDRSTRLEN] = "", serveraddr[INET6_ADDRSTRLEN] = ""; +#else + char clientaddr[INET_ADDRSTRLEN] = "", serveraddr[INET_ADDRSTRLEN] = ""; +#endif + int allow; + + if (!xfd->para.socket.ip.dolibwrap) { + return 0; + } + +#if defined(HAVE_HOSTS_ALLOW_TABLE) + save_hosts_allow_table = hosts_allow_table; + if (xfd->para.socket.ip.hosts_allow_table) { + Debug1("hosts_allow_table = \"%s\"", + xfd->para.socket.ip.hosts_allow_table); + hosts_allow_table = xfd->para.socket.ip.hosts_allow_table; + } +#endif /* defined(HAVE_HOSTS_ALLOW_TABLE) */ +#if defined(HAVE_HOSTS_DENY_TABLE) + save_hosts_deny_table = hosts_deny_table; + if (xfd->para.socket.ip.hosts_deny_table) { + Debug1("hosts_deny_table = \"%s\"", + xfd->para.socket.ip.hosts_deny_table); + hosts_deny_table = xfd->para.socket.ip.hosts_deny_table; + } +#endif /* defined(HAVE_HOSTS_DENY_TABLE) */ + + hosts_access_verbose = 32767; + if (inet_ntop(them->soa.sa_family, +#if WITH_IP6 + them->soa.sa_family==PF_INET6 ? + (void *)&them->ip6.sin6_addr : +#endif + (void *)&them->ip4.sin_addr, + clientaddr, sizeof(clientaddr)) == NULL) { + Warn1("inet_ntop(): %s", strerror(errno)); + } + if (inet_ntop(us->soa.sa_family, +#if WITH_IP6 + us->soa.sa_family==PF_INET6 ? + (void *)&us->ip6.sin6_addr : +#endif + (void *)&us->ip4.sin_addr, + serveraddr, sizeof(serveraddr)) == NULL) { + Warn1("inet_ntop(): %s", strerror(errno)); + } + Debug7("request_init(%p, RQ_FILE, %d, RQ_CLIENT_SIN, {%s:%u}, RQ_SERVER_SIN, {%s:%u}, RQ_DAEMON, \"%s\", 0", + &ri, xfd->fd, clientaddr, + ntohs(((struct sockaddr_in *)them)->sin_port), + serveraddr, ntohs(us->ip4.sin_port), + xfd->para.socket.ip.libwrapname?xfd->para.socket.ip.libwrapname:(char *)diag_get_string('p')); + request_init(&ri, RQ_FILE, xfd->fd, + RQ_CLIENT_SIN, them, + RQ_SERVER_SIN, &us->soa, + RQ_DAEMON, xfd->para.socket.ip.libwrapname?xfd->para.socket.ip.libwrapname:(char *)diag_get_string('p'), 0); + Debug("request_init() ->"); + + Debug1("sock_methods(%p)", &ri); + sock_methods(&ri); + Debug("sock_methods() ->"); + + Debug1("hosts_access(%p)", &ri); + allow = hosts_access(&ri); + Debug1("hosts_access() -> %d", allow); + +#if defined(HAVE_HOSTS_ALLOW_TABLE) + hosts_allow_table = save_hosts_allow_table; +#endif +#if defined(HAVE_HOSTS_DENY_TABLE) + hosts_deny_table = save_hosts_deny_table; +#endif + if (allow == 0) { + return -1; + } + return 1; +} + +#endif /* (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */ + diff --git a/xio-tcpwrap.h b/xio-tcpwrap.h new file mode 100644 index 0000000..aaffc98 --- /dev/null +++ b/xio-tcpwrap.h @@ -0,0 +1,22 @@ +/* $Id: xio-tcpwrap.h,v 1.1 2006/05/12 21:00:00 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_tcpwrap_h_included +#define __xio_tcpwrap_h_included 1 + +#if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP + +extern const struct optdesc opt_tcpwrappers; +extern const struct optdesc opt_tcpwrap_etc; +extern const struct optdesc opt_tcpwrap_hosts_allow_table; +extern const struct optdesc opt_tcpwrap_hosts_deny_table; + +extern int xio_retropt_tcpwrap(xiosingle_t *xfd, struct opt *opts); +extern +int xio_tcpwrap_check(xiosingle_t *xfd, union sockaddr_union *us, + union sockaddr_union *them); + +#endif /* (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */ + +#endif /* !defined(__xio_tcpwrap_h_included) */ diff --git a/xio-termios.c b/xio-termios.c new file mode 100644 index 0000000..ff07001 --- /dev/null +++ b/xio-termios.c @@ -0,0 +1,326 @@ +/* $Id: xio-termios.c,v 1.18 2006/07/13 06:49:37 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for terminal I/O options */ + +#include "xiosysincludes.h" +#include "xioopen.h" + +#include "xio-termios.h" + +/****** TERMIOS addresses ******/ +#if WITH_TERMIOS +const struct optdesc opt_tiocsctty={ "tiocsctty", "ctty",OPT_TIOCSCTTY, GROUP_TERMIOS, PH_LATE2, TYPE_BOOL, OFUNC_SPEC }; + +const struct optdesc opt_brkint = { "brkint", NULL, OPT_BRKINT, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 0, BRKINT }; +const struct optdesc opt_icrnl = { "icrnl", NULL, OPT_ICRNL, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 0, ICRNL }; +const struct optdesc opt_ignbrk = { "ignbrk", NULL, OPT_IGNBRK, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 0, IGNBRK }; +const struct optdesc opt_igncr = { "igncr", NULL, OPT_IGNCR, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 0, IGNCR }; +const struct optdesc opt_ignpar = { "ignpar", NULL, OPT_IGNPAR, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 0, IGNPAR }; +const struct optdesc opt_imaxbel = { "imaxbel", NULL, OPT_IMAXBEL, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 0, IMAXBEL }; +const struct optdesc opt_inlcr = { "inlcr", NULL, OPT_INLCR, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 0, INLCR }; +const struct optdesc opt_inpck = { "inpck", NULL, OPT_INPCK, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 0, INPCK }; +const struct optdesc opt_istrip = { "istrip", NULL, OPT_ISTRIP, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 0, ISTRIP }; +#ifdef IUCLC +const struct optdesc opt_iuclc = { "iuclc", NULL, OPT_IUCLC, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 0, IUCLC }; +#endif +const struct optdesc opt_ixany = { "ixany", NULL, OPT_IXANY, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 0, IXANY }; +const struct optdesc opt_ixoff = { "ixoff", NULL, OPT_IXOFF, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 0, IXOFF }; +const struct optdesc opt_ixon = { "ixon", NULL, OPT_IXON, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 0, IXON }; +const struct optdesc opt_parmrk = { "parmrk", NULL, OPT_PARMRK, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 0, PARMRK }; + +#ifdef CRDLY +# ifdef CR0 +const struct optdesc opt_cr0 = { "cr0", NULL, OPT_CR0, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 1, CR0, CRDLY }; +# endif +# ifdef CR1 +const struct optdesc opt_cr1 = { "cr1", NULL, OPT_CR1, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 1, CR1, CRDLY }; +# endif +# ifdef CR2 +const struct optdesc opt_cr2 = { "cr2", NULL, OPT_CR2, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 1, CR2, CRDLY }; +# endif +# ifdef CR3 +const struct optdesc opt_cr3 = { "cr3", NULL, OPT_CR3, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 1, CR3, CRDLY }; +#endif +const struct optdesc opt_crdly = { "crdly", NULL, OPT_CRDLY, GROUP_TERMIOS, PH_FD, TYPE_UINT, OFUNC_TERMIOS_VALUE, 1, CRDLY, CRDLY_SHIFT }; +#endif /* defined(CRDLY) */ +#ifdef NLDLY +# ifdef NL0 +const struct optdesc opt_nl0 = { "nl0", NULL, OPT_NL0, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 1, NL0, NLDLY }; +# endif +# ifdef NL1 +const struct optdesc opt_nl1 = { "nl1", NULL, OPT_NL1, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 1, NL1, NLDLY }; +# endif +const struct optdesc opt_nldly = { "nldly", NULL, OPT_NLDLY, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 1, NLDLY }; +#endif /* defined(NLDLY) */ +#ifdef OCRNL +const struct optdesc opt_ocrnl = { "ocrnl", NULL, OPT_OCRNL, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 1, OCRNL }; +#endif +#ifdef OFDEL +const struct optdesc opt_ofdel = { "ofdel", NULL, OPT_OFDEL, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 1, OFDEL }; +#endif +#ifdef OFILL +const struct optdesc opt_ofill = { "ofill", NULL, OPT_OFILL, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 1, OFILL }; +#endif +const struct optdesc opt_opost = { "opost", NULL, OPT_OPOST, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 1, OPOST }; +#ifdef OLCUC +const struct optdesc opt_olcuc = { "olcuc", NULL, OPT_OLCUC, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 1, OLCUC }; +#endif +const struct optdesc opt_onlcr = { "onlcr", NULL, OPT_ONLCR, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 1, ONLCR }; +#ifdef ONLRET +const struct optdesc opt_onlret = { "onlret", NULL, OPT_ONLRET, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 1, ONLRET }; +#endif +#ifdef ONOCR +const struct optdesc opt_onocr = { "onocr", NULL, OPT_ONOCR, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 1, ONOCR }; +#endif +#ifdef TABDLY +# ifdef TAB0 +const struct optdesc opt_tab0 = { "tab0", NULL, OPT_TAB0, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_FLAG, 1, TAB0, TABDLY }; +# endif +# ifdef TAB1 +const struct optdesc opt_tab1 = { "tab1", NULL, OPT_TAB1, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_FLAG, 1, TAB1, TABDLY }; +# endif +# ifdef TAB2 +const struct optdesc opt_tab2 = { "tab2", NULL, OPT_TAB2, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_FLAG, 1, TAB2, TABDLY }; +# endif +# ifdef TAB3 +const struct optdesc opt_tab3 = { "tab3", NULL, OPT_TAB3, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_FLAG, 1, TAB3, TABDLY }; +# endif +# ifdef XTABS +const struct optdesc opt_xtabs = { "xtabs", NULL, OPT_XTABS, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_FLAG, 1, XTABS, TABDLY }; +# endif +const struct optdesc opt_tabdly = { "tabdly", NULL, OPT_TABDLY, GROUP_TERMIOS, PH_FD, TYPE_UINT, OFUNC_TERMIOS_VALUE, 1, TABDLY, TABDLY_SHIFT }; +#endif +#ifdef BSDLY +# ifdef BS0 +const struct optdesc opt_bs0 = { "bs0", NULL, OPT_BS0, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 1, BS0, BSDLY }; +#endif +# ifdef BS1 +const struct optdesc opt_bs1 = { "bs1", NULL, OPT_BS1, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 1, BS1, BSDLY }; +# endif +const struct optdesc opt_bsdly = { "bsdly", NULL, OPT_BSDLY, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 1, BSDLY }; +#endif +#ifdef VTDLY +# ifdef VT0 +const struct optdesc opt_vt0 = { "vt0", NULL, OPT_VT0, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 1, VT0, VTDLY }; +# endif +# ifdef VT1 +const struct optdesc opt_vt1 = { "vt1", NULL, OPT_VT1, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 1, VT1, VTDLY }; +# endif +const struct optdesc opt_vtdly = { "vtdly", NULL, OPT_VTDLY, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 1, VTDLY }; +#endif +#ifdef FFDLY +# ifdef FF0 +const struct optdesc opt_ff0 = { "ff0", NULL, OPT_FF0, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 1, FF0, FFDLY }; +# endif +# ifdef FF1 +const struct optdesc opt_ff1 = { "ff1", NULL, OPT_FF1, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 1, FF1, FFDLY }; +# endif +const struct optdesc opt_ffdly = { "ffdly", NULL, OPT_FFDLY, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 1, FFDLY }; +#endif + +#ifdef CBAUD +const struct optdesc opt_b0 = { "b0", NULL, OPT_B0, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B0, CBAUD }; +const struct optdesc opt_b50 = { "b50", NULL, OPT_B50, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B50, CBAUD }; +const struct optdesc opt_b75 = { "b75", NULL, OPT_B75, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B75, CBAUD }; +const struct optdesc opt_b110 = { "b110", NULL, OPT_B110, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B110, CBAUD }; +const struct optdesc opt_b134 = { "b134", NULL, OPT_B134, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B134, CBAUD }; +const struct optdesc opt_b150 = { "b150", NULL, OPT_B150, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B150, CBAUD }; +const struct optdesc opt_b200 = { "b200", NULL, OPT_B200, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B200, CBAUD }; +const struct optdesc opt_b300 = { "b300", NULL, OPT_B300, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B300, CBAUD }; +const struct optdesc opt_b600 = { "b600", NULL, OPT_B600, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B600, CBAUD }; +#ifdef B900 /* HP-UX */ +const struct optdesc opt_b900 = { "b900", NULL, OPT_B900, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B900, CBAUD }; +#endif +const struct optdesc opt_b1200 = { "b1200", NULL, OPT_B1200, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B1200, CBAUD }; +const struct optdesc opt_b1800 = { "b1800", NULL, OPT_B1800, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B1800, CBAUD }; +const struct optdesc opt_b2400 = { "b2400", NULL, OPT_B2400, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B2400, CBAUD }; +#ifdef B3600 /* HP-UX */ +const struct optdesc opt_b3600 = { "b3600", NULL, OPT_B3600, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B3600, CBAUD }; +#endif +const struct optdesc opt_b4800 = { "b4800", NULL, OPT_B4800, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B4800, CBAUD }; +#ifdef B7200 /* HP-UX */ +const struct optdesc opt_b7200 = { "b7200", NULL, OPT_B7200, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B7200, CBAUD }; +#endif +const struct optdesc opt_b9600 = { "b9600", NULL, OPT_B9600, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B9600, CBAUD }; +const struct optdesc opt_b19200 = { "b19200", NULL, OPT_B19200, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B19200, CBAUD }; +const struct optdesc opt_b38400 = { "b38400", NULL, OPT_B38400, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B38400, CBAUD }; +#ifdef B57600 +const struct optdesc opt_b57600 = { "b57600", NULL, OPT_B57600, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B57600, CBAUD }; +#endif +#ifdef B115200 +const struct optdesc opt_b115200 = { "b115200", NULL, OPT_B115200, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B115200, CBAUD }; +#endif +#ifdef B230400 +const struct optdesc opt_b230400 = { "b230400", NULL, OPT_B230400, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B230400, CBAUD }; +#endif +#ifdef B460800 +const struct optdesc opt_b460800 = { "b460800", NULL, OPT_B460800, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B460800, CBAUD }; +#endif +#ifdef B500000 +const struct optdesc opt_b500000 = { "b500000", NULL, OPT_B500000, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B500000, CBAUD }; +#endif +#ifdef B576000 +const struct optdesc opt_b576000 = { "b576000", NULL, OPT_B576000, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B576000, CBAUD }; +#endif +#ifdef B921600 +const struct optdesc opt_b921600 = { "b921600", NULL, OPT_B921600, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B921600, CBAUD }; +#endif +#ifdef B1000000 +const struct optdesc opt_b1000000= { "b1000000",NULL, OPT_B1000000,GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B1000000, CBAUD }; +#endif +#ifdef B1152000 +const struct optdesc opt_b1152000= { "b1152000",NULL, OPT_B1152000,GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B1152000, CBAUD }; +#endif +#ifdef B1500000 +const struct optdesc opt_b1500000= { "b1500000",NULL, OPT_B1500000,GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B1500000, CBAUD }; +#endif +#ifdef B2000000 +const struct optdesc opt_b2000000= { "b2000000",NULL, OPT_B2000000,GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B2000000, CBAUD }; +#endif +#ifdef B2500000 +const struct optdesc opt_b2500000= { "b2500000",NULL, OPT_B2500000,GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B2500000, CBAUD }; +#endif +#ifdef B3000000 +const struct optdesc opt_b3000000= { "b3000000",NULL, OPT_B3000000,GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B3000000, CBAUD }; +#endif +#ifdef B3500000 +const struct optdesc opt_b3500000= { "b3500000",NULL, OPT_B3500000,GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B3500000, CBAUD }; +#endif +#ifdef B4000000 +const struct optdesc opt_b4000000= { "b4000000",NULL, OPT_B4000000,GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, B4000000, CBAUD }; +#endif +#endif /* defined(CBAUD) */ +const struct optdesc opt_cs5 = { "cs5", NULL, OPT_CS5, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, CS5, CSIZE }; +const struct optdesc opt_cs6 = { "cs6", NULL, OPT_CS6, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, CS6, CSIZE }; +const struct optdesc opt_cs7 = { "cs7", NULL, OPT_CS7, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, CS7, CSIZE }; +const struct optdesc opt_cs8 = { "cs8", NULL, OPT_CS8, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_PATTERN, 2, CS8, CSIZE }; +const struct optdesc opt_csize = { "csize", NULL, OPT_CSIZE, GROUP_TERMIOS, PH_FD, TYPE_UINT, OFUNC_TERMIOS_VALUE, 2, CSIZE, CSIZE_SHIFT }; +const struct optdesc opt_cstopb = { "cstopb", NULL, OPT_CSTOPB, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 2, CSTOPB }; +const struct optdesc opt_cread = { "cread", NULL, OPT_CREAD, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 2, CREAD }; +const struct optdesc opt_parenb = { "parenb", NULL, OPT_PARENB, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 2, PARENB }; +const struct optdesc opt_parodd = { "parodd", NULL, OPT_PARODD, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 2, PARODD }; +const struct optdesc opt_hupcl = { "hupcl", NULL, OPT_HUPCL, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 2, HUPCL }; +const struct optdesc opt_clocal = { "clocal", NULL, OPT_CLOCAL, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 2, CLOCAL }; +/*const struct optdesc opt_cibaud = { "cibaud",NULL, OPT_CIBAUD, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 2, CIBAUD };*/ +#ifdef CRTSCTS +const struct optdesc opt_crtscts = { "crtscts", NULL, OPT_CRTSCTS, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 2, CRTSCTS }; +#endif + +const struct optdesc opt_isig = { "isig", NULL, OPT_ISIG, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 3, ISIG }; +const struct optdesc opt_icanon = { "icanon", NULL, OPT_ICANON, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 3, ICANON }; +#ifdef XCASE +const struct optdesc opt_xcase = { "xcase", NULL, OPT_XCASE, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 3, XCASE }; +#endif +const struct optdesc opt_echo = { "echo", NULL, OPT_ECHO, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 3, ECHO }; +const struct optdesc opt_echoe = { "echoe", NULL, OPT_ECHOE, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 3, ECHOE }; +const struct optdesc opt_echok = { "echok", NULL, OPT_ECHOK, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 3, ECHOK }; +const struct optdesc opt_echonl = { "echonl", NULL, OPT_ECHONL, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 3, ECHONL }; +const struct optdesc opt_echoctl = { "echoctl", NULL, OPT_ECHOCTL, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 3, ECHOCTL }; +#ifdef ECHOPRT +const struct optdesc opt_echoprt = { "echoprt", NULL, OPT_ECHOPRT, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 3, ECHOPRT }; +#endif +const struct optdesc opt_echoke = { "echoke", NULL, OPT_ECHOKE, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 3, ECHOKE }; +const struct optdesc opt_flusho = { "flusho", NULL, OPT_FLUSHO, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 3, FLUSHO }; +const struct optdesc opt_noflsh = { "noflsh", NULL, OPT_NOFLSH, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 3, NOFLSH }; +const struct optdesc opt_tostop = { "tostop", NULL, OPT_TOSTOP, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 3, TOSTOP }; +#ifdef PENDIN +const struct optdesc opt_pendin = { "pendin", NULL, OPT_PENDIN, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 3, PENDIN }; +#endif +const struct optdesc opt_iexten = { "iexten", NULL, OPT_IEXTEN, GROUP_TERMIOS, PH_FD, TYPE_BOOL, OFUNC_TERMIOS_FLAG, 3, IEXTEN }; + +const struct optdesc opt_vintr = { "vintr", "intr", OPT_VINTR, GROUP_TERMIOS, PH_FD, TYPE_BYTE, OFUNC_TERMIOS_CHAR, VINTR }; +const struct optdesc opt_vquit = { "vquit", "quit", OPT_VQUIT, GROUP_TERMIOS, PH_FD, TYPE_BYTE, OFUNC_TERMIOS_CHAR, VQUIT }; +const struct optdesc opt_verase = { "verase", "erase", OPT_VERASE, GROUP_TERMIOS, PH_FD, TYPE_BYTE, OFUNC_TERMIOS_CHAR, VERASE }; +const struct optdesc opt_vkill = { "vkill", "kill", OPT_VKILL, GROUP_TERMIOS, PH_FD, TYPE_BYTE, OFUNC_TERMIOS_CHAR, VKILL }; +const struct optdesc opt_veof = { "veof", "eof", OPT_VEOF, GROUP_TERMIOS, PH_FD, TYPE_BYTE, OFUNC_TERMIOS_CHAR, VEOF }; +const struct optdesc opt_vtime = { "vtime", "time", OPT_VTIME, GROUP_TERMIOS, PH_FD, TYPE_BYTE, OFUNC_TERMIOS_CHAR, VTIME }; +const struct optdesc opt_vmin = { "vmin", "min", OPT_VMIN, GROUP_TERMIOS, PH_FD, TYPE_BYTE, OFUNC_TERMIOS_CHAR, VMIN }; +#ifdef VSWTC +const struct optdesc opt_vswtc = { "vswtc", "swtc", OPT_VSWTC, GROUP_TERMIOS, PH_FD, TYPE_BYTE, OFUNC_TERMIOS_CHAR, VSWTC }; +#endif /* VSWTC */ +const struct optdesc opt_vstart = { "vstart", "start", OPT_VSTART, GROUP_TERMIOS, PH_FD, TYPE_BYTE, OFUNC_TERMIOS_CHAR, VSTART }; +const struct optdesc opt_vstop = { "vstop", "stop", OPT_VSTOP, GROUP_TERMIOS, PH_FD, TYPE_BYTE, OFUNC_TERMIOS_CHAR, VSTOP }; +const struct optdesc opt_vsusp = { "vsusp", "susp", OPT_VSUSP, GROUP_TERMIOS, PH_FD, TYPE_BYTE, OFUNC_TERMIOS_CHAR, VSUSP }; +#ifdef VDSUSP /* HP-UX */ +const struct optdesc opt_vdsusp = { "vdsusp", "dsusp", OPT_VDSUSP, GROUP_TERMIOS, PH_FD, TYPE_BYTE, OFUNC_TERMIOS_CHAR, VDSUSP }; +#endif +const struct optdesc opt_veol = { "veol", "eol", OPT_VEOL, GROUP_TERMIOS, PH_FD, TYPE_BYTE, OFUNC_TERMIOS_CHAR, VEOL }; +#ifdef VREPRINT +const struct optdesc opt_vreprint = { "vreprint","reprint",OPT_VREPRINT,GROUP_TERMIOS,PH_FD, TYPE_BYTE, OFUNC_TERMIOS_CHAR, VREPRINT }; +#endif +#ifdef VDISCARD +const struct optdesc opt_vdiscard = { "vdiscard","discard",OPT_VDISCARD,GROUP_TERMIOS,PH_FD, TYPE_BYTE, OFUNC_TERMIOS_CHAR, VDISCARD }; +#endif +#ifdef VWERASE +const struct optdesc opt_vwerase = { "vwerase","werase",OPT_VWERASE, GROUP_TERMIOS, PH_FD, TYPE_BYTE, OFUNC_TERMIOS_CHAR, VWERASE }; +#endif +const struct optdesc opt_vlnext = { "vlnext", "lnext", OPT_VLNEXT, GROUP_TERMIOS, PH_FD, TYPE_BYTE, OFUNC_TERMIOS_CHAR, VLNEXT }; +const struct optdesc opt_veol2 = { "veol2", "eol2", OPT_VEOL2, GROUP_TERMIOS, PH_FD, TYPE_BYTE, OFUNC_TERMIOS_CHAR, VEOL2 }; + +const struct optdesc opt_raw = { "raw", NULL, OPT_RAW, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_SPEC }; +const struct optdesc opt_sane = { "sane", NULL, OPT_SANE, GROUP_TERMIOS, PH_FD, TYPE_CONST, OFUNC_TERMIOS_SPEC }; + +#ifdef HAVE_TERMIOS_ISPEED +const struct optdesc opt_ispeed = { "ispeed", NULL, OPT_ISPEED, GROUP_TERMIOS, PH_FD, TYPE_UINT, OFUNC_TERMIOS_SPEED, ISPEED_OFFSET }; +const struct optdesc opt_ospeed = { "ospeed", NULL, OPT_OSPEED, GROUP_TERMIOS, PH_FD, TYPE_UINT, OFUNC_TERMIOS_SPEED, OSPEED_OFFSET }; +#endif /* HAVE_TERMIOS_ISPEED */ + + +int xiotermiosflag_applyopt(int fd, struct opt *opt) { + int result; + if (opt->value.u_bool) { + result = xiotermios_setflag(fd, opt->desc->major, opt->desc->minor); + } else { + result = xiotermios_clrflag(fd, opt->desc->major, opt->desc->minor); + } + if (result < 0) { + opt->desc = ODESC_ERROR; + return -1; + } + return 0; +} + +#endif /* WITH_TERMIOS */ + +int xiotermios_setflag(int fd, int word, tcflag_t mask) { + union { + struct termios termarg; + tcflag_t flags[4]; + } tdata; + + if (Tcgetattr(fd, &tdata.termarg) < 0) { + Error3("tcgetattr(%d, %p): %s", + fd, &tdata.termarg, strerror(errno)); + return -1; + } + tdata.flags[word] |= mask; + if (Tcsetattr(fd, TCSADRAIN, &tdata.termarg) < 0) { + Error3("tcsetattr(%d, TCSADRAIN, %p): %s", + fd, &tdata.termarg, strerror(errno)); + return -1; + } + return 0; +} + +int xiotermios_clrflag(int fd, int word, tcflag_t mask) { + union { + struct termios termarg; + tcflag_t flags[4]; + } tdata; + + if (Tcgetattr(fd, &tdata.termarg) < 0) { + Error3("tcgetattr(%d, %p): %s", + fd, &tdata.termarg, strerror(errno)); + return -1; + } + tdata.flags[word] &= ~mask; + if (Tcsetattr(fd, TCSADRAIN, &tdata.termarg) < 0) { + Error3("tcsetattr(%d, TCSADRAIN, %p): %s", + fd, &tdata.termarg, strerror(errno)); + return -1; + } + return 0; +} + diff --git a/xio-termios.h b/xio-termios.h new file mode 100644 index 0000000..8023346 --- /dev/null +++ b/xio-termios.h @@ -0,0 +1,147 @@ +/* $Id: xio-termios.h,v 1.11 2006/05/31 19:23:43 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_termios_h_included +#define __xio_termios_h_included 1 + +extern const struct optdesc opt_tiocsctty; + +extern const struct optdesc opt_brkint; +extern const struct optdesc opt_icrnl; +extern const struct optdesc opt_ignbrk; +extern const struct optdesc opt_igncr; +extern const struct optdesc opt_ignpar; +extern const struct optdesc opt_imaxbel; +extern const struct optdesc opt_inlcr; +extern const struct optdesc opt_inpck; +extern const struct optdesc opt_istrip; +extern const struct optdesc opt_iuclc; +extern const struct optdesc opt_ixany; +extern const struct optdesc opt_ixoff; +extern const struct optdesc opt_ixon; +extern const struct optdesc opt_parmrk; +extern const struct optdesc opt_cr0; +extern const struct optdesc opt_cr1; +extern const struct optdesc opt_cr2; +extern const struct optdesc opt_cr3; +extern const struct optdesc opt_crdly; +extern const struct optdesc opt_nl0; +extern const struct optdesc opt_nl1; +extern const struct optdesc opt_nldly; +extern const struct optdesc opt_ocrnl; +extern const struct optdesc opt_ofdel; +extern const struct optdesc opt_ofill; +extern const struct optdesc opt_opost; +extern const struct optdesc opt_olcuc; +extern const struct optdesc opt_onlcr; +extern const struct optdesc opt_onlret; +extern const struct optdesc opt_onocr; +extern const struct optdesc opt_tab0; +extern const struct optdesc opt_tab1; +extern const struct optdesc opt_tab2; +extern const struct optdesc opt_tab3; +extern const struct optdesc opt_xtabs; +extern const struct optdesc opt_tabdly; +extern const struct optdesc opt_bs0; +extern const struct optdesc opt_bs1; +extern const struct optdesc opt_bsdly; +extern const struct optdesc opt_vt0; +extern const struct optdesc opt_vt1; +extern const struct optdesc opt_vtdly; +extern const struct optdesc opt_ff0; +extern const struct optdesc opt_ff1; +extern const struct optdesc opt_ffdly; +extern const struct optdesc opt_b0; +extern const struct optdesc opt_b50; +extern const struct optdesc opt_b75; +extern const struct optdesc opt_b110; +extern const struct optdesc opt_b134; +extern const struct optdesc opt_b150; +extern const struct optdesc opt_b200; +extern const struct optdesc opt_b300; +extern const struct optdesc opt_b600; +extern const struct optdesc opt_b900; +extern const struct optdesc opt_b1200; +extern const struct optdesc opt_b1800; +extern const struct optdesc opt_b2400; +extern const struct optdesc opt_b3600; +extern const struct optdesc opt_b4800; +extern const struct optdesc opt_b7200; +extern const struct optdesc opt_b9600; +extern const struct optdesc opt_b19200; +extern const struct optdesc opt_b38400; +extern const struct optdesc opt_b57600; +extern const struct optdesc opt_b115200; +extern const struct optdesc opt_b230400; +extern const struct optdesc opt_b460800; +extern const struct optdesc opt_b500000; +extern const struct optdesc opt_b576000; +extern const struct optdesc opt_b921600; +extern const struct optdesc opt_b1000000; +extern const struct optdesc opt_b1152000; +extern const struct optdesc opt_b1500000; +extern const struct optdesc opt_b2000000; +extern const struct optdesc opt_b2500000; +extern const struct optdesc opt_b3000000; +extern const struct optdesc opt_b3500000; +extern const struct optdesc opt_b4000000; +extern const struct optdesc opt_cs5; +extern const struct optdesc opt_cs6; +extern const struct optdesc opt_cs7; +extern const struct optdesc opt_cs8; +extern const struct optdesc opt_csize; +extern const struct optdesc opt_cstopb; +extern const struct optdesc opt_cread; +extern const struct optdesc opt_parenb; +extern const struct optdesc opt_parodd; +extern const struct optdesc opt_hupcl; +extern const struct optdesc opt_clocal; +/*extern const struct optdesc opt_cibaud*/ +extern const struct optdesc opt_crtscts; +extern const struct optdesc opt_isig; +extern const struct optdesc opt_icanon; +extern const struct optdesc opt_xcase; +extern const struct optdesc opt_echo; +extern const struct optdesc opt_echoe; +extern const struct optdesc opt_echok; +extern const struct optdesc opt_echonl; +extern const struct optdesc opt_echoctl; +extern const struct optdesc opt_echoprt; +extern const struct optdesc opt_echoke; +extern const struct optdesc opt_flusho; +extern const struct optdesc opt_noflsh; +extern const struct optdesc opt_tostop; +extern const struct optdesc opt_pendin; +extern const struct optdesc opt_iexten; +extern const struct optdesc opt_vintr; +extern const struct optdesc opt_vquit; +extern const struct optdesc opt_verase; +extern const struct optdesc opt_vkill; +extern const struct optdesc opt_veof; +extern const struct optdesc opt_vtime; +extern const struct optdesc opt_vmin; +extern const struct optdesc opt_vswtc; +extern const struct optdesc opt_vstart; +extern const struct optdesc opt_vstop; +extern const struct optdesc opt_vsusp; +extern const struct optdesc opt_vdsusp; +extern const struct optdesc opt_veol; +extern const struct optdesc opt_vreprint; +extern const struct optdesc opt_vdiscard; +extern const struct optdesc opt_vwerase; +extern const struct optdesc opt_vlnext; +extern const struct optdesc opt_veol2; +extern const struct optdesc opt_raw; +extern const struct optdesc opt_sane; + +extern const struct optdesc opt_ispeed; +extern const struct optdesc opt_ospeed; + +#if WITH_TERMIOS /* otherwise tcflag_t might be reported undefined */ +extern int xiotermios_setflag(int fd, int word, tcflag_t mask); +extern int xiotermios_clrflag(int fd, int word, tcflag_t mask); +extern int xiotermiosflag_applyopt(int fd, struct opt *opt); +#endif /* WITH_TERMIOS */ + +#endif /* !defined(__xio_termios_h_included) */ diff --git a/xio-tun.c b/xio-tun.c new file mode 100644 index 0000000..2ed0f87 --- /dev/null +++ b/xio-tun.c @@ -0,0 +1,209 @@ +/* $Id: xio-tun.c,v 1.2 2007/03/06 21:13:35 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for opening addresses of tun/tap type */ + +#include "xiosysincludes.h" +#if WITH_TUN +#include "xioopen.h" + +#include "xio-named.h" +#include "xio-socket.h" +#include "xio-ip.h" + +#include "xio-tun.h" + + +static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); + +#define XIO_OFFSETOF(x) ((size_t)&((xiosingle_t *)0)->x) + +/****** TUN addresses ******/ +const struct optdesc opt_tun_device = { "tun-device", NULL, OPT_TUN_DEVICE, GROUP_TUN, PH_OPEN, TYPE_FILENAME, OFUNC_SPEC }; +const struct optdesc opt_tun_name = { "tun-name", NULL, OPT_TUN_NAME, GROUP_INTERFACE, PH_FD, TYPE_STRING, OFUNC_SPEC }; +const struct optdesc opt_tun_type = { "tun-type", NULL, OPT_TUN_TYPE, GROUP_INTERFACE, PH_FD, TYPE_STRING, OFUNC_SPEC }; +const struct optdesc opt_iff_no_pi = { "iff-no-pi", "no-pi", OPT_IFF_NO_PI, GROUP_TUN, PH_FD, TYPE_BOOL, OFUNC_SPEC }; +/*0 const struct optdesc opt_interface_addr = { "interface-addr", "address", OPT_INTERFACE_ADDR, GROUP_INTERFACE, PH_FD, TYPE_STRING, OFUNC_SPEC };*/ +/*0 const struct optdesc opt_interface_netmask = { "interface-netmask", "netmask", OPT_INTERFACE_NETMASK, GROUP_INTERFACE, PH_FD, TYPE_STRING, OFUNC_SPEC };*/ +const struct optdesc opt_iff_up = { "iff-up", "up", OPT_IFF_UP, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), sizeof(short), IFF_UP }; +const struct optdesc opt_iff_broadcast = { "iff-broadcast", NULL, OPT_IFF_BROADCAST, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), sizeof(short), IFF_BROADCAST }; +const struct optdesc opt_iff_debug = { "iff-debug" , NULL, OPT_IFF_DEBUG, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), sizeof(short), IFF_DEBUG }; +const struct optdesc opt_iff_loopback = { "iff-loopback" , "loopback", OPT_IFF_LOOPBACK, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), sizeof(short), IFF_LOOPBACK }; +const struct optdesc opt_iff_pointopoint = { "iff-pointopoint", "pointopoint",OPT_IFF_POINTOPOINT, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), sizeof(short), IFF_POINTOPOINT }; +const struct optdesc opt_iff_notrailers = { "iff-notrailers", "notrailers", OPT_IFF_NOTRAILERS, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), sizeof(short), IFF_NOTRAILERS }; +const struct optdesc opt_iff_running = { "iff-running", "running", OPT_IFF_RUNNING, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), sizeof(short), IFF_RUNNING }; +const struct optdesc opt_iff_noarp = { "iff-noarp", "noarp", OPT_IFF_NOARP, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), sizeof(short), IFF_NOARP }; +const struct optdesc opt_iff_promisc = { "iff-promisc", "promisc", OPT_IFF_PROMISC, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), sizeof(short), IFF_PROMISC }; +const struct optdesc opt_iff_allmulti = { "iff-allmulti", "allmulti", OPT_IFF_ALLMULTI, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), sizeof(short), IFF_ALLMULTI }; +const struct optdesc opt_iff_master = { "iff-master", "master", OPT_IFF_MASTER, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), sizeof(short), IFF_MASTER }; +const struct optdesc opt_iff_slave = { "iff-slave", "slave", OPT_IFF_SLAVE, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), sizeof(short), IFF_SLAVE }; +const struct optdesc opt_iff_multicast = { "iff-multicast", NULL, OPT_IFF_MULTICAST, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), sizeof(short), IFF_MULTICAST }; +const struct optdesc opt_iff_portsel = { "iff-portsel", "portsel", OPT_IFF_PORTSEL, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), sizeof(short), IFF_PORTSEL }; +const struct optdesc opt_iff_automedia = { "iff-automedia", "automedia", OPT_IFF_AUTOMEDIA, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), sizeof(short), IFF_AUTOMEDIA }; +/*const struct optdesc opt_iff_dynamic = { "iff-dynamic", "dynamic", OPT_IFF_DYNAMIC, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), sizeof(short), IFF_DYNAMIC };*/ +#if LATER +const struct optdesc opt_route = { "route", NULL, OPT_ROUTE, GROUP_INTERFACE, PH_INIT, TYPE_STRING, OFUNC_SPEC }; +#endif + +const struct addrdesc xioaddr_tun = { "tun", 3, xioopen_tun, GROUP_FD|GROUP_CHR|GROUP_NAMED|GROUP_OPEN|GROUP_TUN, 0, 0, 0 HELP(":/") }; +// "if-name"=tun3 +// "route"=address/netmask +// "ip6-route"=address/netmask +// "iff-broadcast" +// "iff-debug" +// "iff-promisc" +// see .../linux/if.h + + +#if LATER +/* sub options for route option */ +#define IFOPT_ROUTE 1 +static const struct optdesc opt_route_tos = { "route", NULL, IFOPT_ROUTE, }; +static const struct optname xio_route_options[] = { + {"tos", &xio_route_tos } +} ; +#endif + +static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3) { + char *tundevice = NULL; + char *tunname = NULL, *tuntype = NULL; + int pf = /*! PF_UNSPEC*/ PF_INET; + union xiorange_union network; + bool no_pi = false; + const char *namedargv[] = { "tun", NULL, NULL }; + int rw = (xioflags & XIO_ACCMODE); + bool exists; + struct ifreq ifr; + int sockfd; + char *ifaddr; + int result; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", + argv[0], argc-1); + } + + if (retropt_string(opts, OPT_TUN_DEVICE, &tundevice) != 0) { + tundevice = strdup("/dev/net/tun"); + } + + /*! socket option here? */ + retropt_socket_pf(opts, &pf); + + namedargv[1] = tundevice; + /* open the tun cloning device */ + if ((result = _xioopen_named_early(2, namedargv, xfd, groups, &exists, opts)) < 0) { + return result; + } + + /*========================= the tunnel interface =========================*/ + Notice("creating tunnel network interface"); + if ((result = _xioopen_open(tundevice, rw, opts)) < 0) + return result; + xfd->stream.fd = result; + + /* prepare configuration of the new network interface */ + memset(&ifr, 0,sizeof(ifr)); + + if (retropt_string(opts, OPT_TUN_NAME, &tunname) == 0) { + strncpy(ifr.ifr_name, tunname, IFNAMSIZ); + free(tunname); + } else { + ifr.ifr_name[0] = '\0'; + } + + ifr.ifr_flags = IFF_TUN; + if (retropt_string(opts, OPT_TUN_TYPE, &tuntype) == 0) { + if (!strcmp(tuntype, "tap")) { + ifr.ifr_flags = IFF_TAP; + } else if (strcmp(tuntype, "tun")) { + Error1("unknown tun-type \"%s\"", tuntype); + } + } + + 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 */ + } else { + ifr.ifr_flags &= ~IFF_NO_PI; +#endif + } + } + + if (Ioctl(xfd->stream.fd, TUNSETIFF, &ifr) < 0) { + Error3("ioctl(%d, TUNSETIFF, {\"%s\"}: %s", + xfd->stream.fd, ifr.ifr_name, strerror(errno)); + Close(xfd->stream.fd); + } + + /*===================== setting interface properties =====================*/ + + /* 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 = xfd->stream.fd; /* desparate fallback attempt */ + } + + /*--------------------- setting interface address and netmask ------------*/ + if ((ifaddr = strdup(argv[1])) == NULL) { + Error1("strdup(\"%s\"): out of memory", argv[1]); + return STAT_RETRYLATER; + } + if ((result = xioparsenetwork(ifaddr, pf, &network)) != STAT_OK) { + /*! recover */ + return result; + } + socket_init(pf, (union sockaddr_union *)&ifr.ifr_addr); + ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr = network.ip4.netaddr; + if (Ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) { + Error4("ioctl(%d, SIOCSIFADDR, {\"%s\", \"%s\"}: %s", + sockfd, ifr.ifr_name, ifaddr, strerror(errno)); + } + ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr = network.ip4.netmask; + if (Ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) { + Error4("ioctl(%d, SIOCSIFNETMASK, {\"0x%08u\", \"%s\"}, %s", + sockfd, ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr, + ifaddr, strerror(errno)); + } + free(ifaddr); + + /*--------------------- setting interface flags --------------------------*/ + applyopts_single(&xfd->stream, opts, PH_FD); + + if (Ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { + Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s", + sockfd, ifr.ifr_name, strerror(errno)); + } + Debug2("\"%s\": system set flags: 0x%hx", ifr.ifr_name, ifr.ifr_flags); + ifr.ifr_flags |= xfd->stream.para.tun.iff_opts[0]; + ifr.ifr_flags &= ~xfd->stream.para.tun.iff_opts[1]; + Debug2("\"%s\": xio merged flags: 0x%hx", ifr.ifr_name, ifr.ifr_flags); + if (Ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { + Error4("ioctl(%d, SIOCSIFFLAGS, {\"%s\", %hd}: %s", + sockfd, ifr.ifr_name, ifr.ifr_flags, strerror(errno)); + } + ifr.ifr_flags = 0; + if (Ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { + Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s", + sockfd, ifr.ifr_name, strerror(errno)); + } + Debug2("\"%s\": resulting flags: 0x%hx", ifr.ifr_name, ifr.ifr_flags); + + +#if LATER + applyopts_named(tundevice, opts, PH_FD); +#endif + applyopts(xfd->stream.fd, opts, PH_FD); + applyopts_cloexec(xfd->stream.fd, opts); + + applyopts_fchown(xfd->stream.fd, opts); + + if ((result = _xio_openlate(&xfd->stream, opts)) < 0) + return result; + + return 0; +} + +#endif /* WITH_TUN */ diff --git a/xio-tun.h b/xio-tun.h new file mode 100644 index 0000000..53eb6c8 --- /dev/null +++ b/xio-tun.h @@ -0,0 +1,33 @@ +/* $Id: xio-tun.h,v 1.2 2007/03/06 21:19:18 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2006-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_tun_h_included +#define __xio_tun_h_included 1 + +extern const struct optdesc opt_tun_device; +extern const struct optdesc opt_tun_name; +extern const struct optdesc opt_tun_type; +extern const struct optdesc opt_iff_no_pi; +extern const struct optdesc opt_interface_addr; +extern const struct optdesc opt_interface_netmask; +extern const struct optdesc opt_iff_up; +extern const struct optdesc opt_iff_broadcast; +extern const struct optdesc opt_iff_debug; +extern const struct optdesc opt_iff_loopback; +extern const struct optdesc opt_iff_pointopoint; +extern const struct optdesc opt_iff_notrailers; +extern const struct optdesc opt_iff_running; +extern const struct optdesc opt_iff_noarp; +extern const struct optdesc opt_iff_promisc; +extern const struct optdesc opt_iff_allmulti; +extern const struct optdesc opt_iff_master; +extern const struct optdesc opt_iff_slave; +extern const struct optdesc opt_iff_multicast; +extern const struct optdesc opt_iff_portsel; +extern const struct optdesc opt_iff_automedia; +/*extern const struct optdesc opt_iff_dynamic;*/ + +extern const struct addrdesc xioaddr_tun; + +#endif /* !defined(__xio_tun_h_included) */ diff --git a/xio-udp.c b/xio-udp.c new file mode 100644 index 0000000..4a23b3d --- /dev/null +++ b/xio-udp.c @@ -0,0 +1,608 @@ +/* $Id: xio-udp.c,v 1.36 2007/02/08 18:27:00 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for handling UDP addresses */ + +#include "xiosysincludes.h" + +#if WITH_UDP && (WITH_IP4 || WITH_IP6) + +#include "xioopen.h" +#include "xio-socket.h" +#include "xio-ip4.h" +#include "xio-ip6.h" +#include "xio-ip.h" +#include "xio-ipapp.h" +#include "xio-tcpwrap.h" + +#include "xio-udp.h" + + +static +int xioopen_udp_sendto(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xfd, unsigned groups, + int pf, int socktype, int ipproto); +static +int xioopen_udp_datagram(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xfd, unsigned groups, + int pf, int socktype, int ipproto); +static +int xioopen_udp_recvfrom(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xfd, unsigned groups, + int pf, int socktype, int ipproto); +static +int xioopen_udp_recv(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xfd, unsigned groups, + int pf, int socktype, int ipproto); + +static +int _xioopen_udp_sendto(const char *hostname, const char *servname, + struct opt *opts, + int xioflags, xiofile_t *xxfd, unsigned groups, + int pf, int socktype, int ipproto); + +const struct addrdesc addr_udp_connect = { "udp-connect", 3, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP, SOCK_DGRAM, IPPROTO_UDP, PF_UNSPEC HELP("::") }; +#if WITH_LISTEN +const struct addrdesc addr_udp_listen = { "udp-listen", 3, xioopen_ipdgram_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE, PF_UNSPEC, IPPROTO_UDP, PF_UNSPEC HELP(":") }; +#endif /* WITH_LISTEN */ +const struct addrdesc addr_udp_sendto = { "udp-sendto", 3, xioopen_udp_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP, PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP HELP("::") }; +const struct addrdesc addr_udp_recvfrom = { "udp-recvfrom", 3, xioopen_udp_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_CHILD|GROUP_RANGE, PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP HELP(":") }; +const struct addrdesc addr_udp_recv = { "udp-recv", 1, xioopen_udp_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_RANGE, PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP HELP(":") }; +const struct addrdesc addr_udp_datagram = { "udp-datagram", 3, xioopen_udp_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_RANGE, PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP HELP("::") }; + +#if WITH_IP4 +const struct addrdesc addr_udp4_connect = { "udp4-connect", 3, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP, SOCK_DGRAM, IPPROTO_UDP, PF_INET HELP("::") }; +#if WITH_LISTEN +const struct addrdesc addr_udp4_listen = { "udp4-listen", 3, xioopen_ipdgram_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE, PF_INET, IPPROTO_UDP, PF_INET HELP(":") }; +#endif /* WITH_LISTEN */ +const struct addrdesc addr_udp4_sendto = { "udp4-sendto", 3, xioopen_udp_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP, PF_INET, SOCK_DGRAM, IPPROTO_UDP HELP("::") }; +const struct addrdesc addr_udp4_datagram = { "udp4-datagram",3, xioopen_udp_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP|GROUP_RANGE, PF_INET, SOCK_DGRAM, IPPROTO_UDP HELP("::") }; +const struct addrdesc addr_udp4_recvfrom= { "udp4-recvfrom", 3, xioopen_udp_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP|GROUP_CHILD|GROUP_RANGE, PF_INET, SOCK_DGRAM, IPPROTO_UDP HELP("::") }; +const struct addrdesc addr_udp4_recv = { "udp4-recv", 1, xioopen_udp_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_UDP|GROUP_RANGE, PF_INET, SOCK_DGRAM, IPPROTO_UDP HELP(":") }; +#endif /* WITH_IP4 */ + +#if WITH_IP6 +const struct addrdesc addr_udp6_connect = { "udp6-connect", 3, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP, SOCK_DGRAM, IPPROTO_UDP, PF_INET6 HELP("::") }; +#if WITH_LISTEN +const struct addrdesc addr_udp6_listen = { "udp6-listen", 3, xioopen_ipdgram_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE, PF_INET6, IPPROTO_UDP, 0 HELP(":") }; +#endif /* WITH_LISTEN */ +const struct addrdesc addr_udp6_sendto = { "udp6-sendto", 3, xioopen_udp_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP, PF_INET6, SOCK_DGRAM, IPPROTO_UDP HELP("::") }; +const struct addrdesc addr_udp6_datagram= { "udp6-datagram", 3, xioopen_udp_datagram,GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_RANGE, PF_INET6, SOCK_DGRAM, IPPROTO_UDP HELP("::") }; +const struct addrdesc addr_udp6_recvfrom= { "udp6-recvfrom", 3, xioopen_udp_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_CHILD|GROUP_RANGE, PF_INET6, SOCK_DGRAM, IPPROTO_UDP HELP(":") }; +const struct addrdesc addr_udp6_recv = { "udp6-recv", 1, xioopen_udp_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_RANGE, PF_INET6, SOCK_DGRAM, IPPROTO_UDP HELP(":") }; +#endif /* WITH_IP6 */ + + +/* we expect the form: port */ +int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *fd, + unsigned groups, int pf, int ipproto, + int protname) { + const char *portname = argv[1]; + union sockaddr_union us; + union sockaddr_union themunion; + union sockaddr_union *them = &themunion; + int socktype = SOCK_DGRAM; + fd_set in, out, expt; + bool dofork = false; + pid_t pid; + char *rangename; + char infobuff[256]; + unsigned char buff1[1]; + socklen_t uslen; + socklen_t themlen; + int result; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1); + } + + if (pf == PF_UNSPEC) { +#if WITH_IP4 && WITH_IP6 + pf = xioopts.default_ip=='6'?PF_INET6:PF_INET; +#elif WITH_IP6 + pf = PF_INET6; +#else + pf = PF_INET; +#endif + } + + retropt_socket_pf(opts, &pf); + + if (applyopts_single(&fd->stream, opts, PH_INIT) < 0) return -1; + applyopts(-1, opts, PH_INIT); + + uslen = socket_init(pf, &us); + retropt_int(opts, OPT_SO_TYPE, &socktype); + retropt_bind(opts, pf, socktype, IPPROTO_UDP, + (struct sockaddr *)&us, &uslen, 1, + fd->stream.para.socket.ip.res_opts[1], + fd->stream.para.socket.ip.res_opts[0]); + + if (false) { + ; +#if WITH_IP4 + } else if (pf == PF_INET) { + us.ip4.sin_port = parseport(portname, ipproto); +#endif +#if WITH_IP6 + } else if (pf == PF_INET6) { + us.ip6.sin6_port = parseport(portname, ipproto); +#endif + } else { + Error1("xioopen_ipdgram_listen(): unknown address family %d", pf); + } + + retropt_bool(opts, OPT_FORK, &dofork); + + if (dofork) { + if (!(xioflags & XIO_MAYFORK)) { + Error("option fork not allowed here"); + return STAT_NORETRY; + } + } + +#if WITH_IP4 /*|| WITH_IP6*/ + if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { + if (parserange(rangename, pf, &fd->stream.para.socket.range) < 0) { + free(rangename); + return STAT_NORETRY; + } + free(rangename); + fd->stream.para.socket.dorange = true; + } +#endif + +#if WITH_LIBWRAP + xio_retropt_tcpwrap(&fd->stream, opts); +#endif /* WITH_LIBWRAP */ + + if (retropt_ushort(opts, OPT_SOURCEPORT, &fd->stream.para.socket.ip.sourceport) + >= 0) { + fd->stream.para.socket.ip.dosourceport = true; + } + retropt_bool(opts, OPT_LOWPORT, &fd->stream.para.socket.ip.lowport); + + while (true) { /* we loop with fork or prohibited packets */ + /* now wait for some packet on this datagram socket, get its sender + address, connect there, and return */ + int one = 1; + char infobuff[256]; + union sockaddr_union _sockname; + union sockaddr_union *la = &_sockname; /* local address */ + + if ((fd->stream.fd = Socket(pf, socktype, ipproto)) < 0) { + Error4("socket(%d, %d, %d): %s", pf, socktype, ipproto, strerror(errno)); + return STAT_RETRYLATER; + } + applyopts(fd->stream.fd, opts, PH_PASTSOCKET); + if (Setsockopt(fd->stream.fd, opt_so_reuseaddr.major, + opt_so_reuseaddr.minor, &one, sizeof(one)) < 0) { + Warn6("setsockopt(%d, %d, %d, {%d}, "F_Zd"): %s", + fd->stream.fd, opt_so_reuseaddr.major, + opt_so_reuseaddr.minor, one, sizeof(one), strerror(errno)); + } + applyopts_cloexec(fd->stream.fd, opts); + applyopts(fd->stream.fd, opts, PH_PREBIND); + applyopts(fd->stream.fd, opts, PH_BIND); + if (Bind(fd->stream.fd, &us.soa, uslen) < 0) { + Error4("bind(%d, {%s}, "F_Zd"): %s", fd->stream.fd, + sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)), + uslen, strerror(errno)); + return STAT_RETRYLATER; + } + /* under some circumstances bind() fills sockaddr with interesting info. */ + if (Getsockname(fd->stream.fd, &us.soa, &uslen) < 0) { + Error4("getsockname(%d, %p, {%d}): %s", + fd->stream.fd, &us.soa, uslen, strerror(errno)); + } + applyopts(fd->stream.fd, opts, PH_PASTBIND); + + Notice1("listening on UDP %s", + sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff))); + FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt); + FD_SET(fd->stream.fd, &in); + while (Select(fd->stream.fd+1, &in, &out, &expt, NULL) < 0) { + if (errno != EINTR) break; + } + + themlen = socket_init(pf, them); + do { + result = Recvfrom(fd->stream.fd, buff1, 1, MSG_PEEK, + &them->soa, &themlen); + } while (result < 0 && errno == EINTR); + if (result < 0) { + Error5("recvfrom(%d, %p, 1, MSG_PEEK, {%s}, {"F_Zu"}): %s", + fd->stream.fd, buff1, + sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)), + themlen, strerror(errno)); + return STAT_RETRYLATER; + } + + Notice1("accepting UDP connection from %s", + sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff))); + + if (xiocheckpeer(&fd->stream, them, la) < 0) { + /* drop packet */ + char buff[512]; + Recv(fd->stream.fd, buff, sizeof(buff), 0); + continue; + } + Info1("permitting UDP connection from %s", + sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff))); + + if (dofork) { + pid = Fork(); + if (pid < 0) { + Error1("fork(): %s", strerror(errno)); + return STAT_RETRYLATER; + } + if (pid == 0) { /* child */ + + /* drop parents locks, reset FIPS... */ + if (xio_forked_inchild() != 0) { + Exit(1); + } + break; + } + /* server: continue loop with select */ + /* when we dont close this we get awkward behaviour on Linux 2.4: + recvfrom gives 0 bytes with invalid socket address */ + if (Close(fd->stream.fd) < 0) { + Info2("close(%d): %s", fd->stream.fd, strerror(errno)); + } + Notice1("forked off child process "F_pid, pid); + Sleep(1); /*! give child a chance to consume the old packet */ + + continue; + } + break; + } + + applyopts(fd->stream.fd, opts, PH_CONNECT); + if ((result = Connect(fd->stream.fd, &them->soa, themlen)) < 0) { + Error4("connect(%d, {%s}, "F_Zd"): %s", + fd->stream.fd, + sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)), + themlen, strerror(errno)); + return STAT_RETRYLATER; + } + + fd->stream.howtoend = END_SHUTDOWN; + applyopts_fchown(fd->stream.fd, opts); + applyopts(fd->stream.fd, opts, PH_LATE); + + if ((result = _xio_openlate(&fd->stream, opts)) < 0) + return result; + + return 0; +} + + +static +int xioopen_udp_sendto(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xxfd, unsigned groups, + int pf, int socktype, int ipproto) { + int result; + + if (argc != 3) { + Error2("%s: wrong number of parameters (%d instead of 2)", + argv[0], argc-1); + return STAT_NORETRY; + } + if ((result = _xioopen_udp_sendto(argv[1], argv[2], opts, xioflags, xxfd, + groups, pf, socktype, ipproto)) + != STAT_OK) { + return result; + } + _xio_openlate(&xxfd->stream, opts); + return STAT_OK; +} + +static +int _xioopen_udp_sendto(const char *hostname, const char *servname, + struct opt *opts, + int xioflags, xiofile_t *xxfd, unsigned groups, + int pf, int socktype, int ipproto) { + xiosingle_t *xfd = &xxfd->stream; + union sockaddr_union us; + socklen_t uslen; + int feats = 3; /* option bind supports address and port */ + bool needbind = false; + int result; + + xfd->howtoend = END_SHUTDOWN; + retropt_int(opts, OPT_SO_TYPE, &socktype); + + /* ...res_opts[] */ + if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; + applyopts(-1, opts, PH_INIT); + + xfd->salen = sizeof(xfd->peersa); + if ((result = + xiogetaddrinfo(hostname, servname, pf, socktype, ipproto, + &xfd->peersa, &xfd->salen, + xfd->para.socket.ip.res_opts[0], + xfd->para.socket.ip.res_opts[1])) + != STAT_OK) { + return result; + } + if (pf == PF_UNSPEC) { + pf = xfd->peersa.soa.sa_family; + } + uslen = socket_init(pf, &us); + if (retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, feats, + xfd->para.socket.ip.res_opts[0], + xfd->para.socket.ip.res_opts[1]) + != STAT_NOACTION) { + needbind = true; + } + + if (retropt_ushort(opts, OPT_SOURCEPORT, + &xfd->para.socket.ip.sourceport) >= 0) { + switch (pf) { +#if WITH_IP4 + case PF_INET: + us.ip4.sin_port = htons(xfd->para.socket.ip.sourceport); + break; +#endif +#if WITH_IP6 + case PF_INET6: + us.ip6.sin6_port = htons(xfd->para.socket.ip.sourceport); + break; +#endif + } + needbind = true; + } + + retropt_bool(opts, OPT_LOWPORT, &xfd->para.socket.ip.lowport); + if (xfd->para.socket.ip.lowport) { + switch (pf) { +#if WITH_IP4 + case PF_INET: + /*!!! this is buggy */ + us.ip4.sin_port = htons(xfd->para.socket.ip.lowport); break; +#endif +#if WITH_IP6 + case PF_INET6: + /*!!! this is buggy */ + us.ip6.sin6_port = htons(xfd->para.socket.ip.lowport); break; +#endif + } + needbind = true; + } + + xfd->dtype = XIODATA_RECVFROM; + return _xioopen_dgram_sendto(needbind?&us:NULL, uslen, + opts, xioflags, xfd, groups, + pf, socktype, ipproto); +} + + +static +int xioopen_udp_datagram(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xxfd, unsigned groups, + int pf, int socktype, int ipproto) { + xiosingle_t *xfd = &xxfd->stream; + char *rangename; + char *hostname; + int result; + + if (argc != 3) { + Error2("%s: wrong number of parameters (%d instead of 2)", + argv[0], argc-1); + return STAT_NORETRY; + } + + if ((hostname = strdup(argv[1])) == NULL) { + Error1("strdup(\"%s\"): out of memory", argv[1]); + return STAT_RETRYLATER; + } + + result = + _xioopen_udp_sendto(hostname, argv[2], opts, xioflags, xxfd, groups, + pf, socktype, ipproto); + free(hostname); + if (result != STAT_OK) { + return result; + } + + xfd->dtype = XIOREAD_RECV|XIOWRITE_SENDTO; + + xfd->para.socket.la.soa.sa_family = xfd->peersa.soa.sa_family; + + /* only accept packets with correct remote ports */ + xfd->para.socket.ip.sourceport = ntohs(xfd->peersa.ip4.sin_port); + xfd->para.socket.ip.dosourceport = true; + + /* which reply packets will be accepted - determine by range option */ + if (retropt_string(opts, OPT_RANGE, &rangename) + >= 0) { + if (parserange(rangename, pf, &xfd->para.socket.range) < 0) { + free(rangename); + return STAT_NORETRY; + } + xfd->para.socket.dorange = true; + xfd->dtype |= XIOREAD_RECV_CHECKRANGE; + free(rangename); + } + +#if WITH_LIBWRAP + xio_retropt_tcpwrap(xfd, opts); +#endif /* WITH_LIBWRAP */ + + _xio_openlate(xfd, opts); + return STAT_OK; +} + + +static +int xioopen_udp_recvfrom(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xfd, unsigned groups, + int pf, int socktype, int ipproto) { + union sockaddr_union us; + socklen_t uslen = sizeof(us); + bool needbind = false; + int result; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", + argv[0], argc-1); + return STAT_NORETRY; + } + + xfd->stream.howtoend = END_NONE; + retropt_socket_pf(opts, &pf); + if (pf == PF_UNSPEC) { +#if WITH_IP4 && WITH_IP6 + pf = xioopts.default_ip=='6'?PF_INET6:PF_INET; +#elif WITH_IP6 + pf = PF_INET6; +#else + pf = PF_INET; +#endif + } + + if ((result = + xiogetaddrinfo(NULL, argv[1], pf, socktype, ipproto, + &us, &uslen, xfd->stream.para.socket.ip.res_opts[0], + xfd->stream.para.socket.ip.res_opts[1])) + != STAT_OK) { + return result; + } + if (pf == PF_UNSPEC) { + pf = us.soa.sa_family; + } + + { + union sockaddr_union la; + socklen_t lalen = sizeof(la); + + if (retropt_bind(opts, pf, socktype, ipproto, &la.soa, &lalen, 1, + xfd->stream.para.socket.ip.res_opts[0], + xfd->stream.para.socket.ip.res_opts[1]) + != STAT_NOACTION) { + switch (pf) { +#if WITH_IP4 + case PF_INET: us.ip4.sin_addr = la.ip4.sin_addr; break; +#endif +#if WITH_IP6 + case PF_INET6: us.ip6.sin6_addr = la.ip6.sin6_addr; break; +#endif + } + needbind = true; + } + } + + if (retropt_ushort(opts, OPT_SOURCEPORT, &xfd->stream.para.socket.ip.sourceport) >= 0) { + xfd->stream.para.socket.ip.dosourceport = true; + } + retropt_bool(opts, OPT_LOWPORT, &xfd->stream.para.socket.ip.lowport); + + xfd->stream.dtype = XIODATA_RECVFROM_ONE; + if ((result = + _xioopen_dgram_recvfrom(&xfd->stream, xioflags, &us.soa, uslen, + opts, pf, socktype, ipproto, E_ERROR)) + != STAT_OK) { + return result; + } + _xio_openlate(&xfd->stream, opts); + return STAT_OK; +} + + +static +int xioopen_udp_recv(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xfd, unsigned groups, + int pf, int socktype, int ipproto) { + union sockaddr_union us; + socklen_t uslen = sizeof(us); + char *rangename; + int result; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", + argv[0], argc-1); + return STAT_NORETRY; + } + + retropt_socket_pf(opts, &pf); + if (pf == PF_UNSPEC) { +#if WITH_IP4 && WITH_IP6 + pf = xioopts.default_ip=='6'?PF_INET6:PF_INET; +#elif WITH_IP6 + pf = PF_INET6; +#else + pf = PF_INET; +#endif + } + + if ((result = + xiogetaddrinfo(NULL, argv[1], pf, socktype, ipproto, + &us, &uslen, xfd->stream.para.socket.ip.res_opts[0], + xfd->stream.para.socket.ip.res_opts[1])) + != STAT_OK) { + return result; + } + if (pf == PF_UNSPEC) { + pf = us.soa.sa_family; + } + +#if 1 + { + union sockaddr_union la; + socklen_t lalen = sizeof(la); + + if (retropt_bind(opts, pf, socktype, ipproto, + &xfd->stream.para.socket.la.soa, &lalen, 1, + xfd->stream.para.socket.ip.res_opts[0], + xfd->stream.para.socket.ip.res_opts[1]) + != STAT_NOACTION) { + switch (pf) { +#if WITH_IP4 + case PF_INET: + us.ip4.sin_addr = xfd->stream.para.socket.la.ip4.sin_addr; break; +#endif +#if WITH_IP6 + case PF_INET6: + us.ip6.sin6_addr = xfd->stream.para.socket.la.ip6.sin6_addr; break; +#endif + } + } else { + xfd->stream.para.socket.la.soa.sa_family = pf; + } + } +#endif + +#if WITH_IP4 /*|| WITH_IP6*/ + if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { + if (parserange(rangename, pf, &xfd->stream.para.socket.range) < 0) { + return STAT_NORETRY; + } + xfd->stream.para.socket.dorange = true; + } +#endif + +#if WITH_LIBWRAP + xio_retropt_tcpwrap(&xfd->stream, opts); +#endif /* WITH_LIBWRAP */ + + if (retropt_ushort(opts, OPT_SOURCEPORT, + &xfd->stream.para.socket.ip.sourceport) + >= 0) { + xfd->stream.para.socket.ip.dosourceport = true; + } + retropt_bool(opts, OPT_LOWPORT, &xfd->stream.para.socket.ip.lowport); + + xfd->stream.dtype = XIODATA_RECV; + if ((result = _xioopen_dgram_recv(&xfd->stream, xioflags, &us.soa, uslen, + opts, pf, socktype, ipproto, E_ERROR)) + != STAT_OK) { + return result; + } + _xio_openlate(&xfd->stream, opts); + return result; +} + +#endif /* WITH_UDP && (WITH_IP4 || WITH_IP6) */ diff --git a/xio-udp.h b/xio-udp.h new file mode 100644 index 0000000..3ccf0dd --- /dev/null +++ b/xio-udp.h @@ -0,0 +1,32 @@ +/* $Id: xio-udp.h,v 1.12 2007/02/05 19:57:09 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_udp_h_included +#define __xio_udp_h_included 1 + +extern const struct addrdesc addr_udp_connect; +extern const struct addrdesc addr_udp_listen; +extern const struct addrdesc addr_udp_sendto; +extern const struct addrdesc addr_udp_datagram; +extern const struct addrdesc addr_udp_recvfrom; +extern const struct addrdesc addr_udp_recv; +extern const struct addrdesc addr_udp4_connect; +extern const struct addrdesc addr_udp4_listen; +extern const struct addrdesc addr_udp4_sendto; +extern const struct addrdesc addr_udp4_datagram; +extern const struct addrdesc addr_udp4_recvfrom; +extern const struct addrdesc addr_udp4_recv; +extern const struct addrdesc addr_udp6_connect; +extern const struct addrdesc addr_udp6_listen; +extern const struct addrdesc addr_udp6_sendto; +extern const struct addrdesc addr_udp6_datagram; +extern const struct addrdesc addr_udp6_recvfrom; +extern const struct addrdesc addr_udp6_recv; + +extern int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, + int rw, xiofile_t *fd, + unsigned groups, int af, int ipproto, + int protname); + +#endif /* !defined(__xio_udp_h_included) */ diff --git a/xio-unix.c b/xio-unix.c new file mode 100644 index 0000000..c0d9ecb --- /dev/null +++ b/xio-unix.c @@ -0,0 +1,738 @@ +/* $Id: xio-unix.c,v 1.34 2007/03/06 21:25:12 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for opening addresses of UNIX socket type */ + +#include "xiosysincludes.h" +#include "xioopen.h" + +#include "xio-socket.h" +#include "xio-listen.h" +#include "xio-unix.h" +#include "xio-named.h" + + +#if WITH_UNIX + +static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); +static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); +static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int dummy2, int dummy3); +static int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3); +static +int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xfd, unsigned groups, + int pf, int socktype, int ipproto); +static +int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3); + +#if WITH_ABSTRACT_UNIXSOCKET +static int xioopen_abstract_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); +static int xioopen_abstract_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); +static int xioopen_abstract_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int dummy2, int dummy3); +static int xioopen_abstract_recvfrom(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3); +static +int xioopen_abstract_recv(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xfd, unsigned groups, + int pf, int socktype, int ipproto); +static +int xioopen_abstract_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3); +#endif /* WITH_ABSTRACT_UNIXSOCKET */ + +const struct addrdesc addr_unix_connect = { "unix-connect", 3, xioopen_unix_connect, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, SOCK_STREAM, 0 HELP(":") }; +#if WITH_LISTEN +const struct addrdesc addr_unix_listen = { "unix-listen", 3, xioopen_unix_listen, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, 0, SOCK_STREAM, 0 HELP(":") }; +#endif /* WITH_LISTEN */ +const struct addrdesc addr_unix_sendto = { "unix-sendto", 3, xioopen_unix_sendto, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, SOCK_DGRAM, 0 HELP(":") }; +const struct addrdesc addr_unix_recvfrom= { "unix-recvfrom", 3, xioopen_unix_recvfrom, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY|GROUP_CHILD, PF_UNIX, SOCK_DGRAM, 0 HELP(":") }; +const struct addrdesc addr_unix_recv = { "unix-recv", 1, xioopen_unix_recv, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, PF_UNIX, SOCK_DGRAM, 0 HELP(":") }; +const struct addrdesc addr_unix_client = { "unix-client", 3, xioopen_unix_client, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, PF_UNIX, 0, 0 HELP(":") }; +#if WITH_ABSTRACT_UNIXSOCKET +const struct addrdesc xioaddr_abstract_connect = { "abstract-connect", 3, xioopen_abstract_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, SOCK_STREAM, 0 HELP(":") }; +#if WITH_LISTEN +const struct addrdesc xioaddr_abstract_listen = { "abstract-listen", 3, xioopen_abstract_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, 0, SOCK_STREAM, 0 HELP(":") }; +#endif /* WITH_LISTEN */ +const struct addrdesc xioaddr_abstract_sendto = { "abstract-sendto", 3, xioopen_abstract_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, SOCK_DGRAM, 0 HELP(":") }; +const struct addrdesc xioaddr_abstract_recvfrom= { "abstract-recvfrom", 3, xioopen_abstract_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY|GROUP_CHILD, PF_UNIX, SOCK_DGRAM, 0 HELP(":") }; +const struct addrdesc xioaddr_abstract_recv = { "abstract-recv", 1, xioopen_abstract_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, PF_UNIX, SOCK_DGRAM, 0 HELP(":") }; +const struct addrdesc xioaddr_abstract_client = { "abstract-client", 3, xioopen_abstract_client, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, PF_UNIX, 0, 0 HELP(":") }; +#endif /* WITH_ABSTRACT_UNIXSOCKET */ + +const struct optdesc opt_unix_tightsocklen = { "unix-tightsocklen", "tightsocklen", OPT_UNIX_TIGHTSOCKLEN, GROUP_SOCK_UNIX, PH_INIT, TYPE_BOOL, OFUNC_SPEC, 0, 0 }; + + +socklen_t +xiosetunix(struct sockaddr_un *saun, + const char *path, + bool abstract, + bool tight) { + size_t pathlen; + socklen_t len; + + if (!abstract) { + if ((pathlen = strlen(path)) > sizeof(saun->sun_path)) { + Warn2("unix socket address "F_Zu" characters long, truncating to "F_Zu"", + pathlen, sizeof(saun->sun_path)); + } + strncpy(saun->sun_path, path, sizeof(saun->sun_path)); + if (tight) { + len = sizeof(struct sockaddr_un)-sizeof(saun->sun_path)+ + MIN(pathlen, sizeof(saun->sun_path)); + } else { + len = sizeof(struct sockaddr_un); + } + } else { + if ((pathlen = strlen(path)) >= sizeof(saun->sun_path)) { + Warn2("socket address "F_Zu" characters long, truncating to "F_Zu"", + pathlen+1, sizeof(saun->sun_path)); + } + saun->sun_path[0] = '\0'; /* so it's abstract */ + strncpy(saun->sun_path+1, path, sizeof(saun->sun_path)-1); + if (tight) { + len = sizeof(struct sockaddr_un)-sizeof(saun->sun_path)+ + MIN(pathlen+1, sizeof(saun->sun_path)); + } else { + len = sizeof(struct sockaddr_un); + } + } + return len; +} + +#if WITH_LISTEN +static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) { + /* we expect the form: filename */ + const char *name; + xiosingle_t *xfd = &xxfd->stream; + struct sockaddr_un us; + socklen_t uslen; + bool tight = true; + struct opt *opts0 = NULL; + bool opt_unlink_early = false; + bool opt_unlink_close = true; + int result; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", + argv[0], argc-1); + return STAT_NORETRY; + } + + socket_un_init(&us); + + retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); + name = argv[1]; + uslen = xiosetunix(&us, name, false, tight); + + retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early); + retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); + + if (opt_unlink_close) { + if ((xfd->unlink_close = strdup(name)) == NULL) { + Error1("strdup(\"%s\"): out of memory", name); + } + xfd->opt_unlink_close = true; + } + + xfd->howtoend = END_SHUTDOWN; + + applyopts(-1, opts, PH_INIT); + if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; + applyopts(-1, opts, PH_EARLY); + + if (opt_unlink_early) { + if (Unlink(name) < 0) { + if (errno == ENOENT) { + Warn2("unlink(\"%s\"): %s", name, strerror(errno)); + } else { + Error2("unlink(\"%s\"): %s", name, strerror(errno)); + } + } + } + + /* trying to set user-early, perm-early etc. here is useless because + file system entry is available only past bind() call. */ + applyopts_named(name, opts, PH_EARLY); /* umask! */ + + retropt_int(opts, OPT_SO_TYPE, &socktype); + + opts0 = copyopts(opts, GROUP_ALL); + + if ((result = + xioopen_listen(xfd, xioflags, + (struct sockaddr *)&us, uslen, + opts, opts0, PF_UNIX, socktype, 0)) + != 0) + return result; + return 0; +} +#endif /* WITH_LISTEN */ + + +static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) { + /* we expect the form: filename */ + const char *name; + struct single *xfd = &xxfd->stream; + struct sockaddr_un them, us; + socklen_t themlen, uslen; + bool tight = true; + bool needbind = false; + bool opt_unlink_close = false; + int result; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", + argv[0], argc-1); + return STAT_NORETRY; + } + + socket_un_init(&us); + socket_un_init(&them); + + retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); + name = argv[1]; + themlen = xiosetunix(&them, name, false, tight); + retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); + + if (retropt_bind(opts, AF_UNIX, socktype, 0, (struct sockaddr *)&us, &uslen, 0, 0, 0) + != STAT_NOACTION) { + needbind = true; + } + + if (opt_unlink_close) { + if ((xfd->unlink_close = strdup(name)) == NULL) { + Error1("strdup(\"%s\"): out of memory", name); + } + xfd->opt_unlink_close = true; + } + + applyopts(-1, opts, PH_INIT); + if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; + applyopts(-1, opts, PH_EARLY); + + if ((result = + xioopen_connect(xfd, + needbind?(struct sockaddr *)&us:NULL, uslen, + (struct sockaddr *)&them, themlen, + opts, PF_UNIX, socktype, 0, false)) != 0) { + return result; + } + if ((result = _xio_openlate(xfd, opts)) < 0) { + return result; + } + return 0; +} + + +static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) { + const char *name; + xiosingle_t *xfd = &xxfd->stream; + union sockaddr_union us; + socklen_t uslen; + bool tight = true; + int pf = PF_UNIX; + bool needbind = false; + bool opt_unlink_close = false; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", + argv[0], argc-1); + return STAT_NORETRY; + } + + uslen = socket_init(pf, &us); + xfd->salen = socket_init(pf, &xfd->peersa); + + xfd->howtoend = END_SHUTDOWN; + + retropt_int(opts, OPT_SO_TYPE, &socktype); + + retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); + name = argv[1]; + xfd->salen = xiosetunix(&xfd->peersa.un, name, false, tight); + + retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); + + xfd->dtype = XIODATA_RECVFROM; + + if (retropt_bind(opts, pf, socktype, 0, &us.soa, &uslen, 0, 0, 0) + != STAT_NOACTION) { + needbind = true; + } + + if (opt_unlink_close) { + if ((xfd->unlink_close = strdup(name)) == NULL) { + Error1("strdup(\"%s\"): out of memory", name); + } + xfd->opt_unlink_close = true; + } + + applyopts(-1, opts, PH_INIT); + if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; + + return + _xioopen_dgram_sendto(needbind?&us:NULL, uslen, + opts, xioflags, xfd, groups, pf, socktype, 0); +} + + +static +int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xfd, unsigned groups, + int pf, int socktype, int dummy3) { + const char *name; + struct sockaddr_un us; + socklen_t uslen; + bool tight = true; + bool needbind = true; + bool opt_unlink_early = false; + bool opt_unlink_close = true; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", + argv[0], argc-1); + return STAT_NORETRY; + } + + socket_un_init(&us); + + retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); + name = argv[1]; + uslen = xiosetunix(&us, name, false, tight); + + xfd->stream.howtoend = END_NONE; + retropt_int(opts, OPT_SO_TYPE, &socktype); + retropt_bind(opts, pf, socktype, 0, (struct sockaddr *)&us, &uslen, 1, 0, 0); + retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early); + retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); + + if (opt_unlink_close) { + if ((xfd->stream.unlink_close = strdup(name)) == NULL) { + Error1("strdup(\"%s\"): out of memory", name); + } + xfd->stream.opt_unlink_close = true; + } + + if (opt_unlink_early) { + if (Unlink(name) < 0) { + if (errno == ENOENT) { + Warn2("unlink(\"%s\"): %s", name, strerror(errno)); + } else { + Error2("unlink(\"%s\"): %s", name, strerror(errno)); + } + } + } + + xfd->stream.para.socket.la.soa.sa_family = pf; + + xfd->stream.dtype = XIODATA_RECVFROM_ONE; + return _xioopen_dgram_recvfrom(&xfd->stream, xioflags, + needbind?(struct sockaddr *)&us:NULL, uslen, + opts, pf, socktype, 0, E_ERROR); +} + + +static +int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xfd, unsigned groups, + int pf, int socktype, int ipproto) { + const char *name; + union sockaddr_union us; + socklen_t uslen; + bool tight = true; + bool opt_unlink_early = false; + bool opt_unlink_close = true; + int result; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", + argv[0], argc-1); + return STAT_NORETRY; + } + + retropt_int(opts, OPT_SO_TYPE, &socktype); + + socket_un_init(&us.un); + + retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); + name = argv[1]; + uslen = xiosetunix(&us.un, name, false, tight); + +#if 1 /*!!! why bind option? */ + retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, 1, 0, 0); +#endif + + retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early); + if (opt_unlink_early) { + if (Unlink(name) < 0) { + if (errno == ENOENT) { + Warn2("unlink(\"%s\"): %s", name, strerror(errno)); + } else { + Error2("unlink(\"%s\"): %s", name, strerror(errno)); + } + } + } + + retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); + + if (opt_unlink_close) { + if ((xfd->stream.unlink_close = strdup(name)) == NULL) { + Error1("strdup(\"%s\"): out of memory", name); + } + xfd->stream.opt_unlink_close = true; + } + + xfd->stream.para.socket.la.soa.sa_family = pf; + + xfd->stream.dtype = XIODATA_RECV; + result = _xioopen_dgram_recv(&xfd->stream, xioflags, &us.soa, uslen, + opts, pf, socktype, ipproto, E_ERROR); + return result; +} + + +static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) { + const char *name; + xiosingle_t *xfd = &xxfd->stream; + bool tight = true; + int pf = PF_UNIX; + union sockaddr_union them, us; + socklen_t themlen; + socklen_t uslen; + bool needbind = false; + bool opt_unlink_close = false; + int result; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1); + } + + xfd->howtoend = END_SHUTDOWN; + retropt_int(opts, OPT_SO_TYPE, &socktype); + + uslen = socket_init(pf, &us); + themlen = socket_init(pf, &them); + + retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); + name = argv[1]; + themlen = xiosetunix(&them.un, name, false, tight); + + retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); + + if (retropt_bind(opts, pf, socktype, 0, &us.soa, &uslen, 0, 0, 0) + != STAT_NOACTION) { + needbind = true; + } + + if (opt_unlink_close) { + if ((xfd->unlink_close = strdup(name)) == NULL) { + Error1("strdup(\"%s\"): out of memory", name); + } + xfd->opt_unlink_close = true; + } + + /* xfd->dtype = DATA_STREAM; // is default */ + if ((result = + xioopen_connect(xfd, + needbind?(struct sockaddr *)&us:NULL, uslen, + (struct sockaddr *)&them, themlen, + opts, PF_UNIX, socktype?socktype:SOCK_STREAM, 0, false)) != 0) { + if (errno == EPROTOTYPE) { + if (needbind) { + Unlink(us.un.sun_path); + } + + applyopts(-1, opts, PH_INIT); + if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; + + xfd->peersa = them; + xfd->salen = sizeof(struct sockaddr_un); + if ((result = + _xioopen_dgram_sendto(needbind?&us:NULL, uslen, + opts, xioflags, xfd, groups, pf, + socktype?socktype:SOCK_DGRAM, 0)) + != 0) { + return result; + } + xfd->dtype = XIODATA_RECVFROM; + } + } + if ((result = _xio_openlate(xfd, opts)) < 0) { + return result; + } + return 0; +} + + +#if WITH_ABSTRACT_UNIXSOCKET +#if WITH_LISTEN +static int xioopen_abstract_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) { + /* we expect the form: filename */ + const char *name; + xiosingle_t *xfd = &xxfd->stream; + bool tight = true; + struct sockaddr_un us; + socklen_t uslen; + struct opt *opts0 = NULL; + int result; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", + argv[0], argc-1); + return STAT_NORETRY; + } + + socket_un_init(&us); + + retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); + name = argv[1]; + uslen = xiosetunix(&us, name, true, tight); + + xfd->howtoend = END_SHUTDOWN; + + applyopts(-1, opts, PH_INIT); + if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; + applyopts(-1, opts, PH_EARLY); + + /* trying to set user-early, perm-early etc. here is useless because + file system entry is available only past bind() call. */ + + retropt_int(opts, OPT_SO_TYPE, &socktype); + + opts0 = copyopts(opts, GROUP_ALL); + + if ((result = + xioopen_listen(xfd, xioflags, + (struct sockaddr *)&us, uslen, + opts, opts0, PF_UNIX, socktype, 0)) + != 0) + return result; + return 0; +} +#endif /* WITH_LISTEN */ + +static int xioopen_abstract_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) { + /* we expect the form: filename */ + const char *name; + struct single *xfd = &xxfd->stream; + bool tight = true; + struct sockaddr_un them, us; + socklen_t themlen, uslen; + bool needbind = false; + int result; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", + argv[0], argc-1); + return STAT_NORETRY; + } + + socket_un_init(&us); + socket_un_init(&them); + + retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); + name = argv[1]; + themlen = xiosetunix(&them, name, true, tight); + + if (retropt_bind(opts, AF_UNIX, socktype, 0, (struct sockaddr *)&us, &uslen, 0, 0, 0) + != STAT_NOACTION) { + needbind = true; + } + + applyopts(-1, opts, PH_INIT); + if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; + applyopts(-1, opts, PH_EARLY); + + if ((result = + xioopen_connect(xfd, + needbind?(struct sockaddr *)&us:NULL, uslen, + (struct sockaddr *)&them, themlen, + opts, PF_UNIX, socktype, 0, false)) != 0) { + return result; + } + if ((result = _xio_openlate(xfd, opts)) < 0) { + return result; + } + return 0; +} + + +static int xioopen_abstract_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) { + const char *name; + xiosingle_t *xfd = &xxfd->stream; + union sockaddr_union us; + socklen_t uslen; + bool tight = true; + int pf = PF_UNIX; + bool needbind = false; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", + argv[0], argc-1); + return STAT_NORETRY; + } + + uslen = socket_init(pf, &us); + xfd->salen = socket_init(pf, &xfd->peersa); + + xfd->howtoend = END_SHUTDOWN; + + retropt_int(opts, OPT_SO_TYPE, &socktype); + + retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); + name = argv[1]; + xfd->salen = xiosetunix(&xfd->peersa.un, name, true, tight); + + xfd->dtype = XIODATA_RECVFROM; + + if (retropt_bind(opts, pf, socktype, 0, &us.soa, &uslen, 0, 0, 0) + != STAT_NOACTION) { + needbind = true; + } + + applyopts(-1, opts, PH_INIT); + if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; + + return + _xioopen_dgram_sendto(needbind?&us:NULL, uslen, + opts, xioflags, xfd, groups, pf, socktype, 0); +} + + +static +int xioopen_abstract_recvfrom(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xfd, unsigned groups, + int pf, int socktype, int dummy3) { + const char *name; + struct sockaddr_un us; + socklen_t uslen; + bool tight = true; + bool needbind = true; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", + argv[0], argc-1); + return STAT_NORETRY; + } + + socket_un_init(&us); + + retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); + name = argv[1]; + uslen = xiosetunix(&us, name, true, tight); + + xfd->stream.howtoend = END_NONE; + retropt_int(opts, OPT_SO_TYPE, &socktype); + retropt_bind(opts, pf, socktype, 0, (struct sockaddr *)&us, &uslen, 1, 0, 0); + + xfd->stream.para.socket.la.soa.sa_family = pf; + + xfd->stream.dtype = XIODATA_RECVFROM_ONE; + return _xioopen_dgram_recvfrom(&xfd->stream, xioflags, + needbind?(struct sockaddr *)&us:NULL, uslen, + opts, pf, socktype, 0, E_ERROR); +} + + +static +int xioopen_abstract_recv(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *xfd, unsigned groups, + int pf, int socktype, int ipproto) { + const char *name; + union sockaddr_union us; + socklen_t uslen; + bool tight = true; + int result; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", + argv[0], argc-1); + return STAT_NORETRY; + } + + retropt_int(opts, OPT_SO_TYPE, &socktype); + + socket_un_init(&us.un); + + retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); + name = argv[1]; + uslen = xiosetunix(&us.un, name, true, tight); + +#if 1 /*!!! why bind option? */ + retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, 1, 0, 0); +#endif + + xfd->stream.para.socket.la.soa.sa_family = pf; + + xfd->stream.dtype = XIODATA_RECV; + result = _xioopen_dgram_recv(&xfd->stream, xioflags, &us.soa, uslen, + opts, pf, socktype, ipproto, E_ERROR); + return result; +} + + +static int xioopen_abstract_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) { + const char *name; + xiosingle_t *xfd = &xxfd->stream; + bool tight = true; + int pf = PF_UNIX; + union sockaddr_union them, us; + socklen_t themlen; + socklen_t uslen; + bool needbind = false; + int result; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1); + } + + xfd->howtoend = END_SHUTDOWN; + retropt_int(opts, OPT_SO_TYPE, &socktype); + + uslen = socket_init(pf, &us); + themlen = socket_init(pf, &them); + + retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); + name = argv[1]; + themlen = xiosetunix(&them.un, name, true, tight); + + if (retropt_bind(opts, pf, socktype, 0, &us.soa, &uslen, 0, 0, 0) + != STAT_NOACTION) { + needbind = true; + } + + /* xfd->dtype = DATA_STREAM; // is default */ + if ((result = + xioopen_connect(xfd, + needbind?(struct sockaddr *)&us:NULL, uslen, + (struct sockaddr *)&them, themlen, + opts, PF_UNIX, socktype?socktype:SOCK_STREAM, 0, false)) != 0) { + if (errno == EPROTOTYPE) { + if (needbind) { + Unlink(us.un.sun_path); + } + + /* ...res_opts[] */ + applyopts(-1, opts, PH_INIT); + if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; + + xfd->peersa = them; + xfd->salen = themlen; + if ((result = + _xioopen_dgram_sendto(needbind?&us:NULL, uslen, + opts, xioflags, xfd, groups, pf, + socktype?socktype:SOCK_DGRAM, 0)) + != 0) { + return result; + } + xfd->dtype = XIODATA_RECVFROM; + } + } + if ((result = _xio_openlate(xfd, opts)) < 0) { + return result; + } + return 0; +} + +#endif /* WITH_ABSTRACT_UNIXSOCKET */ + +#endif /* WITH_UNIX */ diff --git a/xio-unix.h b/xio-unix.h new file mode 100644 index 0000000..3cea77e --- /dev/null +++ b/xio-unix.h @@ -0,0 +1,29 @@ +/* $Id: xio-unix.h,v 1.6 2007/02/08 18:30:08 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_unix_h_included +#define __xio_unix_h_included 1 + +extern const struct addrdesc addr_unix_connect; +extern const struct addrdesc addr_unix_listen; +extern const struct addrdesc addr_unix_sendto; +extern const struct addrdesc addr_unix_recvfrom; +extern const struct addrdesc addr_unix_recv; +extern const struct addrdesc addr_unix_client; +extern const struct addrdesc xioaddr_abstract_connect; +extern const struct addrdesc xioaddr_abstract_listen; +extern const struct addrdesc xioaddr_abstract_sendto; +extern const struct addrdesc xioaddr_abstract_recvfrom; +extern const struct addrdesc xioaddr_abstract_recv; +extern const struct addrdesc xioaddr_abstract_client; + +extern const struct optdesc opt_unix_tightsocklen; + +extern socklen_t +xiosetunix(struct sockaddr_un *saun, + const char *path, + bool abstract, + bool tight); + +#endif /* !defined(__xio_unix_h_included) */ diff --git a/xio.h b/xio.h new file mode 100644 index 0000000..649f854 --- /dev/null +++ b/xio.h @@ -0,0 +1,404 @@ +/* $Id: xio.h,v 1.66 2007/03/06 21:25:51 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_h_included +#define __xio_h_included 1 + +#if 1 /*!*/ +#include "mytypes.h" +#include "sysutils.h" +#endif + +#define XIO_MAXSOCK 2 + +/* Linux 2.2.10 */ +#define HAVE_STRUCT_LINGER 1 + +#define LINETERM_RAW 0 +#define LINETERM_CR 1 +#define LINETERM_CRNL 2 + +struct addrdesc; +struct opt; + +/* the flags argument of xioopen */ +#define XIO_RDONLY O_RDONLY /* asserted to be 0 */ +#define XIO_WRONLY O_WRONLY /* asserted to be 1 */ +#define XIO_RDWR O_RDWR /* asserted to be 2 */ +#define XIO_ACCMODE O_ACCMODE /* must be 3 */ +#define XIO_MAYFORK 4 /* address is allowed to fork the program (fork) */ +#define XIO_MAYCHILD 8 /* address is allowed to fork off a child (exec)*/ +#define XIO_MAYEXEC 16 /* address is allowed to exec a prog (exec+nofork) */ +#define XIO_MAYCONVERT 32 /* address is allowed to perform modifications on the + stream data, e.g. SSL, REALDINE; CRLF */ + +/* the status flags of xiofile_t */ +#define XIO_DOESFORK XIO_MAYFORK +#define XIO_DOESCHILD XIO_MAYCHILD +#define XIO_DOESEXEC XIO_MAYEXEC +#define XIO_DOESCONVERT XIO_MAYCONVERT + + +/* methods for reading and writing, and for related checks */ +#define XIODATA_READMASK 0xf000 /* mask for basic r/w method */ +#define XIOREAD_STREAM 0x1000 /* read() (default) */ +#define XIOREAD_RECV 0x2000 /* recvfrom() */ +#define XIOREAD_PTY 0x4000 /* handle EIO */ +#define XIOREAD_READLINE 0x5000 /* ... */ +#define XIOREAD_OPENSSL 0x6000 /* SSL_read() */ +#define XIODATA_WRITEMASK 0x0f00 /* mask for basic r/w method */ +#define XIOWRITE_STREAM 0x0100 /* write() (default) */ +#define XIOWRITE_SENDTO 0x0200 /* sendto() */ +#define XIOWRITE_PIPE 0x0300 /* write() to alternate (pipe) Fd */ +#define XIOWRITE_2PIPE 0x0400 /* write() to alternate (2pipe) Fd */ +#define XIOWRITE_READLINE 0x0500 /* check for prompt */ +#define XIOWRITE_OPENSSL 0x0600 /* SSL_write() */ +/* modifiers to XIODATA_READ_RECV */ +#define XIOREAD_RECV_CHECKPORT 0x0001 /* recv, check peer port */ +#define XIOREAD_RECV_CHECKADDR 0x0002 /* recv, check peer address */ +#define XIOREAD_RECV_CHECKRANGE 0x0004 /* recv, check if peer addr in range */ +#define XIOREAD_RECV_ONESHOT 0x0008 /* give EOF after first packet */ +#define XIOREAD_RECV_SKIPIP 0x0010 /* recv, skip IPv4 header */ +#define XIOREAD_RECV_FROM 0x0020 /* remember peer for replying */ + +/* combinations */ +#define XIODATA_MASK (XIODATA_READMASK|XIODATA_WRITEMASK) +#define XIODATA_STREAM (XIOREAD_STREAM|XIOWRITE_STREAM) +#define XIODATA_RECVFROM (XIOREAD_RECV|XIOWRITE_SENDTO|XIOREAD_RECV_CHECKPORT|XIOREAD_RECV_CHECKADDR|XIOREAD_RECV_FROM) +#define XIODATA_RECVFROM_SKIPIP (XIODATA_RECVFROM|XIOREAD_RECV_SKIPIP) +#define XIODATA_RECVFROM_ONE (XIODATA_RECVFROM|XIOREAD_RECV_ONESHOT) +#define XIODATA_RECVFROM_SKIPIP_ONE (XIODATA_RECVFROM_SKIPIP|XIOREAD_RECV_ONESHOT) +#define XIODATA_RECV (XIOREAD_RECV|XIOWRITE_SENDTO|XIOREAD_RECV_CHECKRANGE) +#define XIODATA_RECV_SKIPIP (XIODATA_RECV|XIOREAD_RECV_SKIPIP) +#define XIODATA_PIPE (XIOREAD_STREAM|XIOWRITE_PIPE) +#define XIODATA_2PIPE (XIOREAD_STREAM|XIOWRITE_2PIPE) +#define XIODATA_PTY (XIOREAD_PTY|XIOWRITE_STREAM) +#define XIODATA_READLINE (XIOREAD_READLINE|XIOWRITE_STREAM) +#define XIODATA_OPENSSL (XIOREAD_OPENSSL|XIOWRITE_OPENSSL) + + +/* these are the values allowed for the "enum xiotag tag" flag of the "struct + single" and "union bipipe" (xiofile_t) structures. */ +enum xiotag { + XIO_TAG_INVALID, /* the record is not in use */ + XIO_TAG_RDONLY, /* this is a single read-only stream */ + XIO_TAG_WRONLY, /* this is a single write-only stream */ + XIO_TAG_RDWR, /* this is a single read-write stream */ + XIO_TAG_DUAL /* this is a dual stream, consisting of two single + streams */ +} ; + +/* global XIO options/parameters */ +typedef struct { + bool strictopts; + const char *pipesep; + const char *paramsep; + const char *optionsep; + char ip4portsep; + char ip6portsep; /* do not change, might be hardcoded somewhere! */ + char logopt; /* 'm' means "switch to syslog when entering daemon mode" */ + const char *syslogfac; /* syslog facility (only with mixed mode) */ + char default_ip; /* default prot.fam for IP based listen ('4' or '6') */ + char preferred_ip; /* preferred prot.fam. for name resolution ('0' for + unspecified, '4', or '6') */ +} xioopts_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 */ + struct timespec intervall; /* polling intervall */ +} xiolock_t; + +extern xioopts_t xioopts; + +#define MAXARGV 8 + +/* a non-dual file descriptor */ +typedef struct single { + enum xiotag tag; /* see enum xiotag */ + const struct addrdesc *addr; + int flags; + /* until here, keep consistent with bipipe.common !!! */ +#if WITH_RETRY + unsigned int retry; /* retry opening this many times */ + bool forever; /* retry opening forever */ + struct timespec intervall; /* wait so long between retries */ +#endif /* WITH_RETRY */ + bool ignoreeof; /* option ignoreeof; do not pass eof condition to app*/ + int eof; /* 1..exec'd child has died, but no explicit eof + occurred + 2..fd0 has reached EOF (definitely; never with + ignoreeof! */ + size_t wsize; /* write always this size; 0..all available */ + size_t readbytes; /* read only so many bytes; 0...unlimited */ + size_t actbytes; /* so many bytes still to be read (when readbytes!=0)*/ + xiolock_t lock; /* parameters of lockfile */ + bool havelock; /* we are happy owner of the above lock */ + bool cool_write; /* downlevel EPIPE, ECONNRESET to notice */ + /* until here, keep consistent with bipipe.dual ! */ + int argc; /* number of fields in argv */ + const char *argv[MAXARGV]; /* address keyword, required args */ + struct opt *opts; /* the options of this address */ + int lineterm; /* 0..dont touch; 1..CR; 2..CRNL on extern data */ + int fd; + bool opt_unlink_close; /* option unlink_close */ + char *unlink_close; /* name of a symlink or unix socket to be removed */ + int dtype; + enum { + END_UNSPEC, /* after init, when no end-close... option */ + END_NONE, /* no action */ + END_CLOSE, /* close() */ + END_SHUTDOWN, /* shutdown() */ + END_UNLINK, /* unlink() */ + END_KILL, /* has subprocess */ + END_CLOSE_KILL, /* first close fd, then kill subprocess */ + END_SHUTDOWN_KILL /* first shutdown fd, then kill subprocess */ + } howtoend; +#if _WITH_SOCKET + union sockaddr_union peersa; + socklen_t salen; +#endif /* _WITH_SOCKET */ +#if WITH_TERMIOS + bool ttyvalid; /* the following struct is valid */ + struct termios savetty; /* save orig tty settings for later restore */ +#endif /* WITH_TERMIOS */ + const char *name; /* only with END_UNLINK */ + int (*sigchild)(struct single *); /* callback after sigchild */ + pid_t ppid; /* parent pid, only if we send it signals */ + union { + struct { + int fdout; /* use fd for output */ + } bipipe; +#if _WITH_SOCKET + struct { + struct timeval connect_timeout; /* how long to hang in connect() */ + union sockaddr_union la; /* local socket address */ + bool emptyiseof; /* with dgram: empty packet means EOF */ + bool dorange; + union xiorange_union range; /* restrictions for peer address */ +#if _WITH_IP4 || _WITH_IP6 + struct { + unsigned int res_opts[2]; /* bits to be set in _res.options are + at [0], bits to be cleared are at [1] */ + bool dosourceport; + uint16_t sourceport; /* host byte order */ + bool lowport; +#if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP + bool dolibwrap; + char *libwrapname; + char *tcpwrap_etc; + char *hosts_allow_table; + char *hosts_deny_table; +#endif + } ip; +#endif /* _WITH_IP4 || _WITH_IP6 */ + } socket; +#endif /* _WITH_SOCKET */ + struct { + pid_t pid; /* child PID, with EXEC: */ + int fdout; /* use fd for output if two pipes */ + } exec; +#if WITH_READLINE + struct { + char *history_file; + char *prompt; /* static prompt, passed to readline() */ + size_t dynbytes; /* length of buffer for dynamic prompt */ + char *dynprompt; /* the dynamic prompt */ + char *dynend; /* current end of dynamic prompt */ +#if HAVE_REGEX_H + bool hasnoecho; /* following regex is set */ + regex_t noecho; /* if it matches the prompt, input is silent */ +#endif + } readline; +#endif /* WITH_READLINE */ +#if WITH_OPENSSL + struct { + struct timeval connect_timeout; /* how long to hang in connect() */ + SSL *ssl; + SSL_CTX* ctx; + } openssl; +#endif /* WITH_OPENSSL */ +#if WITH_TUN + struct { + short iff_opts[2]; /* ifr flags, using OFUNC_OFFSET_MASKS */ + } tun; +#endif /* WITH_TUN */ + } para; +} xiosingle_t; + +/* rw: 0..read, 1..write, 2..r/w */ +/* when implementing a new address type take care of following topics: + . be aware that xioopen_single is used for O_RDONLY, O_WRONLY, and O_RDWR data + . which options are allowed (option groups) + . implement application of all these options + . set FD_CLOEXEC on new file descriptors BEFORE the cloexec option might be + applied + . +*/ + +typedef union bipipe { + enum xiotag tag; + struct { + enum xiotag tag; + const struct addrdesc *addr; + int flags; + } common; + struct single stream; + struct { + enum xiotag tag; + const struct addrdesc *addr; + int flags; /* compatible to fcntl(.., F_GETFL, ..) */ +#if WITH_RETRY + unsigned retry; /* retry opening this many times */ + bool forever; /* retry opening forever */ + struct timespec intervall; /* wait so long between retries */ +#endif /* WITH_RETRY */ + bool ignoreeof; + int eof; /* fd0 has reached EOF */ + size_t wsize; /* write always this size; 0..all available */ + size_t readbytes; /* read only so many bytes; 0...unlimited */ + size_t actbytes; /* so many bytes still to be read */ + xiolock_t lock; /* parameters of lockfile */ + bool havelock; /* we are happy owner of the above lock */ + xiosingle_t *stream[2]; /* input stream, output stream */ + } dual; +} xiofile_t; + + +struct addrdesc { + const char *defname; /* main (canonical) name of address */ + int directions; /* 1..read, 2..write, 3..both */ + int (*func)(int argc, const char *argv[], struct opt *opts, int rw, xiofile_t *fd, unsigned groups, + int arg1, int arg2, int arg3); + unsigned groups; + int arg1; + int arg2; + int arg3; +#if WITH_HELP + const char *syntax; +#endif +} ; + +#define XIO_WRITABLE(s) (((s)->common.flags+1)&2) +#define XIO_READABLE(s) (((s)->common.flags+1)&1) +#define XIO_RDSTREAM(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[0]:&(s)->stream) +#define XIO_WRSTREAM(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[1]:&(s)->stream) +#define XIO_GETRDFD(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[0]->fd:(s)->stream.fd) +#define XIO_GETWRFD(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[1]->fd:(((s)->stream.dtype&XIODATA_WRITEMASK)==XIOWRITE_2PIPE)?(s)->stream.para.exec.fdout:(((s)->stream.dtype&XIODATA_WRITEMASK)==XIOWRITE_PIPE)?(s)->stream.para.bipipe.fdout:(s)->stream.fd) +#define XIO_EOF(s) (XIO_RDSTREAM(s)->eof && !XIO_RDSTREAM(s)->ignoreeof) + +typedef unsigned long flags_t; + +union integral { + int u_bool; + uint8_t u_byte; + gid_t u_gidt; + int u_int; + long u_long; +#if HAVE_TYPE_LONGLONG + long long u_longlong; +#endif + double u_double; + mode_t u_modet; + short u_short; + size_t u_sizet; + char *u_string; + uid_t u_uidt; + unsigned int u_uint; + unsigned long u_ulong; + unsigned short u_ushort; + uint16_t u_2bytes; + void *u_ptr; + flags_t u_flag; + struct { + uint8_t *b_data; + size_t b_len; + } u_bin; + struct timeval u_timeval; +#if HAVE_STRUCT_LINGER + struct linger u_linger; +#endif /* HAVE_STRUCT_LINGER */ +#if HAVE_STRUCT_TIMESPEC + struct timespec u_timespec; +#endif /* HAVE_STRUCT_TIMESPEC */ +#if HAVE_STRUCT_IP_MREQ || HAVE_STRUCT_IP_MREQN + struct { + char *multiaddr; + char *param2; /* address, interface */ +#if HAVE_STRUCT_IP_MREQN + char ifindex[IF_NAMESIZE+1]; +#endif + } u_ip_mreq; +#endif +#if WITH_IP4 + in_addr_t u_ip4addr; +#endif +} ; + +/* some aliases */ +#define u_off u_long /* please report when this causes problems */ + +#if defined(HAVE_BASIC_OFF64_T) && HAVE_BASIC_OFF64_T +# if HAVE_BASIC_OFF64_T==5 +# define u_off64 u_long +# elif HAVE_BASIC_OFF64_T==7 +# define u_off64 u_longlong +# else +# error "unexpected size of off64_t, please report this as bug" +# endif +#endif /* defined(HAVE_BASIC_OFF64_T) && HAVE_BASIC_OFF64_T */ + + +/* this handles option instances, for communication between subroutines */ +struct opt { + const struct optdesc *desc; + union integral value; +} ; + +extern const char *PIPESEP; +extern xiofile_t *sock[XIO_MAXSOCK]; + +/* return values of xioopensingle */ +#define STAT_OK 0 +#define STAT_WARNING 1 +#define STAT_EXIT 2 +#define STAT_NOACTION 3 /* by retropt_* when option not applied */ +#define STAT_RETRYNOW -1 /* only after timeouts useful ? */ +#define STAT_RETRYLATER -2 /* address cannot be opened, but user might + change something in the filesystem etc. to + make this process succeed later. */ +#define STAT_NORETRY -3 /* address syntax error, not implemented etc; + not even by external changes correctable */ + +extern int xioinitialize(void); +extern int xio_forked_inchild(void); +extern int xiosetopt(char what, const char *arg); +extern int xioinqopt(char what, char *arg, size_t n); +extern xiofile_t *xioopen(const char *args, int flags); +extern int xioopensingle(char *addr, struct single *xfd, int xioflags); +extern int xioopenhelp(FILE *of, int level); + +/* must be outside function for use by childdied handler */ +extern xiofile_t *sock1, *sock2; +extern pid_t diedunknown1; /* child died before it is registered */ +extern pid_t diedunknown2; +extern pid_t diedunknown3; +extern pid_t diedunknown4; + +extern int xiosetsigchild(xiofile_t *xfd, int (*callback)(struct single *)); +extern int xio_opt_signal(pid_t pid, int signum); +extern void childdied(int signum); + +extern ssize_t xioread(xiofile_t *sock1, void *buff, size_t bufsiz); +extern ssize_t xiopending(xiofile_t *sock1); +extern ssize_t xiowrite(xiofile_t *sock1, const void *buff, size_t bufsiz); +extern int xioshutdown(xiofile_t *sock, int how); + +extern int xioclose(xiofile_t *sock); +extern void xioexit(void); + +extern int (*xiohook_newchild)(void); /* xio calls this function from a new child process */ + +#endif /* !defined(__xio_h_included) */ diff --git a/xioclose.c b/xioclose.c new file mode 100644 index 0000000..026e55c --- /dev/null +++ b/xioclose.c @@ -0,0 +1,118 @@ +/* $Id: xioclose.c,v 1.26 2007/01/25 21:36:11 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this is the source of the extended close function */ + + +#include "xiosysincludes.h" +#include "xioopen.h" +#include "xiolockfile.h" + +#include "xio-termios.h" + + +/* close the xio fd; must be valid and "simple" */ +int xioclose1(struct single *pipe) { + + if (pipe->tag == XIO_TAG_INVALID) { + Notice("xioclose1(): invalid file descriptor"); + errno = EINVAL; + return -1; + } + +#if WITH_READLINE + if ((pipe->dtype & XIODATA_MASK) == XIODATA_READLINE) { + Write_history(pipe->para.readline.history_file); + /*xiotermios_setflag(pipe->fd, 3, ECHO|ICANON);*/ /* error when pty closed */ + } +#endif /* WITH_READLINE */ +#if WITH_OPENSSL + if ((pipe->dtype & XIODATA_MASK) == XIODATA_OPENSSL) { + if (pipe->para.openssl.ssl) { + /* e.g. on TCP connection refused, we do not yet have this set */ + sycSSL_shutdown(pipe->para.openssl.ssl); + sycSSL_free(pipe->para.openssl.ssl); + pipe->para.openssl.ssl = NULL; + } + Close(pipe->fd); pipe->fd = -1; + if (pipe->para.openssl.ctx) { + sycSSL_CTX_free(pipe->para.openssl.ctx); + pipe->para.openssl.ctx = NULL; + } + } else +#endif /* WITH_OPENSSL */ +#if WITH_TERMIOS + if (pipe->ttyvalid) { + if (Tcsetattr(pipe->fd, 0, &pipe->savetty) < 0) { + Warn2("cannot restore terminal settings on fd %d: %s", + pipe->fd, strerror(errno)); + } + } +#endif /* WITH_TERMIOS */ + if (pipe->fd >= 0) { + switch (pipe->howtoend) { + case END_KILL: case END_SHUTDOWN_KILL: case END_CLOSE_KILL: + if (pipe->para.exec.pid > 0) { + if (Kill(pipe->para.exec.pid, SIGTERM) < 0) { + Msg2(errno==ESRCH?E_INFO:E_WARN, "kill(%d, SIGTERM): %s", + pipe->para.exec.pid, strerror(errno)); + } + } + default: + break; + } + switch (pipe->howtoend) { + case END_CLOSE: case END_CLOSE_KILL: + if (Close(pipe->fd) < 0) { + Info2("close(%d): %s", pipe->fd, strerror(errno)); } break; +#if WITH_SOCKET + case END_SHUTDOWN: case END_SHUTDOWN_KILL: + if (Shutdown(pipe->fd, 2) < 0) { + Info3("shutdown(%d, %d): %s", pipe->fd, 2, strerror(errno)); } + break; +#endif /* WITH_SOCKET */ + case END_UNLINK: if (Unlink((const char *)pipe->name) < 0) { + Warn2("unlink(\"%s\"): %s", pipe->name, strerror(errno)); } + break; + case END_NONE: default: break; + } + } + + /* unlock */ + if (pipe->havelock) { + xiounlock(pipe->lock.lockfile); + pipe->havelock = false; + } + if (pipe->opt_unlink_close && pipe->unlink_close) { + if (Unlink(pipe->unlink_close) < 0) { + Info2("unlink(\"%s\"): %s", pipe->unlink_close, strerror(errno)); + } + free(pipe->unlink_close); + } + + pipe->tag = XIO_TAG_INVALID; + return 0; /*! */ +} + + +/* close the xio fd */ +int xioclose(xiofile_t *file) { + int result; + + if (file->tag == XIO_TAG_INVALID) { + Error("xioclose(): invalid file descriptor"); + errno = EINVAL; + return -1; + } + + if (file->tag == XIO_TAG_DUAL) { + result = xioclose1(file->dual.stream[0]); + result |= xioclose1(file->dual.stream[1]); + file->tag = XIO_TAG_INVALID; + } else { + result = xioclose1(&file->stream); + } + return result; +} + diff --git a/xioconfig.h b/xioconfig.h new file mode 100644 index 0000000..4da8c5d --- /dev/null +++ b/xioconfig.h @@ -0,0 +1,119 @@ +/* $Id: xioconfig.h,v 1.27 2007/03/06 21:26:23 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xioconfig_h_included +#define __xioconfig_h_included 1 + +/* ensure some dependencies between configure WITH defines. must be included + past config.h */ + +#if WITH_STDIO || WITH_FDNUM +# define WITH_FD 1 +#endif + +#if WITH_FILE || WITH_GOPEN || WITH_CREAT || WITH_PIPE +# define WITH_OPEN 1 +#endif + +#if WITH_OPEN || WITH_PIPE || WITH_UNIX || WITH_PTY +# define WITH_NAMED 1 +#endif + +#if WITH_SOCKS4A +# define WITH_SOCKS4 1 +#endif + +#if WITH_SOCKS4 || WITH_PROXY +# define WITH_TCP 1 +# define WITH_IP4 1 /* currently this socks implementation does not work + with IP6 */ +#endif + +#if WITH_OPENSSL +# define WITH_TCP 1 +# define WITH_IP4 1 +#endif + +#if WITH_IP6 +# if !defined(HAVE_NETINET_IP6_H) +# undef WITH_IP6 +# endif +#endif + +#if !WITH_IP4 && !WITH_IP6 +# if WITH_TCP || WITH_UDP || WITH_RAWIP +# define WITH_IP4 1 +# endif +#endif + +#if WITH_UNIX || WITH_IP4 || WITH_IP6 || WITH_SOCKS4 || WITH_RAWIP +# define WITH_SOCKET 1 +#else +# undef WITH_SOCKET +#endif + +#if !WITH_SOCKET +# undef WITH_LISTEN +#endif + +#if !WITH_LISTEN +# undef WITH_LIBWRAP +#endif + +#if WITH_SOCKET || WITH_TUN +# define _WITH_SOCKET 1 +#endif + +#if WITH_IP4 || WITH_TUN +# define _WITH_IP4 1 +#endif + +#if WITH_IP6 || WITH_TUN +# define _WITH_IP6 1 +#endif + +#if WITH_NAMED || WITH_TUN +# define _WITH_NAMED 1 +#endif + +#if WITH_FILE || WITH_TUN +# define _WITH_FILE 1 +#endif + + +#if HAVE_DEV_PTMX && HAVE_GRANTPT && HAVE_UNLOCKPT && HAVE_PTSNAME +#else +# undef HAVE_DEV_PTMX +#endif + +#if HAVE_DEV_PTC /* && HAVE_GRANTPT && HAVE_UNLOCKPT && HAVE_PTSNAME */ +#else +# undef HAVE_DEV_PTC +#endif + + +/* MacOS does not seem to have any pty implementation */ +#if WITH_PTY && (HAVE_DEV_PTC || HAVE_DEV_PTMX || HAVE_OPENPTY) +# define HAVE_PTY 1 +#else +# undef HAVE_PTY +#endif + +#ifndef HAVE_TYPE_SOCKLEN + typedef int socklen_t; +#endif /* !defined(HAVE_TYPE_SOCKLEN) */ + +#ifndef HAVE_TYPE_UINT8 + typedef unsigned char uint8_t; +#endif + +#ifndef HAVE_TYPE_UINT16 + typedef unsigned short uint16_t; +#endif + +#ifndef HAVE_TYPE_UINT32 + typedef unsigned int uint32_t; +#endif + +#endif /* !defined(__xioconfig_h_included) */ diff --git a/xiodiag.c b/xiodiag.c new file mode 100644 index 0000000..5f60133 --- /dev/null +++ b/xiodiag.c @@ -0,0 +1,21 @@ +/* $Id: xiodiag.c,v 1.3 2003/05/21 05:16:38 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001, 2003 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains source for some diagnostics */ + +#include "xiosysincludes.h" +#include "xioopen.h" + +#include "xiodiag.h" + + +const char *ddirection[] = { + "reading", "writing", "reading and writing" } ; + +/* compliant with S_ macros (sys/stat.h) */ +const char *filetypenames[] = { + "undef", "named pipe", "character device", "undef", + "block device", "undef", "directory", "undef", + "regular file", "undef", "symbolic link", "undef", + "local socket", "undef", "undef", "\"MT\"?"} ; diff --git a/xiodiag.h b/xiodiag.h new file mode 100644 index 0000000..802798b --- /dev/null +++ b/xiodiag.h @@ -0,0 +1,11 @@ +/* $Id: xiodiag.h,v 1.2 2001/11/04 17:13:22 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xiodiag_h_included +#define __xiodiag_h_included 1 + +extern const char *ddirection[]; +extern const char *filetypenames[]; + +#endif /* !defined(__xiodiag_h_included) */ diff --git a/xioexit.c b/xioexit.c new file mode 100644 index 0000000..fe99a42 --- /dev/null +++ b/xioexit.c @@ -0,0 +1,21 @@ +/* $Id: xioexit.c,v 1.10 2005/03/13 12:19:11 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2005 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for the extended exit function */ + +#include "xiosysincludes.h" +#include "xio.h" + + +/* this function closes all open xio sockets on exit, if they are still open. + It must be registered with atexit(). */ +void xioexit(void) { + int i; + + for (i = 0; i < XIO_MAXSOCK; ++i) { + if (sock[i] != NULL && sock[i]->tag != XIO_TAG_INVALID) { + xioclose(sock[i]); + } + } +} diff --git a/xiohelp.c b/xiohelp.c new file mode 100644 index 0000000..508e596 --- /dev/null +++ b/xiohelp.c @@ -0,0 +1,168 @@ +/* $Id: xiohelp.c,v 1.19 2007/02/05 21:07:07 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for the help function */ + +#include "xiosysincludes.h" +#include "xioopen.h" + +#include "xiohelp.h" + +#if WITH_HELP + +/* keep consistent with xioopts.h:enum e_types ! */ +static const char *optiontypenames[] = { + "CONST", "BIN", "BOOL", "BYTE", + "INT", "LONG", "STRING", "PTRDIFF", + "SHORT", "SIZE_T", "SOCKADDR", "UNSIGNED-INT", + "UNSIGNED-LONG","UNSIGNED-SHORT","MODE_T", "GID_T", + "UID_T", "INT[3]", "STRUCT-TIMEVAL", "STRUCT-TIMESPEC", +#if HAVE_STRUCT_LINGER + "STRUCT-LINGER", +#endif + "DOUBLE", "STRING-NULL", "LONG-LONG", + "OFF_T", "OFF64_T", +#if HAVE_STRUCT_IP_MREQN + "STRUCT-IP_MREQN", +#elif HAVE_STRUCT_IP_MREQN + "STRUCT-IP_MREQ", +#endif + "IP4NAME", +} ; + + +/* keep consistent with xioopts.h:#define GROUP_* ! */ +static const char *addressgroupnames[] = { + "FD", "FIFO", "CHR", "BLK", + "REG", "SOCKET", "READLINE", "undef", + "NAMED", "OPEN", "EXEC", "FORK", + "LISTEN", "DEVICE", "CHILD", "RETRY", + "TERMIOS", "RANGE", "PTY", "PARENT", + "UNIX", "IP4", "IP6", "INTERFACE", + "UDP", "TCP", "SOCKS4", "OPENSSL", + "PROCESS", "APPL", "HTTP", "undef" +} ; + + +/* keep consistent with xioopts.h:enum ephase ! */ +static char *optionphasenames[] = { + "ALL", "INIT", "EARLY", + "PREOPEN", "OPEN", "PASTOPEN", + "PRESOCKET", "SOCKET", "PASTSOCKET", + "PREBIGEN", "BIGEN", "PASTBIGEN", + "FD", + "PREBIND", "BIND", "PASTBIND", + "PRELISTEN", "LISTEN", "PASTLISTEN", + "PRECONNECT", "CONNECT", "PASTCONNECT", + "PREACCEPT", "ACCEPT", "PASTACCEPT", + "CONNECTED", + "PREFORK", "FORK", "PASTFORK", + "LATE", "LATE2", + "PREEXEC", "EXEC", "SPECIFIC", + NULL +} ; + + +/* print a line about a single option */ +static int xiohelp_option(FILE *of, const struct optname *on, const char *name) { + int j; + unsigned int groups; + bool occurred; + + fprintf(of, " %s\tgroups=", name); + groups = on->desc->group; occurred = false; + for (j = 0; j < 32; ++j) { + if (groups & 1) { + if (occurred) { fputc(',', of); } + fprintf(of, "%s", addressgroupnames[j]); + occurred = true; + } + groups >>= 1; + } + fprintf(of, "\tphase=%s", optionphasenames[on->desc->phase]); + fprintf(of, "\ttype=%s", optiontypenames[on->desc->type]); + fputc('\n', of); + return 0; +} + +int xioopenhelp(FILE *of, + int level /* 0..only addresses, 1..and options */ + ) { + const struct addrname *an; + const struct optname *on; + int i, j; + unsigned int groups; + bool occurred; + + fputs(" bi-address:\n", of); + fputs(" pipe[,]\tgroups=FD,FIFO\n", of); + if (level == 2) { + fputs(" echo is an alias for pipe\n", of); + fputs(" fifo is an alias for pipe\n", of); + } + fputs(" !!\n", of); + fputs(" \n", of); + fputs(" single-address:\n", of); + fputs(" [,]\n", of); + fputs(" address-head:\n", of); + an = &addressnames[0]; + i = 0; + while (addressnames[i].name) { + if (!strcmp(an->name, an->desc->defname)) { + /* it is a canonical address name */ + fprintf(of, " %s", an->name); + if (an->desc->syntax) { + fputs(an->desc->syntax, of); } + fputs("\tgroups=", of); + groups = an->desc->groups; occurred = false; + for (j = 0; j < 32; ++j) { + if (groups & 1) { + if (occurred) { fputc(',', of); } + fprintf(of, "%s", addressgroupnames[j]); + occurred = true; + } + groups >>= 1; + } + fputc('\n', of); + } else if (level == 2) { + fprintf(of, " %s is an alias name for %s\n", an->name, an->desc->defname); + } + ++an; ++i; + } + if (level == 2) { + fputs(" is a short form for fd:\n", of); + fputs(" is a short form for gopen:\n", of); + } + + if (level <= 0) return 0; + + fputs(" opts:\n", of); + fputs(" {,}:\n", of); + fputs(" opt:\n", of); + on = optionnames; + while (on->name != NULL) { + if (on->desc->nickname!= NULL + && !strcmp(on->name, on->desc->nickname)) { + if (level == 2) { + fprintf(of, " %s is an alias for %s\n", on->name, on->desc->defname); + } else { + xiohelp_option(of, on, on->name); + } + } else if (on->desc->nickname == NULL && + !strcmp(on->name, on->desc->defname)) { + xiohelp_option(of, on, on->name); + } else if (level == 2) { + if (!strcmp(on->name, on->desc->defname)) { + xiohelp_option(of, on, on->name); + } else { + fprintf(of, " %s is an alias for %s\n", on->name, on->desc->defname); + } + } + ++on; + } + fflush(of); + return 0; +} + +#endif /* WITH_HELP */ diff --git a/xiohelp.h b/xiohelp.h new file mode 100644 index 0000000..7953ac8 --- /dev/null +++ b/xiohelp.h @@ -0,0 +1,12 @@ +/* $Id: xiohelp.h,v 1.2 2001/11/04 17:19:21 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xiohelp_h_included +#define __xiohelp_h_included 1 + +extern int xioopenhelp(FILE *of, + int level /* 0..only addresses, 1..and options */ + ); + +#endif /* !defined(__xiohelp_h_included) */ diff --git a/xioinitialize.c b/xioinitialize.c new file mode 100644 index 0000000..84e4e3c --- /dev/null +++ b/xioinitialize.c @@ -0,0 +1,187 @@ +/* $Id: xioinitialize.c,v 1.17 2006/12/28 14:21:41 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for the initialize function */ + +#include "xiosysincludes.h" + +#include "xioopen.h" +#include "xiolockfile.h" + +#include "xio-openssl.h" /* xio_reset_fips_mode() */ + +static int xioinitialized; +xiofile_t *sock[XIO_MAXSOCK]; +int (*xiohook_newchild)(void); /* xio calls this function from a new child + process */ + + +/* returns 0 on success or != if an error occurred */ +int xioinitialize(void) { + if (xioinitialized) return 0; + + /* configure and .h's cannot guarantee this */ + assert(sizeof(uint8_t)==1); + assert(sizeof(uint16_t)==2); + assert(sizeof(uint32_t)==4); + + /* assertions regarding O_ flags - important for XIO_READABLE() etc. */ + assert(O_RDONLY==0); + assert(O_WRONLY==1); + assert(O_RDWR==2); + + assert(SHUT_RD==0); + assert(SHUT_WR==1); + assert(SHUT_RDWR==2); + + /* some assertions about termios */ +#if WITH_TERMIOS +#ifdef CRDLY + assert(3 << opt_crdly.arg3 == CRDLY); +#endif +#ifdef TABDLY + assert(3 << opt_tabdly.arg3 == TABDLY); +#endif + assert(3 << opt_csize.arg3 == CSIZE); + { + union { + struct termios termarg; + tcflag_t flags[4]; +#if HAVE_TERMIOS_ISPEED + speed_t speeds[sizeof(struct termios)/sizeof(speed_t)]; +#endif + } tdata; + tdata.termarg.c_iflag = 0x12345678; + tdata.termarg.c_oflag = 0x23456789; + tdata.termarg.c_cflag = 0x3456789a; + tdata.termarg.c_lflag = 0x456789ab; + assert(tdata.termarg.c_iflag == tdata.flags[0]); + assert(tdata.termarg.c_oflag == tdata.flags[1]); + assert(tdata.termarg.c_cflag == tdata.flags[2]); + assert(tdata.termarg.c_lflag == tdata.flags[3]); +#if HAVE_TERMIOS_ISPEED + tdata.termarg.c_ispeed = 0x56789abc; + tdata.termarg.c_ospeed = 0x6789abcd; + assert(tdata.termarg.c_ispeed == tdata.speeds[ISPEED_OFFSET]); + assert(tdata.termarg.c_ospeed == tdata.speeds[OSPEED_OFFSET]); +#endif + } +#endif + + /* these dependencies required in applyopts() for OFUNC_FCNTL */ + assert(F_GETFD == F_SETFD-1); + assert(F_GETFL == F_SETFL-1); + + { + const char *default_ip; + default_ip = getenv("SOCAT_DEFAULT_LISTEN_IP"); + if (default_ip != NULL) { + switch (default_ip[0]) { + case '4': + case '6': + xioopts.default_ip = default_ip[0]; break; + } + } + } + { + const char *preferred_ip; + preferred_ip = getenv("SOCAT_PREFERRED_RESOLVE_IP"); + if (preferred_ip != NULL) { + switch (preferred_ip[0]) { + case '4': + case '6': + xioopts.preferred_ip = preferred_ip[0]; break; + default: + xioopts.preferred_ip = '0'; break; + } + } + } + + if (Atexit(xioexit) < 0) { + Error("atexit(xioexit) failed"); + return -1; + } + + xioinitialized = 1; + return 0; +} + + +/* well, this function is not for initialization, but I could not find a better + place for it + it is called in the child process after fork + it drops the locks of the xiofile's so only the parent owns them + */ +void xiodroplocks(void) { + int i; + + for (i = 0; i < XIO_MAXSOCK; ++i) { + if (sock[i] != NULL && sock[i]->tag != XIO_TAG_INVALID) { + xiofiledroplock(sock[i]); + } + } +} + + +/* consider an invokation like this: + socat -u exec:'some program that accepts data' tcp-l:...,fork + we do not want the program to be killed by the first tcp-l sub process, it's + better if it survives all sub processes. Thus, it must not be killed if the + sub process delivers EOF. Also, a socket that is reused in sub processes + should not be shut down (affects the connection), but closed (affects only + sub processes copy of file descriptor) */ +static int xio_nokill(xiofile_t *sock) { + int result = 0; + switch (sock->tag) { + case XIO_TAG_INVALID: + default: + return -1; + case XIO_TAG_DUAL: + if ((result = xio_nokill((xiofile_t *)sock->dual.stream[0])) != 0) + return result; + result = xio_nokill((xiofile_t *)sock->dual.stream[1]); + break; + case XIO_TAG_RDONLY: + case XIO_TAG_WRONLY: + case XIO_TAG_RDWR: + /* here is the core of this function */ + switch (sock->stream.howtoend) { + case END_SHUTDOWN_KILL: sock->stream.howtoend = END_CLOSE; break; + case END_CLOSE_KILL: sock->stream.howtoend = END_CLOSE; break; + case END_SHUTDOWN: sock->stream.howtoend = END_CLOSE; break; + default: break; + } + break; + } + return result; +} + +/* call this function immediately after fork() in child process */ +/* it performs some neccessary actions + returns 0 on success or != 0 if an error occurred */ +int xio_forked_inchild(void) { + int result = 0; + xiodroplocks(); +#if WITH_FIPS + if (xio_reset_fips_mode() != 0) { + result = 1; + } +#endif /* WITH_FIPS */ + /* some locks belong to parent process, so "drop" them now */ + if (xiohook_newchild) { + if ((*xiohook_newchild)() != 0) { + Exit(1); + } + } + + /* change XIO_SHUTDOWN_KILL to XIO_SHUTDOWN */ + if (sock1 != NULL) { + int result2; + result2 = xio_nokill(sock1); + if (result2 < 0) Exit(1); + result |= result2; + } + + return result; +} diff --git a/xiolayer.c b/xiolayer.c new file mode 100644 index 0000000..2e0bc18 --- /dev/null +++ b/xiolayer.c @@ -0,0 +1,25 @@ +/* $Id: xiolayer.c,v 1.7 2005/08/18 19:56:05 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2005 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for common options */ + +#include "xiosysincludes.h" +#include "xioopen.h" + +#include "xiolayer.h" + +/****** for ALL addresses - by application ******/ +const struct optdesc opt_ignoreeof = { "ignoreeof", NULL, OPT_IGNOREEOF, GROUP_APPL, PH_LATE, TYPE_BOOL, OFUNC_EXT, (int)(&((struct single *)0)->ignoreeof), sizeof(((struct single *)0)->ignoreeof) }; +const struct optdesc opt_cr = { "cr", NULL, OPT_CR, GROUP_APPL, PH_LATE, TYPE_CONST, OFUNC_EXT, (int)(&((struct single *)0)->lineterm), sizeof(((struct single *)0)->lineterm), LINETERM_CR }; +const struct optdesc opt_crnl = { "crnl", NULL, OPT_CRNL, GROUP_APPL, PH_LATE, TYPE_CONST, OFUNC_EXT, (int)(&((struct single *)0)->lineterm), sizeof(((struct single *)0)->lineterm), LINETERM_CRNL }; +const struct optdesc opt_readbytes = { "readbytes", "bytes", OPT_READBYTES, GROUP_APPL, PH_LATE, TYPE_SIZE_T, OFUNC_EXT, (int)(&((struct single *)0)->readbytes), sizeof(((struct single *)0)->readbytes) }; +const struct optdesc opt_lockfile = { "lockfile", NULL, OPT_LOCKFILE, GROUP_APPL, PH_INIT, TYPE_FILENAME, OFUNC_EXT, 0, 0 }; +const struct optdesc opt_waitlock = { "waitlock", NULL, OPT_WAITLOCK, GROUP_APPL, PH_INIT, TYPE_FILENAME, OFUNC_EXT, 0, 0 }; +/****** APPL addresses ******/ +#if WITH_RETRY +const struct optdesc opt_forever = { "forever", NULL, OPT_FOREVER, GROUP_RETRY, PH_INIT, TYPE_BOOL, OFUNC_EXT, (int)(&((struct single *)0)->forever), sizeof(((struct single *)0)->forever) }; +const struct optdesc opt_intervall = { "intervall", NULL, OPT_INTERVALL, GROUP_RETRY, PH_INIT, TYPE_TIMESPEC, OFUNC_EXT, (int)(&((struct single *)0)->intervall), sizeof(((struct single *)0)->intervall) }; +const struct optdesc opt_retry = { "retry", NULL, OPT_RETRY, GROUP_RETRY, PH_INIT, TYPE_UINT, OFUNC_EXT, (int)(&((struct single *)0)->retry), sizeof(((struct single *)0)->retry) }; +#endif + diff --git a/xiolayer.h b/xiolayer.h new file mode 100644 index 0000000..743cbc7 --- /dev/null +++ b/xiolayer.h @@ -0,0 +1,18 @@ +/* $Id: xiolayer.h,v 1.5 2005/08/18 19:56:05 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2005 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xiolayer_h_included +#define __xiolayer_h_included 1 + +extern const struct optdesc opt_ignoreeof; +extern const struct optdesc opt_cr; +extern const struct optdesc opt_crnl; +extern const struct optdesc opt_readbytes; +extern const struct optdesc opt_lockfile; +extern const struct optdesc opt_waitlock; +extern const struct optdesc opt_forever; +extern const struct optdesc opt_intervall; +extern const struct optdesc opt_retry; + +#endif /* !defined(__xiolayer_h_included) */ diff --git a/xiolockfile.c b/xiolockfile.c new file mode 100644 index 0000000..c297394 --- /dev/null +++ b/xiolockfile.c @@ -0,0 +1,118 @@ +/* $Id: xiolockfile.c,v 1.2 2006/02/08 19:51:24 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2005-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains socats explicit locking mechanisms */ + +#include "xiosysincludes.h" + +#include "compat.h" +#include "mytypes.h" +#include "error.h" +#include "utils.h" +#include "sysutils.h" + +#include "sycls.h" + +#include "xio.h" +#include "xiolockfile.h" + + +/* returns 0 if it could create lock; 1 if the lock exists; -1 on error */ +int xiogetlock(const char *lockfile) { + char *s; + struct stat strat; + int fd; + pid_t pid; + char pidbuf[3*sizeof(pid_t)+1]; + size_t bytes; + + if (Lstat(lockfile, &strat) == 0) { + return 1; + } + switch (errno) { + case ENOENT: break; + default: + Error3("Lstat(\"%s\", %p): %s", lockfile, &strat, strerror(errno)); + return -1; + } + /* in this moment, the file did not exist */ + + if ((s = Malloc(strlen(lockfile)+8)) == NULL) { + errno = ENOMEM; + return -1; + } + strcpy(s, lockfile); + strcat(s, ".XXXXXX"); + + if ((fd = Mkstemp(s)) < 0) { + Error2("mkstemp(\"%s\"): %s", s, strerror(errno)); + return -1; + } + + pid = Getpid(); + bytes = sprintf(pidbuf, F_pid, pid); + Write(fd, pidbuf, bytes); + Close(fd); + + /* Chmod(lockfile, 0600); */ + if (Link(s, lockfile) < 0) { + int _errno = errno; + Error3("link(\"%s\", \"%s\"): %s", s, lockfile, strerror(errno)); + Unlink(s); + errno = _errno; + return -1; + } + Unlink(s); + + return 0; +} + +int xiounlock(const char *lockfile) { + return Unlink(lockfile); +} + + +/* returns 0 when it could create lock, or -1 on error */ +int xiowaitlock(const char *lockfile, struct timespec *intervall) { + int rc; + int level = E_NOTICE; /* first print a notice */ + + while ((rc = xiogetlock(lockfile)) == 1) { + Msg1(level, "waiting for lock \"%s\"", lockfile); + level = E_INFO; /* afterwards only make info */ + Nanosleep(intervall, NULL); + } + return rc; +} + + +/* returns 0 when it could obtain lock or the lock is not valid + (lockfile==NULL), 1 if it could not obtain the lock, or -1 on error */ +int xiolock(xiolock_t *lock) { + int result; + + if (lock->lockfile == NULL) { + return 0; + } + if (lock->waitlock) { + result = xiowaitlock(lock->lockfile, &lock->intervall); + } else { + result = xiogetlock(lock->lockfile); + } + if (result == 0) { + Info1("obtained lock \"%s\"", lock->lockfile); + } + return result; +} + + +int xiofiledroplock(xiofile_t *xfd) { + if (xfd->tag == XIO_TAG_DUAL) { + xiofiledroplock((xiofile_t *)xfd->dual.stream[0]); + xiofiledroplock((xiofile_t *)xfd->dual.stream[1]); + } else { + xfd->stream.havelock = false; + } + return 0; +} diff --git a/xiolockfile.h b/xiolockfile.h new file mode 100644 index 0000000..ff22288 --- /dev/null +++ b/xiolockfile.h @@ -0,0 +1,17 @@ +/* $Id: xiolockfile.h,v 1.1 2005/08/18 19:42:05 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2005 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xiolockfile_h_included +#define __xiolockfile_h_included 1 + +/* preferred lock handling functions */ +extern int xiolock(xiolock_t *lock); +extern int xiounlock(const char *lockfile); + +/* more "internal" functions */ +extern int xiogetlock(const char *lockfile); +extern int xiowaitlock(const char *lockfile, struct timespec *intervall); +extern int xiofiledroplock(xiofile_t *xfd); + +#endif /* !defined(__xiolockfile_h_included) */ diff --git a/xiomodes.h b/xiomodes.h new file mode 100644 index 0000000..afeae15 --- /dev/null +++ b/xiomodes.h @@ -0,0 +1,45 @@ +/* $Id: xiomodes.h,v 1.13 2007/03/06 21:22:29 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xiomodes_h_included +#define __xiomodes_h_included 1 + +#include "xiolayer.h" +#include "xio-process.h" +#include "xio-fd.h" +#include "xio-fdnum.h" +#include "xio-stdio.h" +#include "xio-named.h" +#include "xio-file.h" +#include "xio-creat.h" +#include "xio-gopen.h" +#include "xio-pipe.h" +#if WITH_SOCKET +#include "xio-socket.h" +#include "xio-listen.h" +#include "xio-unix.h" +#include "xio-rawip.h" +#include "xio-ip.h" +#if WITH_IP4 +#include "xio-ip4.h" +#endif /* WITH_IP4 */ +#include "xio-ip6.h" +#include "xio-ipapp.h" +#include "xio-tcp.h" +#include "xio-udp.h" +#include "xio-socks.h" +#include "xio-proxy.h" +#endif /* WITH_SOCKET */ +#include "xio-progcall.h" +#include "xio-exec.h" +#include "xio-system.h" +#include "xio-termios.h" +#include "xio-readline.h" +#include "xio-pty.h" +#include "xio-openssl.h" +#include "xio-tcpwrap.h" +#include "xio-ext2.h" +#include "xio-tun.h" + +#endif /* !defined(__xiomodes_h_included) */ diff --git a/xioopen.c b/xioopen.c new file mode 100644 index 0000000..59d8e7f --- /dev/null +++ b/xioopen.c @@ -0,0 +1,533 @@ +/* $Id: xioopen.c,v 1.119 2007/03/06 21:20:28 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this is the source file of the extended open function */ + +#include "xiosysincludes.h" + +#include "xioopen.h" +#include "xiomodes.h" +#include "nestlex.h" + +static xiofile_t *xioallocfd(void); + +xiosingle_t hugo; +static xiosingle_t *xioparse_single(const char **addr); +static xiofile_t *xioparse_dual(const char **addr); +static int xioopen_dual(xiofile_t *xfd, int xioflags); + +const struct addrname addressnames[] = { +#if 1 +#if WITH_STDIO + { "-", &addr_stdio }, +#endif +#if defined(WITH_UNIX) && defined(WITH_ABSTRACT_UNIXSOCKET) + { "abstract", &xioaddr_abstract_client }, + { "abstract-client", &xioaddr_abstract_client }, + { "abstract-connect", &xioaddr_abstract_connect }, +#if WITH_LISTEN + { "abstract-listen", &xioaddr_abstract_listen }, +#endif + { "abstract-recv", &xioaddr_abstract_recv }, + { "abstract-recvfrom", &xioaddr_abstract_recvfrom }, + { "abstract-sendto", &xioaddr_abstract_sendto }, +#endif /* defined(WITH_UNIX) && defined(WITH_ABSTRACT_UNIXSOCKET) */ +#if WITH_CREAT + { "creat", &addr_creat }, + { "create", &addr_creat }, +#endif +#if WITH_PIPE + { "echo", &addr_pipe }, +#endif +#if WITH_EXEC + { "exec", &addr_exec }, +#endif +#if WITH_FDNUM + { "fd", &addr_fd }, +#endif +#if WITH_PIPE + { "fifo", &addr_pipe }, +#endif +#if WITH_FILE + { "file", &addr_open }, +#endif +#if WITH_GOPEN + { "gopen", &addr_gopen }, +#endif +#if (WITH_IP4 || WITH_IP6) && WITH_TCP + { "inet", &addr_tcp_connect }, +#endif +#if (WITH_IP4 || WITH_IP6) && WITH_TCP && WITH_LISTEN + { "inet-l", &addr_tcp_listen }, + { "inet-listen", &addr_tcp_listen }, +#endif +#if WITH_IP4 && WITH_TCP + { "inet4", &addr_tcp4_connect }, +#endif +#if WITH_IP4 && WITH_TCP && WITH_LISTEN + { "inet4-l", &addr_tcp4_listen }, + { "inet4-listen", &addr_tcp4_listen }, +#endif +#if WITH_IP6 && WITH_TCP + { "inet6", &addr_tcp6_connect }, +#endif +#if WITH_IP6 && WITH_TCP && WITH_LISTEN + { "inet6-l", &addr_tcp6_listen }, + { "inet6-listen", &addr_tcp6_listen }, +#endif +#if WITH_RAWIP +#if (WITH_IP4 || WITH_IP6) + { "ip", &addr_rawip_sendto }, + { "ip-datagram", &addr_rawip_datagram }, + { "ip-dgram", &addr_rawip_datagram }, + { "ip-recv", &addr_rawip_recv }, + { "ip-recvfrom", &addr_rawip_recvfrom }, + { "ip-send", &addr_rawip_sendto }, + { "ip-sendto", &addr_rawip_sendto }, +#endif +#if WITH_IP4 + { "ip4", &addr_rawip4_sendto }, + { "ip4-datagram", &addr_rawip4_datagram }, + { "ip4-dgram", &addr_rawip4_datagram }, + { "ip4-recv", &addr_rawip4_recv }, + { "ip4-recvfrom", &addr_rawip4_recvfrom }, + { "ip4-send", &addr_rawip4_sendto }, + { "ip4-sendto", &addr_rawip4_sendto }, +#endif +#if WITH_IP6 + { "ip6", &addr_rawip6_sendto }, + { "ip6-datagram", &addr_rawip6_datagram }, + { "ip6-dgram", &addr_rawip6_datagram }, + { "ip6-recv", &addr_rawip6_recv }, + { "ip6-recvfrom", &addr_rawip6_recvfrom }, + { "ip6-send", &addr_rawip6_sendto }, + { "ip6-sendto", &addr_rawip6_sendto }, +#endif +#endif /* WITH_RAWIP */ +#if WITH_UNIX + { "local", &addr_unix_connect }, +#endif +#if WITH_FILE + { "open", &addr_open }, +#endif +#if WITH_OPENSSL + { "openssl", &addr_openssl }, + { "openssl-connect", &addr_openssl }, +#if WITH_LISTEN + { "openssl-listen", &addr_openssl_listen }, +#endif +#endif +#if WITH_PIPE + { "pipe", &addr_pipe }, +#endif +#if WITH_PROXY + { "proxy", &addr_proxy_connect }, + { "proxy-connect", &addr_proxy_connect }, +#endif +#if WITH_PTY + { "pty", &addr_pty }, +#endif +#if WITH_READLINE + { "readline", &addr_readline }, +#endif +#if WITH_SOCKS4 + { "socks", &addr_socks4_connect }, + { "socks4", &addr_socks4_connect }, +#endif +#if WITH_SOCKS4A + { "socks4a", &addr_socks4a_connect }, +#endif +#if WITH_OPENSSL + { "ssl", &addr_openssl }, +#if WITH_LISTEN + { "ssl-l", &addr_openssl_listen }, +#endif +#endif +#if WITH_STDIO + { "stderr", &addr_stderr }, + { "stdin", &addr_stdin }, + { "stdio", &addr_stdio }, + { "stdout", &addr_stdout }, +#endif +#if WITH_SYSTEM + { "system", &addr_system }, +#endif +#if (WITH_IP4 || WITH_IP6) && WITH_TCP + { "tcp", &addr_tcp_connect }, + { "tcp-connect", &addr_tcp_connect }, +#endif +#if (WITH_IP4 || WITH_IP6) && WITH_TCP && WITH_LISTEN + { "tcp-l", &addr_tcp_listen }, + { "tcp-listen", &addr_tcp_listen }, +#endif +#if WITH_IP4 && WITH_TCP + { "tcp4", &addr_tcp4_connect }, + { "tcp4-connect", &addr_tcp4_connect }, +#endif +#if WITH_IP4 && WITH_TCP && WITH_LISTEN + { "tcp4-l", &addr_tcp4_listen }, + { "tcp4-listen", &addr_tcp4_listen }, +#endif +#if WITH_IP6 && WITH_TCP + { "tcp6", &addr_tcp6_connect }, + { "tcp6-connect", &addr_tcp6_connect }, +#endif +#if WITH_IP6 && WITH_TCP && WITH_LISTEN + { "tcp6-l", &addr_tcp6_listen }, + { "tcp6-listen", &addr_tcp6_listen }, +#endif +#if WITH_TUN + { "tun", &xioaddr_tun }, +#endif +#if (WITH_IP4 || WITH_IP6) && WITH_UDP + { "udp", &addr_udp_connect }, +#endif +#if (WITH_IP4 || WITH_IP6) && WITH_UDP + { "udp-connect", &addr_udp_connect }, + { "udp-datagram", &addr_udp_datagram }, + { "udp-dgram", &addr_udp_datagram }, +#endif +#if (WITH_IP4 || WITH_IP6) && WITH_UDP && WITH_LISTEN + { "udp-l", &addr_udp_listen }, + { "udp-listen", &addr_udp_listen }, +#endif +#if (WITH_IP4 || WITH_IP6) && WITH_UDP + { "udp-recv", &addr_udp_recv }, + { "udp-recvfrom", &addr_udp_recvfrom }, + { "udp-send", &addr_udp_sendto }, + { "udp-sendto", &addr_udp_sendto }, +#endif +#if WITH_IP4 && WITH_UDP + { "udp4", &addr_udp4_connect }, + { "udp4-connect", &addr_udp4_connect }, + { "udp4-datagram", &addr_udp4_datagram }, + { "udp4-dgram", &addr_udp4_datagram }, +#endif +#if WITH_IP4 && WITH_UDP && WITH_LISTEN + { "udp4-l", &addr_udp4_listen }, + { "udp4-listen", &addr_udp4_listen }, +#endif +#if WITH_IP4 && WITH_UDP + { "udp4-recv", &addr_udp4_recv }, + { "udp4-recvfrom", &addr_udp4_recvfrom }, + { "udp4-send", &addr_udp4_sendto }, + { "udp4-sendto", &addr_udp4_sendto }, +#endif +#if WITH_IP6 && WITH_UDP + { "udp6", &addr_udp6_connect }, + { "udp6-connect", &addr_udp6_connect }, + { "udp6-datagram", &addr_udp6_datagram }, + { "udp6-dgram", &addr_udp6_datagram }, +#endif +#if WITH_IP6 && WITH_UDP && WITH_LISTEN + { "udp6-l", &addr_udp6_listen }, + { "udp6-listen", &addr_udp6_listen }, +#endif +#if WITH_IP6 && WITH_UDP + { "udp6-recv", &addr_udp6_recv }, + { "udp6-recvfrom", &addr_udp6_recvfrom }, + { "udp6-send", &addr_udp6_sendto }, + { "udp6-sendto", &addr_udp6_sendto }, +#endif +#if WITH_UNIX + { "unix", &addr_unix_client }, + { "unix-client", &addr_unix_client }, + { "unix-connect", &addr_unix_connect }, +#endif +#if WITH_UNIX && WITH_LISTEN + { "unix-l", &addr_unix_listen }, + { "unix-listen", &addr_unix_listen }, +#endif +#if WITH_UNIX + { "unix-recv", &addr_unix_recv }, + { "unix-recvfrom", &addr_unix_recvfrom }, + { "unix-send", &addr_unix_sendto }, + { "unix-sendto", &addr_unix_sendto }, +#endif +#else /* !0 */ +# if WITH_INTEGRATE +# include "xiointegrate.c" +# else +# include "xioaddrtab.c" +# endif +#endif /* !0 */ + { NULL } /* end marker */ +} ; + +int xioopen_single(xiofile_t *xfd, int xioflags); + + +/* prepares a xiofile_t record for dual address type: + sets the tag and allocates memory for the substreams. + returns 0 on success, or <0 if an error occurred. +*/ +int xioopen_makedual(xiofile_t *file) { + file->tag = XIO_TAG_DUAL; + file->common.flags = XIO_RDWR; + if ((file->dual.stream[0] = (xiosingle_t *)xioallocfd()) == NULL) + return -1; + file->dual.stream[0]->flags = XIO_RDONLY; + if ((file->dual.stream[1] = (xiosingle_t *)xioallocfd()) == NULL) + return -1; + file->dual.stream[1]->flags = XIO_WRONLY; + return 0; +} + +static xiofile_t *xioallocfd(void) { + xiofile_t *fd; + + if ((fd = Calloc(1, sizeof(xiofile_t))) == NULL) { + return NULL; + } + /* some default values; 0's and NULL's need not be applied (calloc'ed) */ + fd->common.tag = XIO_TAG_INVALID; +/* fd->common.addr = NULL; */ + fd->common.flags = XIO_RDWR; + +#if WITH_RETRY +/* fd->stream.retry = 0; */ +/* fd->stream.forever = false; */ + fd->stream.intervall.tv_sec = 1; +/* fd->stream.intervall.tv_nsec = 0; */ +#endif /* WITH_RETRY */ +/* fd->common.ignoreeof = false; */ +/* fd->common.eof = 0; */ + + fd->stream.fd = -1; + fd->stream.dtype = XIODATA_STREAM; +#if WITH_SOCKET +/* fd->stream.salen = 0; */ +#endif /* WITH_SOCKET */ + fd->stream.howtoend = END_UNSPEC; +/* fd->stream.name = NULL; */ +/* fd->stream.para.exec.pid = 0; */ + fd->stream.lineterm = LINETERM_RAW; + + /*!! support n socks */ + if (!sock[0]) { + sock[0] = fd; + } else { + sock[1] = fd; + } + return fd; +} + + +/* parse the argument that specifies a two-directional data stream + and open the resulting address + */ +xiofile_t *xioopen(const char *addr, /* address specification */ + int xioflags) { + xiofile_t *xfd; + + if (xioinitialize() < 0) { + return NULL; + } + + if ((xfd = xioparse_dual(&addr)) == NULL) { + return NULL; + } + if (xioopen_dual(xfd, xioflags) < 0) { + /*!!! free something? */ + return NULL; + } + + return xfd; +} + +static xiofile_t *xioparse_dual(const char **addr) { + xiofile_t *xfd; + xiosingle_t *sfd1; + + /* we parse a single address */ + if ((sfd1 = xioparse_single(addr)) == NULL) { + return NULL; + } + + /* and now we see if we reached a dual-address separator */ + if (!strncmp(*addr, xioopts.pipesep, strlen(xioopts.pipesep))) { + /* yes we reached it, so we parse the second single address */ + *addr += strlen(xioopts.pipesep); + + if ((xfd = xioallocfd()) == NULL) { + free(sfd1); /*! and maybe have free some if its contents */ + return NULL; + } + xfd->tag = XIO_TAG_DUAL; + xfd->dual.stream[0] = sfd1; + if ((xfd->dual.stream[1] = xioparse_single(addr)) == NULL) { + return NULL; + } + + return xfd; + } + + /* a truly single address */ + xfd = (xiofile_t *)sfd1; sfd1 = NULL; + + return xfd; +} + +static int xioopen_dual(xiofile_t *xfd, int xioflags) { + + if (xfd->tag == XIO_TAG_DUAL) { + /* a really dual address */ + if ((xioflags&XIO_ACCMODE) != XIO_RDWR) { + Warn("unidirectional open of dual address"); + } + if (((xioflags&XIO_ACCMODE)+1) & (XIO_RDONLY+1)) { + if (xioopen_single((xiofile_t *)xfd->dual.stream[0], XIO_RDONLY|(xioflags&~XIO_ACCMODE&~XIO_MAYEXEC)) + < 0) { + return -1; + } + } + if (((xioflags&XIO_ACCMODE)+1) & (XIO_WRONLY+1)) { + if (xioopen_single((xiofile_t *)xfd->dual.stream[1], XIO_WRONLY|(xioflags&~XIO_ACCMODE&~XIO_MAYEXEC)) + < 0) { + xioclose((xiofile_t *)xfd->dual.stream[0]); + return -1; + } + } + return 0; + } + + return xioopen_single(xfd, xioflags); +} + + +static xiosingle_t *xioparse_single(const char **addr) { + xiofile_t *xfd; + xiosingle_t *sfd; + struct addrname *ae; + const struct addrdesc *addrdesc = NULL; + const char *ends[4+1]; + const char *hquotes[] = { + "'", + NULL + } ; + const char *squotes[] = { + "\"", + NULL + } ; + const char *nests[] = { + "'", "'", + "(", ")", + "[", "]", + "{", "}", + NULL + } ; + char token[512], *tokp; + size_t len; + int i; + + /* init */ + i = 0; + /*ends[i++] = xioopts.chainsep;*/ /* default: "|" */ + ends[i++] = xioopts.pipesep; /* default: "!!" */ + ends[i++] = ","/*xioopts.comma*/; /* default: "," */ + ends[i++] = ":"/*xioopts.colon*/; /* default: ":" */ + ends[i++] = NULL; + + if ((xfd = xioallocfd()) == NULL) { + return NULL; + } + sfd = &xfd->stream; + sfd->argc = 0; + + len = sizeof(token); tokp = token; + if (nestlex(addr, &tokp, &len, ends, hquotes, squotes, nests, + true, true, false) < 0) { + Error2("keyword too long, in address \"%s%s\"", token, *addr); + } + *tokp = '\0'; /*! len? */ + ae = (struct addrname *) + keyw((struct wordent *)&addressnames, token, + sizeof(addressnames)/sizeof(struct addrname)-1); + + if (ae) { + addrdesc = ae->desc; + /* keyword */ + if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) { + Error1("strdup(\"%s\"): out of memory", token); + } + } else { + if (false) { + ; +#if WITH_FDNUM + } else if (isdigit(token[0]&0xff) && token[1] == '\0') { + Info1("interpreting address \"%s\" as file descriptor", token); + addrdesc = &addr_fd; + if ((sfd->argv[sfd->argc++] = strdup("FD")) == NULL) { + Error("strdup(\"FD\"): out of memory"); + } + if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) { + Error1("strdup(\"%s\"): out of memory", token); + } + /*! check argc overflow */ +#endif /* WITH_FDNUM */ +#if WITH_GOPEN + } else if (strchr(token, '/')) { + Info1("interpreting address \"%s\" as file name", token); + addrdesc = &addr_gopen; + if ((sfd->argv[sfd->argc++] = strdup("GOPEN")) == NULL) { + Error("strdup(\"GOPEN\"): out of memory"); + } + if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) { + Error1("strdup(\"%s\"): out of memory", token); + } + /*! check argc overflow */ +#endif /* WITH_GOPEN */ + } else { + Error1("unknown device/address \"%s\"", token); + /*!!! free something*/ return NULL; + } + } + + sfd->tag = XIO_TAG_RDWR; + sfd->addr = addrdesc; + + while (!strncmp(*addr, xioopts.paramsep, strlen(xioopts.paramsep))) { + *addr += strlen(xioopts.paramsep); + len = sizeof(token); tokp = token; + if (nestlex(addr, &tokp, &len, ends, hquotes, squotes, nests, + true, true, false) != 0) { + Error2("syntax error in address \"%s%s\"", token, *addr); + } + *tokp = '\0'; + if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) { + Error1("strdup(\"%s\"): out of memory", token); + } + } + + if (parseopts(addr, addrdesc->groups, &sfd->opts) < 0) { + free(xfd); + return NULL; + } + + return sfd; +} + +int xioopen_single(xiofile_t *xfd, int xioflags) { + const struct addrdesc *addrdesc; + int result; + + if ((xioflags&XIO_ACCMODE) == XIO_RDONLY) { + xfd->tag = XIO_TAG_RDONLY; + } else if ((xioflags&XIO_ACCMODE) == XIO_WRONLY) { + xfd->tag = XIO_TAG_WRONLY; + } else if ((xioflags&XIO_ACCMODE) == XIO_RDWR) { + xfd->tag = XIO_TAG_RDWR; + } else { + Error1("invalid mode for address \"%s\"", xfd->stream.argv[0]); + } + xfd->stream.flags &= (~XIO_ACCMODE); + xfd->stream.flags |= (xioflags & XIO_ACCMODE); + addrdesc = xfd->stream.addr; + result = (*addrdesc->func)(xfd->stream.argc, xfd->stream.argv, + xfd->stream.opts, xioflags, xfd, + addrdesc->groups, addrdesc->arg1, + addrdesc->arg2, addrdesc->arg3); + return result; +} + diff --git a/xioopen.h b/xioopen.h new file mode 100644 index 0000000..7578b64 --- /dev/null +++ b/xioopen.h @@ -0,0 +1,94 @@ +/* $Id: xioopen.h,v 1.22 2006/05/12 20:14:05 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xioopen_h_included +#define __xioopen_h_included 1 + +#include "compat.h" /* F_pid */ +#include "mytypes.h" +#include "error.h" +#include "utils.h" +#include "sysutils.h" + +#include "sycls.h" +#include "sslcls.h" +#include "dalan.h" +#include "filan.h" +#include "xio.h" +#include "xioopts.h" + + +#if WITH_HELP +#define HELP(x) , x +#else +#define HELP(x) +#endif + + + +/* xioinitialize performs asserts on these records */ +extern const struct optdesc opt_crdly; +extern const struct optdesc opt_tabdly; +extern const struct optdesc opt_csize; + + +struct addrname { + const char *name; + const struct addrdesc *desc; +} ; + +extern const char *ddirection[]; +extern const char *filetypenames[]; +extern const struct addrname addressnames[]; +extern const struct optname optionnames[]; + +extern int xioopen_makedual(xiofile_t *file); + +#define retropt_2bytes(o,c,r) retropt_ushort(o,c,r) + +/* mode_t might be unsigned short or unsigned int or what else? */ +#if HAVE_BASIC_MODE_T==1 +# define retropt_modet(x,y,z) retropt_short(x,y,z) +#elif HAVE_BASIC_MODE_T==2 +# define retropt_modet(x,y,z) retropt_ushort(x,y,z) +#elif HAVE_BASIC_MODE_T==3 +# define retropt_modet(x,y,z) retropt_int(x,y,z) +#elif HAVE_BASIC_MODE_T==4 +# define retropt_modet(x,y,z) retropt_uint(x,y,z) +#elif HAVE_BASIC_MODE_T==5 +# define retropt_modet(x,y,z) retropt_long(x,y,z) +#elif HAVE_BASIC_MODE_T==6 +# define retropt_modet(x,y,z) retropt_ulong(x,y,z) +#endif + +#if HAVE_BASIC_UID_T==1 +# define retropt_uidt(x,y,z) retropt_short(x,y,z) +#elif HAVE_BASIC_UID_T==2 +# define retropt_uidt(x,y,z) retropt_ushort(x,y,z) +#elif HAVE_BASIC_UID_T==3 +# define retropt_uidt(x,y,z) retropt_int(x,y,z) +#elif HAVE_BASIC_UID_T==4 +# define retropt_uidt(x,y,z) retropt_uint(x,y,z) +#elif HAVE_BASIC_UID_T==5 +# define retropt_uidt(x,y,z) retropt_long(x,y,z) +#elif HAVE_BASIC_UID_T==6 +# define retropt_uidt(x,y,z) retropt_ulong(x,y,z) +#endif + +#if HAVE_BASIC_GID_T==1 +# define retropt_gidt(x,y,z) retropt_short(x,y,z) +#elif HAVE_BASIC_GID_T==2 +# define retropt_gidt(x,y,z) retropt_ushort(x,y,z) +#elif HAVE_BASIC_GID_T==3 +# define retropt_gidt(x,y,z) retropt_int(x,y,z) +#elif HAVE_BASIC_GID_T==4 +# define retropt_gidt(x,y,z) retropt_uint(x,y,z) +#elif HAVE_BASIC_GID_T==5 +# define retropt_gidt(x,y,z) retropt_long(x,y,z) +#elif HAVE_BASIC_GID_T==6 +# define retropt_gidt(x,y,z) retropt_ulong(x,y,z) +#endif + + +#endif /* !defined(__xioopen_h_included) */ diff --git a/xioopts.c b/xioopts.c new file mode 100644 index 0000000..d84b138 --- /dev/null +++ b/xioopts.c @@ -0,0 +1,3732 @@ +/* $Id: xioopts.c,v 1.99 2007/03/06 21:22:04 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for address options handling */ + +#include "xiosysincludes.h" +#include "xioopen.h" +#include "xio-unix.h" + +#include "xiomodes.h" +#include "xiolockfile.h" +#include "nestlex.h" + +bool xioopts_ignoregroups; + +#define IF_ANY(a,b) {a,b}, + +#if WITH_NAMED +# define IF_NAMED(a,b) {a,b}, +#else +# define IF_NAMED(a,b) +#endif + +#if WITH_PIPE || WITH_GOPEN +# define IF_OPEN(a,b) {a,b}, +#else +# define IF_OPEN(a,b) +#endif + +#if WITH_TERMIOS +# define IF_TERMIOS(a,b) {a,b}, +#else +# define IF_TERMIOS(a,b) +#endif + +#if WITH_EXEC +# define IF_EXEC(a,b) {a,b}, +#else +# define IF_EXEC(a,b) +#endif + +#if WITH_SOCKET +# define IF_SOCKET(a,b) {a,b}, +#else +# define IF_SOCKET(a,b) +#endif + +#if WITH_LISTEN +# define IF_LISTEN(a,b) {a,b}, +#else +# define IF_LISTEN(a,b) +#endif + +#if (WITH_UDP || WITH_TCP) && WITH_LISTEN +# define IF_RANGE(a,b) {a,b}, +#else +# define IF_RANGE(a,b) +#endif + +#if WITH_IP4 || WITH_IP6 +# define IF_IP(a,b) {a,b}, +#else +# define IF_IP(a,b) +#endif + +#if WITH_IP6 +# define IF_IP6(a,b) {a,b}, +#else +# define IF_IP6(a,b) +#endif + +#if WITH_TCP|WITH_UDP +# define IF_IPAPP(a,b) {a,b}, +#else +# define IF_IPAPP(a,b) +#endif + +#if WITH_TCP +# define IF_TCP(a,b) {a,b}, +#else +# define IF_TCP(a,b) +#endif + +#if WITH_SOCKS4 +# define IF_SOCKS4(a,b) {a,b}, +#else +# define IF_SOCKS4(a,b) +#endif + +#if WITH_PROXY +# define IF_PROXY(a,b) {a,b}, +#else +# define IF_PROXY(a,b) +#endif + +#if WITH_READLINE +# define IF_READLINE(a,b) {a,b}, +#else +# define IF_READLINE(a,b) +#endif + +#if WITH_PTY +# define IF_PTY(a,b) {a,b}, +#else +# define IF_PTY(a,b) +#endif + +#if WITH_OPENSSL +# define IF_OPENSSL(a,b) {a,b}, +#else +# define IF_OPENSSL(a,b) +#endif + +#if WITH_TUN +# define IF_TUN(a,b) {a,b}, +#else +# define IF_TUN(a,b) +#endif + +#if WITH_UNIX +# define IF_UNIX(a,b) {a,b}, +#else +# define IF_UNIX(a,b) +#endif + +#if WITH_RETRY +# define IF_RETRY(a,b) {a,b}, +#else +# define IF_RETRY(a,b) +#endif + + +static int applyopt_offset(struct single *xfd, struct opt *opt); + + +/* address options - keep this array strictly alphabetically sorted for + binary search! */ +/* NULL terminated */ +const struct optname optionnames[] = { +#if HAVE_RESOLV_H + IF_IP ("aaonly", &opt_res_aaonly) +#endif /* HAVE_RESOLV_H */ +#ifdef TCP_ABORT_THRESHOLD /* HP_UX */ + IF_TCP ("abort-threshold", &opt_tcp_abort_threshold) +#endif +#ifdef SO_ACCEPTCONN /* AIX433 */ + IF_SOCKET ("acceptconn", &opt_so_acceptconn) +#endif /* SO_ACCEPTCONN */ +#ifdef IP_ADD_MEMBERSHIP + IF_IP ("add-membership", &opt_ip_add_membership) +#endif + IF_TUN ("allmulti", &opt_iff_allmulti) +#if WITH_LIBWRAP && defined(HAVE_HOSTS_ALLOW_TABLE) + IF_IPAPP ("allow-table", &opt_tcpwrap_hosts_allow_table) +#endif + IF_ANY ("append", &opt_append) +#ifdef O_ASYNC + IF_ANY ("async", &opt_async) +#endif +#ifdef SO_ATTACH_FILTER + IF_SOCKET ("attach-filter", &opt_so_attach_filter) + IF_SOCKET ("attachfilter", &opt_so_attach_filter) +#endif +#ifdef SO_AUDIT /* AIX 4.3.3 */ + IF_SOCKET ("audit", &opt_so_audit) +#endif /* SO_AUDIT */ + IF_TUN ("automedia", &opt_iff_automedia) +#ifdef CBAUD + IF_TERMIOS("b0", &opt_b0) +#ifdef B1000000 + IF_TERMIOS("b1000000", &opt_b1000000) +#endif + IF_TERMIOS("b110", &opt_b110) +#ifdef B115200 + IF_TERMIOS("b115200", &opt_b115200) +#endif +#ifdef B1152000 + IF_TERMIOS("b1152000", &opt_b1152000) +#endif + IF_TERMIOS("b1200", &opt_b1200) + IF_TERMIOS("b134", &opt_b134) + IF_TERMIOS("b150", &opt_b150) +#ifdef B1500000 + IF_TERMIOS("b1500000", &opt_b1500000) +#endif + IF_TERMIOS("b1800", &opt_b1800) + IF_TERMIOS("b19200", &opt_b19200) + IF_TERMIOS("b200", &opt_b200) +#ifdef B2000000 + IF_TERMIOS("b2000000", &opt_b2000000) +#endif +#ifdef B230400 + IF_TERMIOS("b230400", &opt_b230400) +#endif + IF_TERMIOS("b2400", &opt_b2400) +#ifdef B2500000 + IF_TERMIOS("b2500000", &opt_b2500000) +#endif + IF_TERMIOS("b300", &opt_b300) +#ifdef B3000000 + IF_TERMIOS("b3000000", &opt_b3000000) +#endif +#ifdef B3500000 + IF_TERMIOS("b3500000", &opt_b3500000) +#endif +#ifdef B3600 /* HP-UX */ + IF_TERMIOS("b3600", &opt_b3600) +#endif + IF_TERMIOS("b38400", &opt_b38400) +#ifdef B4000000 + IF_TERMIOS("b4000000", &opt_b4000000) +#endif +#ifdef B460800 + IF_TERMIOS("b460800", &opt_b460800) +#endif + IF_TERMIOS("b4800", &opt_b4800) + IF_TERMIOS("b50", &opt_b50) +#ifdef B500000 + IF_TERMIOS("b500000", &opt_b500000) +#endif +#ifdef B57600 + IF_TERMIOS("b57600", &opt_b57600) +#endif +#ifdef B576000 + IF_TERMIOS("b576000", &opt_b576000) +#endif + IF_TERMIOS("b600", &opt_b600) +#ifdef B7200 /* HP-UX */ + IF_TERMIOS("b7200", &opt_b7200) +#endif + IF_TERMIOS("b75", &opt_b75) +#ifdef B900 /* HP-UX */ + IF_TERMIOS("b900", &opt_b900) +#endif +#ifdef B921600 + IF_TERMIOS("b921600", &opt_b921600) +#endif + IF_TERMIOS("b9600", &opt_b9600) +#endif /* defined(CBAUD) */ + IF_LISTEN ("backlog", &opt_backlog) +#ifdef O_BINARY + IF_OPEN ("bin", &opt_o_binary) + IF_OPEN ("binary", &opt_o_binary) +#endif + IF_SOCKET ("bind", &opt_bind) +#ifdef SO_BINDTODEVICE + IF_SOCKET ("bindtodevice", &opt_so_bindtodevice) +#endif + IF_TERMIOS("brkint", &opt_brkint) + IF_SOCKET ("broadcast", &opt_so_broadcast) +#ifdef BSDLY +# ifdef BS0 + IF_TERMIOS("bs0", &opt_bs0) +# endif +# ifdef BS1 + IF_TERMIOS("bs1", &opt_bs1) +# endif +#endif +#ifdef SO_BSDCOMPAT + IF_SOCKET ("bsdcompat", &opt_so_bsdcompat) +#endif +#ifdef BSDLY + IF_TERMIOS("bsdly", &opt_bsdly) +#endif + IF_ANY ("bytes", &opt_readbytes) + IF_OPENSSL("cafile", &opt_openssl_cafile) + IF_OPENSSL("capath", &opt_openssl_capath) + IF_OPENSSL("cert", &opt_openssl_certificate) + IF_OPENSSL("certificate", &opt_openssl_certificate) + IF_ANY ("chroot", &opt_chroot) + IF_ANY ("chroot-early", &opt_chroot_early) + /*IF_TERMIOS("cibaud", &opt_cibaud)*/ + IF_OPENSSL("cipher", &opt_openssl_cipherlist) + IF_OPENSSL("cipherlist", &opt_openssl_cipherlist) + IF_OPENSSL("ciphers", &opt_openssl_cipherlist) +#ifdef SO_CKSUMRECV + IF_SOCKET ("cksumrecv", &opt_so_cksumrecv) +#endif /* SO_CKSUMRECV */ + /*IF_NAMED ("cleanup", &opt_cleanup)*/ + IF_TERMIOS("clocal", &opt_clocal) + IF_ANY ("cloexec", &opt_cloexec) + IF_ANY ("close", &opt_end_close) +#if WITH_EXT2 && defined(EXT2_COMPR_FL) + IF_ANY ("compr", &opt_ext2_compr) +#endif +#ifdef TCP_CONN_ABORT_THRESHOLD /* HP_UX */ + IF_TCP ("conn-abort-threshold", &opt_tcp_conn_abort_threshold) +#endif + IF_SOCKET ("connect-timeout", &opt_connect_timeout) + IF_LISTEN ("cool-write", &opt_cool_write) + IF_LISTEN ("coolwrite", &opt_cool_write) +#ifdef TCP_CORK + IF_TCP ("cork", &opt_tcp_cork) +#endif + IF_ANY ("cr", &opt_cr) +#ifdef CRDLY +# ifdef CR0 + IF_TERMIOS("cr0", &opt_cr0) +# endif +# ifdef CR1 + IF_TERMIOS("cr1", &opt_cr1) +# endif +# ifdef CR2 + IF_TERMIOS("cr2", &opt_cr2) +# endif +# ifdef CR3 + IF_TERMIOS("cr3", &opt_cr3) +# endif + IF_TERMIOS("crdly", &opt_crdly) +#endif /* defined(CRDLY) */ + IF_TERMIOS("cread", &opt_cread) + IF_OPEN ("creat", &opt_o_create) + IF_OPEN ("create", &opt_o_create) + IF_ANY ("crlf", &opt_crnl) + IF_ANY ("crnl", &opt_crnl) + IF_TERMIOS("crterase", &opt_echoe) + IF_TERMIOS("crtkill", &opt_echoke) +#ifdef CRTSCTS + IF_TERMIOS("crtscts", &opt_crtscts) +#endif + IF_TERMIOS("cs5", &opt_cs5) + IF_TERMIOS("cs6", &opt_cs6) + IF_TERMIOS("cs7", &opt_cs7) + IF_TERMIOS("cs8", &opt_cs8) + IF_TERMIOS("csize", &opt_csize) + IF_TERMIOS("cstopb", &opt_cstopb) + IF_TERMIOS("ctlecho", &opt_echoctl) + IF_TERMIOS("ctty", &opt_tiocsctty) + IF_EXEC ("dash", &opt_dash) + IF_SOCKET ("debug", &opt_so_debug) + /*IF_IP ("debug", &opt_res_debug)*/ +#ifdef O_DEFER + IF_OPEN ("defer", &opt_o_defer) +#endif +#ifdef TCP_DEFER_ACCEPT /* Linux 2.4.0 */ + IF_TCP ("defer-accept", &opt_tcp_defer_accept) +#endif +#if HAVE_RESOLV_H + IF_IP ("defnames", &opt_res_defnames) +#endif /* HAVE_RESOLV_H */ +#ifdef O_DELAY + IF_OPEN ("delay", &opt_o_delay) +#endif + IF_NAMED ("delete", &opt_unlink) +#if WITH_LIBWRAP && defined(HAVE_HOSTS_DENY_TABLE) + IF_IPAPP ("deny-table", &opt_tcpwrap_hosts_deny_table) +#endif +#ifdef SO_DETACH_FILTER + IF_SOCKET ("detach-filter", &opt_so_detach_filter) + IF_SOCKET ("detachfilter", &opt_so_detach_filter) +#endif +#ifdef SO_DGRAM_ERRIND + IF_SOCKET ("dgram-errind", &opt_so_dgram_errind) + IF_SOCKET ("dgramerrind", &opt_so_dgram_errind) +#endif + IF_OPENSSL("dh", &opt_openssl_dhparam) + IF_OPENSSL("dhparam", &opt_openssl_dhparam) +#ifdef O_DIRECT + IF_OPEN ("direct", &opt_o_direct) +#endif +#ifdef O_DIRECTORY + IF_OPEN ("directory", &opt_o_directory) +#endif +#if WITH_EXT2 && defined(EXT2_DIRSYNC_FL) + IF_ANY ("dirsync", &opt_ext2_dirsync) +#endif +#ifdef VDISCARD + IF_TERMIOS("discard", &opt_vdiscard) +#endif +#if HAVE_RESOLV_H + IF_IP ("dnsrch", &opt_res_dnsrch) +#endif /* HAVE_RESOLV_H */ +#ifdef SO_DONTLINGER + IF_SOCKET ("dontlinger", &opt_so_dontlinger) +#endif + IF_SOCKET ("dontroute", &opt_so_dontroute) +#ifdef VDSUSP /* HP-UX */ + IF_TERMIOS("dsusp", &opt_vdsusp) +#endif +#ifdef O_DSYNC + IF_OPEN ("dsync", &opt_o_dsync) +#endif + IF_TERMIOS("echo", &opt_echo) + IF_TERMIOS("echoctl", &opt_echoctl) + IF_TERMIOS("echoe", &opt_echoe) + IF_TERMIOS("echok", &opt_echok) + IF_TERMIOS("echoke", &opt_echoke) + IF_TERMIOS("echonl", &opt_echonl) +#ifdef ECHOPRT + IF_TERMIOS("echoprt", &opt_echoprt) +#endif + IF_OPENSSL("egd", &opt_openssl_egd) + IF_ANY ("end-close", &opt_end_close) + IF_TERMIOS("eof", &opt_veof) + IF_TERMIOS("eol", &opt_veol) + IF_TERMIOS("eol2", &opt_veol2) + IF_TERMIOS("erase", &opt_verase) + IF_SOCKET ("error", &opt_so_error) + IF_OPEN ("excl", &opt_o_excl) +#if WITH_EXT2 && defined(EXT2_APPEND_FL) + IF_ANY ("ext2-append", &opt_ext2_append) +#endif +#if WITH_EXT2 && defined(EXT2_COMPR_FL) + IF_ANY ("ext2-compr", &opt_ext2_compr) +#endif +#if WITH_EXT2 && defined(EXT2_DIRSYNC_FL) + IF_ANY ("ext2-dirsync", &opt_ext2_dirsync) +#endif +#if WITH_EXT2 && defined(EXT2_IMMUTABLE_FL) + IF_ANY ("ext2-immutable", &opt_ext2_immutable) +#endif +#if WITH_EXT2 && defined(EXT2_JOURNAL_DATA_FL) + IF_ANY ("ext2-journal-data", &opt_ext2_journal_data) +#endif +#if WITH_EXT2 && defined(EXT2_NOATIME_FL) + IF_ANY ("ext2-noatime", &opt_ext2_noatime) +#endif +#if WITH_EXT2 && defined(EXT2_NODUMP_FL) + IF_ANY ("ext2-nodump", &opt_ext2_nodump) +#endif +#if WITH_EXT2 && defined(EXT2_NOTAIL_FL) + IF_ANY ("ext2-notail", &opt_ext2_notail) +#endif +#if WITH_EXT2 && defined(EXT2_SECRM_FL) + IF_ANY ("ext2-secrm", &opt_ext2_secrm) +#endif +#if WITH_EXT2 && defined(EXT2_SYNC_FL) + IF_ANY ("ext2-sync", &opt_ext2_sync) +#endif +#if WITH_EXT2 && defined(EXT2_TOPDIR_FL) + IF_ANY ("ext2-topdir", &opt_ext2_topdir) +#endif +#if WITH_EXT2 && defined(EXT2_UNRM_FL) + IF_ANY ("ext2-unrm", &opt_ext2_unrm) +#endif +#if WITH_EXT2 && defined(EXT2_APPEND_FL) + IF_ANY ("ext3-append", &opt_ext2_append) +#endif +#if WITH_EXT2 && defined(EXT2_COMPR_FL) + IF_ANY ("ext3-compr", &opt_ext2_compr) +#endif +#if WITH_EXT2 && defined(EXT2_DIRSYNC_FL) + IF_ANY ("ext3-dirsync", &opt_ext2_dirsync) +#endif +#if WITH_EXT2 && defined(EXT2_IMMUTABLE_FL) + IF_ANY ("ext3-immutable", &opt_ext2_immutable) +#endif +#if WITH_EXT2 && defined(EXT2_JOURNAL_DATA_FL) + IF_ANY ("ext3-journal-data", &opt_ext2_journal_data) +#endif +#if WITH_EXT2 && defined(EXT2_NOATIME_FL) + IF_ANY ("ext3-noatime", &opt_ext2_noatime) +#endif +#if WITH_EXT2 && defined(EXT2_NODUMP_FL) + IF_ANY ("ext3-nodump", &opt_ext2_nodump) +#endif +#if WITH_EXT2 && defined(EXT2_NOTAIL_FL) + IF_ANY ("ext3-notail", &opt_ext2_notail) +#endif +#if WITH_EXT2 && defined(EXT2_SECRM_FL) + IF_ANY ("ext3-secrm", &opt_ext2_secrm) +#endif +#if WITH_EXT2 && defined(EXT2_SYNC_FL) + IF_ANY ("ext3-sync", &opt_ext2_sync) +#endif +#if WITH_EXT2 && defined(EXT2_TOPDIR_FL) + IF_ANY ("ext3-topdir", &opt_ext2_topdir) +#endif +#if WITH_EXT2 && defined(EXT2_UNRM_FL) + IF_ANY ("ext3-unrm", &opt_ext2_unrm) +#endif + IF_ANY ("f-setlk", &opt_f_setlk_wr) + IF_ANY ("f-setlk-rd", &opt_f_setlk_rd) + IF_ANY ("f-setlk-wr", &opt_f_setlk_wr) + IF_ANY ("f-setlkw", &opt_f_setlkw_wr) + IF_ANY ("f-setlkw-rd", &opt_f_setlkw_rd) + IF_ANY ("f-setlkw-wr", &opt_f_setlkw_wr) + IF_EXEC ("fdin", &opt_fdin) + IF_EXEC ("fdout", &opt_fdout) +#ifdef FFDLY +# ifdef FF0 + IF_TERMIOS("ff0", &opt_ff0) +# endif +# ifdef FF1 + IF_TERMIOS("ff1", &opt_ff1) +# endif + IF_TERMIOS("ffdly", &opt_ffdly) +#endif +#ifdef FIOSETOWN + IF_SOCKET ("fiosetown", &opt_fiosetown) +#endif +#if WITH_FIPS + IF_OPENSSL("fips", &opt_openssl_fips) +#endif +#if HAVE_FLOCK + IF_ANY ("flock", &opt_flock_ex) + IF_ANY ("flock-ex", &opt_flock_ex) + IF_ANY ("flock-ex-nb", &opt_flock_ex_nb) + IF_ANY ("flock-nb", &opt_flock_ex_nb) + IF_ANY ("flock-sh", &opt_flock_sh) + IF_ANY ("flock-sh-nb", &opt_flock_sh_nb) +#endif + IF_TERMIOS("flusho", &opt_flusho) + IF_RETRY ("forever", &opt_forever) + IF_LISTEN ("fork", &opt_fork) +#ifdef IP_FREEBIND + IF_IP ("freebind", &opt_ip_freebind) +#endif +#if HAVE_FTRUNCATE64 + IF_ANY ("ftruncate", &opt_ftruncate64) +#else + IF_ANY ("ftruncate", &opt_ftruncate32) +#endif + IF_ANY ("ftruncate32", &opt_ftruncate32) +#if HAVE_FTRUNCATE64 + IF_ANY ("ftruncate64", &opt_ftruncate64) +#endif + IF_ANY ("gid", &opt_group) + IF_NAMED ("gid-e", &opt_group_early) + IF_ANY ("gid-l", &opt_group_late) + IF_ANY ("group", &opt_group) + IF_NAMED ("group-early", &opt_group_early) + IF_ANY ("group-late", &opt_group_late) +#ifdef IP_HDRINCL + IF_IP ("hdrincl", &opt_ip_hdrincl) +#endif + IF_READLINE("history", &opt_history_file) + IF_READLINE("history-file", &opt_history_file) +#if WITH_LIBWRAP && defined(HAVE_HOSTS_ALLOW_TABLE) + IF_IPAPP ("hosts-allow", &opt_tcpwrap_hosts_allow_table) +#endif +#if WITH_LIBWRAP && defined(HAVE_HOSTS_DENY_TABLE) + IF_IPAPP ("hosts-deny", &opt_tcpwrap_hosts_deny_table) +#endif + IF_TERMIOS("hup", &opt_hupcl) + IF_TERMIOS("hupcl", &opt_hupcl) + IF_TERMIOS("icanon", &opt_icanon) + IF_TERMIOS("icrnl", &opt_icrnl) + IF_TERMIOS("iexten", &opt_iexten) +#ifdef SO_BINDTODEVICE + IF_SOCKET ("if", &opt_so_bindtodevice) +#endif + IF_TUN ("iff-allmulti", &opt_iff_allmulti) + IF_TUN ("iff-automedia", &opt_iff_automedia) + IF_TUN ("iff-broadcast", &opt_iff_broadcast) + IF_TUN ("iff-debug", &opt_iff_debug) + /*IF_TUN ("iff-dynamic", &opt_iff_dynamic)*/ + IF_TUN ("iff-loopback", &opt_iff_loopback) + IF_TUN ("iff-master", &opt_iff_master) + IF_TUN ("iff-multicast", &opt_iff_multicast) + IF_TUN ("iff-no-pi", &opt_iff_no_pi) + IF_TUN ("iff-noarp", &opt_iff_noarp) + IF_TUN ("iff-notrailers", &opt_iff_notrailers) + IF_TUN ("iff-pointopoint", &opt_iff_pointopoint) + IF_TUN ("iff-portsel", &opt_iff_portsel) + IF_TUN ("iff-promisc", &opt_iff_promisc) + IF_TUN ("iff-running", &opt_iff_running) + IF_TUN ("iff-slave", &opt_iff_slave) + IF_TUN ("iff-up", &opt_iff_up) + IF_TERMIOS("ignbrk", &opt_ignbrk) + IF_TERMIOS("igncr", &opt_igncr) + /* you might need to terminate socat manually if you use this option: */ + IF_PROXY ("ignorecr", &opt_ignorecr) + IF_ANY ("ignoreeof", &opt_ignoreeof) + IF_ANY ("ignoreof", &opt_ignoreeof) + IF_TERMIOS("ignpar", &opt_ignpar) +#if HAVE_RESOLV_H + IF_IP ("igntc", &opt_res_igntc) +#endif /* HAVE_RESOLV_H */ + IF_TERMIOS("imaxbel", &opt_imaxbel) +#if WITH_EXT2 && defined(EXT2_IMMUTABLE_FL) + IF_ANY ("immutable", &opt_ext2_immutable) +#endif +#ifdef TCP_INFO /* Linux 2.4.0 */ + IF_TCP ("info", &opt_tcp_info) +#endif + IF_TERMIOS("inlcr", &opt_inlcr) + IF_TERMIOS("inpck", &opt_inpck) +#ifdef SO_BINDTODEVICE + IF_SOCKET ("interface", &opt_so_bindtodevice) +#endif + IF_RETRY ("intervall", &opt_intervall) + IF_TERMIOS("intr", &opt_vintr) +#ifdef IP_ADD_MEMBERSHIP + IF_IP ("ip-add-membership", &opt_ip_add_membership) +#endif +#ifdef IP_FREEBIND + IF_IP ("ip-freebind", &opt_ip_freebind) +#endif +#ifdef IP_HDRINCL + IF_IP ("ip-hdrincl", &opt_ip_hdrincl) +#endif +#ifdef IP_ADD_MEMBERSHIP + IF_IP ("ip-membership", &opt_ip_add_membership) +#endif +#ifdef IP_MTU + IF_IP ("ip-mtu", &opt_ip_mtu) +#endif +#ifdef IP_MTU_DISCOVER + IF_IP ("ip-mtu-discover", &opt_ip_mtu_discover) +#endif + IF_IP ("ip-multicast-if", &opt_ip_multicast_if) + IF_IP ("ip-multicast-loop", &opt_ip_multicast_loop) + IF_IP ("ip-multicast-ttl", &opt_ip_multicast_ttl) +#ifdef IP_OPTIONS + IF_IP ("ip-options", &opt_ip_options) +#endif +#ifdef IP_PKTINFO + IF_IP ("ip-pktinfo", &opt_ip_pktinfo) +#endif +#ifdef IP_PKTOPTIONS + IF_IP ("ip-pktoptions", &opt_ip_pktoptions) +#endif +#ifdef IP_RECVERR + IF_IP ("ip-recverr", &opt_ip_recverr) +#endif +#ifdef IP_RECVOPTS + IF_IP ("ip-recvopts", &opt_ip_recvopts) +#endif +#ifdef IP_RECVTOS + IF_IP ("ip-recvtos", &opt_ip_recvtos) +#endif +#ifdef IP_RECVTTL + IF_IP ("ip-recvttl", &opt_ip_recvttl) +#endif +#ifdef IP_RETOPTS + IF_IP ("ip-retopts", &opt_ip_retopts) +#endif +#ifdef IP_ROUTER_ALERT + IF_IP ("ip-router-alert", &opt_ip_router_alert) +#endif + IF_IP ("ip-tos", &opt_ip_tos) + IF_IP ("ip-ttl", &opt_ip_ttl) +#ifdef IP_FREEBIND + IF_IP ("ipfreebind", &opt_ip_freebind) +#endif +#ifdef IP_HDRINCL + IF_IP ("iphdrincl", &opt_ip_hdrincl) +#endif +#ifdef IP_MTU + IF_IP ("ipmtu", &opt_ip_mtu) +#endif +#ifdef IP_MTU_DISCOVER + IF_IP ("ipmtudiscover", &opt_ip_mtu_discover) +#endif + IF_IP ("ipmulticastloop", &opt_ip_multicast_loop) + IF_IP ("ipmulticastttl", &opt_ip_multicast_ttl) +#ifdef IP_OPTIONS + IF_IP ("ipoptions", &opt_ip_options) +#endif +#ifdef IP_PKTINFO + IF_IP ("ippktinfo", &opt_ip_pktinfo) +#endif +#ifdef IP_PKTOPTIONS + IF_IP ("ippktoptions", &opt_ip_pktoptions) +#endif +#ifdef IP_RECVERR + IF_IP ("iprecverr", &opt_ip_recverr) +#endif +#ifdef IP_RECVOPTS + IF_IP ("iprecvopts", &opt_ip_recvopts) +#endif +#ifdef IP_RECVTOS + IF_IP ("iprecvtos", &opt_ip_recvtos) +#endif +#ifdef IP_RECVTTL + IF_IP ("iprecvttl", &opt_ip_recvttl) +#endif +#ifdef IP_RETOPTS + IF_IP ("ipretopts", &opt_ip_retopts) +#endif +#ifdef IP_ROUTER_ALERT + IF_IP ("iprouteralert", &opt_ip_router_alert) +#endif + IF_IP ("iptos", &opt_ip_tos) + IF_IP ("ipttl", &opt_ip_ttl) + IF_IP6 ("ipv6-add-membership", &opt_ipv6_join_group) + IF_IP6 ("ipv6-join-group", &opt_ipv6_join_group) +#ifdef IPV6_V6ONLY + IF_IP6 ("ipv6-v6only", &opt_ipv6_v6only) + IF_IP6 ("ipv6only", &opt_ipv6_v6only) +#endif + IF_TERMIOS("isig", &opt_isig) +#ifdef HAVE_TERMIOS_ISPEED + IF_TERMIOS("ispeed", &opt_ispeed) +#endif + IF_TERMIOS("istrip", &opt_istrip) +#ifdef IUCLC + IF_TERMIOS("iuclc", &opt_iuclc) +#endif + IF_TERMIOS("ixany", &opt_ixany) + IF_TERMIOS("ixoff", &opt_ixoff) + IF_TERMIOS("ixon", &opt_ixon) + IF_IP6 ("join-group", &opt_ipv6_join_group) +#if WITH_EXT2 && defined(EXT2_JOURNAL_DATA_FL) + IF_ANY ("journal", &opt_ext2_journal_data) + IF_ANY ("journal-data", &opt_ext2_journal_data) +#endif + IF_SOCKET ("keepalive", &opt_so_keepalive) +#ifdef TCP_KEEPCNT /* Linux 2.4.0 */ + IF_TCP ("keepcnt", &opt_tcp_keepcnt) +#endif +#ifdef TCP_KEEPIDLE /* Linux 2.4.0 */ + IF_TCP ("keepidle", &opt_tcp_keepidle) +#endif +#ifdef TCP_KEEPINIT /* OSF1 */ + IF_TCP ("keepinit", &opt_tcp_keepinit) +#endif +#ifdef TCP_KEEPINTVL /* Linux 2.4.0 */ + IF_TCP ("keepintvl", &opt_tcp_keepintvl) +#endif +#ifdef SO_KERNACCEPT /* AIX 4.3.3 */ + IF_SOCKET ("kernaccept", &opt_so_kernaccept) +#endif /* SO_KERNACCEPT */ + IF_OPENSSL("key", &opt_openssl_key) + IF_TERMIOS("kill", &opt_vkill) +#ifdef O_LARGEFILE + IF_OPEN ("largefile", &opt_o_largefile) +#endif +#if WITH_LIBWRAP + IF_IPAPP ("libwrap", &opt_tcpwrappers) +#endif + IF_SOCKET ("linger", &opt_so_linger) +#ifdef TCP_LINGER2 /* Linux 2.4.0 */ + IF_TCP ("linger2", &opt_tcp_linger2) +#endif + IF_PTY ("link", &opt_symbolic_link) + IF_TERMIOS("lnext", &opt_vlnext) +#if defined(F_SETLKW) + IF_ANY ("lock", &opt_f_setlkw_wr) /* POSIX, first choice */ +#elif defined(HAVE_FLOCK) + IF_ANY ("lock", &opt_flock_ex) /* BSD, fallback */ +#endif + IF_ANY ("lockfile", &opt_lockfile) +#if defined(F_SETLKW) + IF_ANY ("lockw", &opt_f_setlkw_wr) /* POSIX, first choice */ +#elif defined(HAVE_FLOCK) + IF_ANY ("lockw", &opt_flock_ex_nb) /* BSD, fallback */ +#endif + IF_EXEC ("login", &opt_dash) + IF_TUN ("loopback", &opt_iff_loopback) + IF_IPAPP ("lowport", &opt_lowport) +#if HAVE_LSEEK64 + IF_ANY ("lseek", &opt_lseek64_set) +#else + IF_ANY ("lseek", &opt_lseek32_set) +#endif + IF_ANY ("lseek32", &opt_lseek32_set) + IF_ANY ("lseek32-cur", &opt_lseek32_cur) + IF_ANY ("lseek32-end", &opt_lseek32_end) + IF_ANY ("lseek32-set", &opt_lseek32_set) +#if HAVE_LSEEK64 + IF_ANY ("lseek64", &opt_lseek64_set) + IF_ANY ("lseek64-cur", &opt_lseek64_cur) + IF_ANY ("lseek64-end", &opt_lseek64_end) + IF_ANY ("lseek64-set", &opt_lseek64_set) +#endif + IF_TUN ("master", &opt_iff_master) +#ifdef TCP_MAXSEG + IF_TCP ("maxseg", &opt_tcp_maxseg) + IF_TCP ("maxseg-late", &opt_tcp_maxseg_late) +#endif +#ifdef TCP_MD5SUM + IF_TCP ("md5sig", &opt_tcp_md5sig) +#endif +#ifdef IP_ADD_MEMBERSHIP + IF_IP ("membership", &opt_ip_add_membership) +#endif + IF_OPENSSL("method", &opt_openssl_method) + IF_TERMIOS("min", &opt_vmin) + IF_ANY ("mode", &opt_perm) +#ifdef TCP_MAXSEG + IF_TCP ("mss", &opt_tcp_maxseg) + IF_TCP ("mss-late", &opt_tcp_maxseg_late) +#endif +#ifdef IP_MTU + IF_IP ("mtu", &opt_ip_mtu) +#endif +#ifdef IP_MTU_DISCOVER + IF_IP ("mtudiscover", &opt_ip_mtu_discover) +#endif + IF_TUN ("multicast", &opt_iff_multicast) + IF_IP ("multicast-if", &opt_ip_multicast_if) + IF_IP ("multicast-loop", &opt_ip_multicast_loop) + IF_IP ("multicast-ttl", &opt_ip_multicast_ttl) + IF_IP ("multicastloop", &opt_ip_multicast_loop) + IF_IP ("multicastttl", &opt_ip_multicast_ttl) +#if defined(O_NDELAY) && (!defined(O_NONBLOCK) || O_NDELAY != O_NONBLOCK) + IF_ANY ("ndelay", &opt_o_ndelay) +#else + IF_ANY ("ndelay", &opt_nonblock) +#endif + IF_NAMED ("new", &opt_unlink_early) +#ifdef NLDLY +# ifdef NL0 + IF_TERMIOS("nl0", &opt_nl0) +# endif +# ifdef NL1 + IF_TERMIOS("nl1", &opt_nl1) +# endif + IF_TERMIOS("nldly", &opt_nldly) +#endif /* defined(NLDLY) */ +#ifdef SO_NO_CHECK + IF_SOCKET ("no-check", &opt_so_no_check) +#endif + IF_TUN ("no-pi", &opt_iff_no_pi) + IF_TUN ("noarp", &opt_iff_noarp) +#ifdef O_NOATIME + IF_OPEN ("noatime", &opt_o_noatime) +#endif +#ifdef SO_NO_CHECK + IF_SOCKET ("nocheck", &opt_so_no_check) +#endif + IF_OPEN ("noctty", &opt_o_noctty) +#ifdef TCP_NODELAY + IF_TCP ("nodelay", &opt_tcp_nodelay) +#endif +#if WITH_EXT2 && defined(EXT2_NODUMP_FL) + IF_ANY ("nodump", &opt_ext2_nodump) +#endif +#if HAVE_REGEX_H + IF_READLINE("noecho", &opt_noecho) +#endif /* HAVE_REGEX_H */ + IF_TERMIOS("noflsh", &opt_noflsh) +#ifdef O_NOFOLLOW + IF_OPEN ("nofollow", &opt_o_nofollow) +#endif + IF_EXEC ("nofork", &opt_nofork) +#ifdef O_NOINHERIT + IF_ANY ("noinherit", &opt_o_noinherit) +#endif + IF_ANY ("nonblock", &opt_nonblock) +#ifdef TCP_NOOPT + IF_TCP ("noopt", &opt_tcp_noopt) +#endif + IF_READLINE("noprompt", &opt_noprompt) +#ifdef TCP_NOPUSH + IF_TCP ("nopush", &opt_tcp_nopush) +#endif +#ifdef SO_NOREUSEADDR /* AIX 4.3.3 */ + IF_SOCKET ("noreuseaddr", &opt_so_noreuseaddr) +#endif /* SO_NOREUSEADDR */ + IF_TUN ("notrailers", &opt_iff_notrailers) +#ifdef O_NSHARE + IF_OPEN ("nshare", &opt_o_nshare) +#endif +#ifdef O_ASYNC + IF_ANY ("o-async", &opt_async) +#endif +#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) +#ifdef O_DEFER + IF_OPEN ("o-defer", &opt_o_defer) +#endif +#ifdef O_DELAY + IF_OPEN ("o-delay", &opt_o_delay) +#endif +#ifdef O_DIRECT + IF_OPEN ("o-direct", &opt_o_direct) +#endif +#ifdef O_DIRECTORY + IF_OPEN ("o-directory", &opt_o_directory) +#endif +#ifdef O_DSYNC + IF_OPEN ("o-dsync", &opt_o_dsync) +#endif + IF_OPEN ("o-excl", &opt_o_excl) +#ifdef O_LARGEFILE + IF_OPEN ("o-largefile", &opt_o_largefile) +#endif +#if defined(O_NDELAY) && (!defined(O_NONBLOCK) || O_NDELAY != O_NONBLOCK) + IF_ANY ("o-ndelay", &opt_o_ndelay) +#else + IF_ANY ("o-ndelay", &opt_nonblock) +#endif +#ifdef O_NOATIME + IF_OPEN ("o-noatime", &opt_o_noatime) +#endif + IF_OPEN ("o-noctty", &opt_o_noctty) +#ifdef O_NOFOLLOW + IF_OPEN ("o-nofollow", &opt_o_nofollow) +#endif +#ifdef O_NOINHERIT + IF_ANY ("o-noinherit", &opt_o_noinherit) +#endif + IF_ANY ("o-nonblock", &opt_nonblock) +#ifdef O_NSHARE + IF_OPEN ("o-nshare", &opt_o_nshare) +#endif +#ifdef O_PRIV + IF_OPEN ("o-priv", &opt_o_priv) +#endif + IF_OPEN ("o-rdonly", &opt_o_rdonly) + IF_OPEN ("o-rdwr", &opt_o_rdwr) +#ifdef O_RSHARE + IF_OPEN ("o-rshare", &opt_o_rshare) +#endif +#ifdef O_RSYNC + IF_OPEN ("o-rsync", &opt_o_rsync) +#endif +#ifdef O_SYNC + IF_OPEN ("o-sync", &opt_o_sync) +#endif +#ifdef O_TEXT + IF_ANY ("o-text", &opt_o_text) +#endif + IF_OPEN ("o-trunc", &opt_o_trunc) + IF_OPEN ("o-wronly", &opt_o_wronly) + IF_OPEN ("o_create", &opt_o_create) +#ifdef O_DEFER + IF_OPEN ("o_defer", &opt_o_defer) +#endif +#ifdef O_DELAY + IF_OPEN ("o_delay", &opt_o_delay) +#endif +#ifdef O_DIRECT + IF_OPEN ("o_direct", &opt_o_direct) +#endif +#ifdef O_DIRECTORY + IF_OPEN ("o_directory", &opt_o_directory) +#endif +#ifdef O_DSYNC + IF_OPEN ("o_dsync", &opt_o_dsync) +#endif + IF_OPEN ("o_excl", &opt_o_excl) +#ifdef O_LARGEFILE + IF_OPEN ("o_largefile", &opt_o_largefile) +#endif +#if defined(O_NDELAY) && (!defined(O_NONBLOCK) || O_NDELAY != O_NONBLOCK) + IF_ANY ("o_ndelay", &opt_o_ndelay) +#else + IF_ANY ("o_ndelay", &opt_nonblock) +#endif + IF_OPEN ("o_noctty", &opt_o_noctty) +#ifdef O_NOFOLLOW + IF_OPEN ("o_nofollow", &opt_o_nofollow) +#endif +#ifdef O_NSHARE + IF_OPEN ("o_nshare", &opt_o_nshare) +#endif +#ifdef O_PRIV + IF_OPEN ("o_priv", &opt_o_priv) +#endif + IF_OPEN ("o_rdonly", &opt_o_rdonly) + IF_OPEN ("o_rdwr", &opt_o_rdwr) +#ifdef O_RSHARE + IF_OPEN ("o_rshare", &opt_o_rshare) +#endif +#ifdef O_RSYNC + IF_OPEN ("o_rsync", &opt_o_rsync) +#endif +#ifdef O_SYNC + IF_OPEN ("o_sync", &opt_o_sync) +#endif + IF_OPEN ("o_wronly", &opt_o_wronly) +#ifdef OCRNL + IF_TERMIOS("ocrnl", &opt_ocrnl) +#endif +#ifdef OFDEL + IF_TERMIOS("ofdel", &opt_ofdel) +#endif +#ifdef OFILL + IF_TERMIOS("ofill", &opt_ofill) +#endif +#ifdef OLCUC + IF_TERMIOS("olcuc", &opt_olcuc) +#endif + IF_TERMIOS("onlcr", &opt_onlcr) +#ifdef ONLRET + IF_TERMIOS("onlret", &opt_onlret) +#endif +#ifdef ONOCR + IF_TERMIOS("onocr", &opt_onocr) +#endif + IF_SOCKET ("oobinline", &opt_so_oobinline) +#if HAVE_OPENPTY + IF_EXEC ("openpty", &opt_openpty) +#endif /* HAVE_OPENPTY */ + IF_OPENSSL("openssl-cafile", &opt_openssl_cafile) + IF_OPENSSL("openssl-capath", &opt_openssl_capath) + IF_OPENSSL("openssl-certificate", &opt_openssl_certificate) + IF_OPENSSL("openssl-cipherlist", &opt_openssl_cipherlist) + IF_OPENSSL("openssl-dhparam", &opt_openssl_dhparam) + IF_OPENSSL("openssl-egd", &opt_openssl_egd) +#if WITH_FIPS + IF_OPENSSL("openssl-fips", &opt_openssl_fips) +#endif + IF_OPENSSL("openssl-key", &opt_openssl_key) + IF_OPENSSL("openssl-method", &opt_openssl_method) + IF_OPENSSL("openssl-pseudo", &opt_openssl_pseudo) + IF_OPENSSL("openssl-verify", &opt_openssl_verify) + IF_TERMIOS("opost", &opt_opost) +#ifdef HAVE_TERMIOS_ISPEED + IF_TERMIOS("ospeed", &opt_ospeed) +#endif + IF_ANY ("owner", &opt_user) + IF_TERMIOS("parenb", &opt_parenb) + IF_TERMIOS("parmrk", &opt_parmrk) + IF_TERMIOS("parodd", &opt_parodd) +#ifdef SO_PASSCRED + IF_SOCKET ("passcred", &opt_so_passcred) +#endif + IF_EXEC ("path", &opt_path) +#ifdef TCP_PAWS /* OSF1 */ + IF_TCP ("paws", &opt_tcp_paws) +#endif +#ifdef SO_PEERCRED + IF_SOCKET ("peercred", &opt_so_peercred) +#endif +#ifdef PENDIN + IF_TERMIOS("pendin", &opt_pendin) +#endif + IF_ANY ("perm", &opt_perm) + IF_NAMED ("perm-early", &opt_perm_early) + IF_ANY ("perm-late", &opt_perm_late) + IF_SOCKET ("pf", &opt_protocol_family) + IF_EXEC ("pgid", &opt_setpgid) + IF_EXEC ("pipes", &opt_pipes) +#ifdef IP_PKTINFO + IF_IP ("pktinfo", &opt_ip_pktinfo) +#endif +#ifdef IP_PKTOPTIONS + IF_IP ("pktoptions", &opt_ip_pktoptions) + IF_IP ("pktopts", &opt_ip_pktoptions) +#endif + IF_TUN ("pointopoint", &opt_iff_pointopoint) + /*IF_IPAPP("port", &opt_port)*/ + IF_TUN ("portsel", &opt_iff_portsel) +#if HAVE_RESOLV_H + IF_IP ("primary", &opt_res_primary) +#endif /* HAVE_RESOLV_H */ +#ifdef SO_PRIORITY + IF_SOCKET ("priority", &opt_so_priority) +#endif +#ifdef O_PRIV + IF_OPEN ("priv", &opt_o_priv) +#endif + IF_TUN ("promisc", &opt_iff_promisc) + IF_READLINE("prompt", &opt_prompt) + IF_SOCKET ("protocol-family", &opt_protocol_family) +#ifdef SO_PROTOTYPE + IF_SOCKET ("prototype", &opt_so_prototype) +#endif + IF_PROXY ("proxy-authorization", &opt_proxy_authorization) + IF_PROXY ("proxy-auth", &opt_proxy_authorization) + IF_PROXY ("proxy-resolve", &opt_proxy_resolve) + IF_PROXY ("proxyauth", &opt_proxy_authorization) + IF_PROXY ("proxyport", &opt_proxyport) +#ifdef ECHOPRT + IF_TERMIOS("prterase", &opt_echoprt) +#endif + IF_OPENSSL("pseudo", &opt_openssl_pseudo) +#if HAVE_DEV_PTMX || HAVE_DEV_PTC + IF_EXEC ("ptmx", &opt_ptmx) +#endif +#if HAVE_PTY + IF_EXEC ("pty", &opt_pty) +#endif +#if HAVE_PTY && HAVE_POLL + IF_PTY ("pty-intervall", &opt_pty_intervall) + IF_PTY ("pty-wait-slave", &opt_pty_wait_slave) +#endif /* HAVE_PTY && HAVE_POLL */ +#ifdef TCP_QUICKACK + IF_TCP ("quickack", &opt_tcp_quickack) +#endif + IF_TERMIOS("quit", &opt_vquit) + IF_RANGE ("range", &opt_range) + IF_TERMIOS("raw", &opt_raw) + IF_SOCKET ("rcvbuf", &opt_so_rcvbuf) + IF_SOCKET ("rcvbuf-late", &opt_so_rcvbuf_late) +#ifdef SO_RCVLOWAT + IF_SOCKET ("rcvlowat", &opt_so_rcvlowat) +#endif +#ifdef SO_RCVTIMEO + IF_SOCKET ("rcvtimeo", &opt_so_rcvtimeo) +#endif + IF_OPEN ("rdonly", &opt_o_rdonly) + IF_OPEN ("rdwr", &opt_o_rdwr) + IF_ANY ("readbytes", &opt_readbytes) +#if HAVE_RESOLV_H + IF_IP ("recurse", &opt_res_recurse) +#endif /* HAVE_RESOLV_H */ +#ifdef IP_RECVERR + IF_IP ("recverr", &opt_ip_recverr) +#endif +#ifdef IP_RECVOPTS + IF_IP ("recvopts", &opt_ip_recvopts) +#endif +#ifdef IP_RECVTOS + IF_IP ("recvtos", &opt_ip_recvtos) +#endif +#ifdef IP_RECVTTL + IF_IP ("recvttl", &opt_ip_recvttl) +#endif + IF_NAMED ("remove", &opt_unlink) +#ifdef VREPRINT + IF_TERMIOS("reprint", &opt_vreprint) +#endif +#if HAVE_RESOLV_H + IF_IP ("res-aaonly", &opt_res_aaonly) + IF_IP ("res-debug", &opt_res_debug) + IF_IP ("res-defnames", &opt_res_defnames) + IF_IP ("res-dnsrch", &opt_res_dnsrch) + IF_IP ("res-igntc", &opt_res_igntc) + IF_IP ("res-primary", &opt_res_primary) + IF_IP ("res-recurse", &opt_res_recurse) + IF_IP ("res-stayopen", &opt_res_stayopen) + IF_IP ("res-usevc", &opt_res_usevc) +#endif /* 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_RETRY ("retry", &opt_retry) + IF_SOCKET ("reuseaddr", &opt_so_reuseaddr) +#ifdef SO_REUSEPORT /* AIX 4.3.3 */ + IF_SOCKET ("reuseport", &opt_so_reuseport) +#endif /* defined(SO_REUSEPORT) */ +#ifdef TCP_RFC1323 + IF_TCP ("rfc1323", &opt_tcp_rfc1323) +#endif +#ifdef IP_ROUTER_ALERT + IF_IP ("routeralert", &opt_ip_router_alert) +#endif +#ifdef VREPRINT + IF_TERMIOS("rprnt", &opt_vreprint) +#endif +#ifdef O_RSHARE + IF_OPEN ("rshare", &opt_o_rshare) +#endif +#ifdef O_RSYNC + IF_OPEN ("rsync", &opt_o_rsync) +#endif + IF_TUN ("running", &opt_iff_running) +#ifdef TCP_SACK_DISABLE + IF_TCP ("sack-disable", &opt_tcp_sack_disable) +#endif +#ifdef TCP_SACKENA /* OSF1 */ + IF_TCP ("sackena", &opt_tcp_sackena) +#endif + IF_TERMIOS("sane", &opt_sane) +#if WITH_EXT2 && defined(EXT2_SECRM_FL) + IF_ANY ("secrm", &opt_ext2_secrm) +#endif +#ifdef SO_SECURITY_AUTHENTICATION + IF_SOCKET ("security-authentication", &opt_so_security_authentication) +#endif +#ifdef SO_SECURITY_ENCRYPTION_NETWORK + IF_SOCKET ("security-encryption-network", &opt_so_security_encryption_network) +#endif +#ifdef SO_SECURITY_ENCRYPTION_TRANSPORT + IF_SOCKET ("security-encryption-transport", &opt_so_security_encryption_transport) +#endif +#ifdef SO_SECURITY_AUTHENTICATION + IF_SOCKET ("securityauthentication", &opt_so_security_authentication) +#endif +#ifdef SO_SECURITY_ENCRYPTION_NETWORK + IF_SOCKET ("securityencryptionnetwork", &opt_so_security_encryption_network) +#endif +#ifdef SO_SECURITY_ENCRYPTION_TRANSPORT + IF_SOCKET ("securityencryptiontransport", &opt_so_security_encryption_transport) +#endif +#if HAVE_LSEEK64 + IF_ANY ("seek", &opt_lseek64_set) + IF_ANY ("seek-cur", &opt_lseek64_cur) + IF_ANY ("seek-end", &opt_lseek64_end) + IF_ANY ("seek-set", &opt_lseek64_set) +#else + IF_ANY ("seek", &opt_lseek32_set) + IF_ANY ("seek-cur", &opt_lseek32_cur) + IF_ANY ("seek-end", &opt_lseek32_end) + IF_ANY ("seek-set", &opt_lseek32_set) +#endif + IF_ANY ("setgid", &opt_setgid) + IF_ANY ("setgid-early", &opt_setgid_early) + IF_ANY ("setlk", &opt_f_setlk_wr) + IF_ANY ("setlk-rd", &opt_f_setlk_rd) + IF_ANY ("setlk-wr", &opt_f_setlk_wr) + IF_ANY ("setlkw", &opt_f_setlkw_wr) + IF_ANY ("setlkw-rd", &opt_f_setlkw_rd) + IF_ANY ("setlkw-wr", &opt_f_setlkw_wr) + IF_EXEC ("setpgid", &opt_setpgid) +#if WITH_EXEC || WITH_SYSTEM + IF_EXEC ("setsid", &opt_setsid) +#endif + IF_ANY ("setuid", &opt_setuid) + IF_ANY ("setuid-early", &opt_setuid_early) +#if WITH_EXEC || WITH_SYSTEM + IF_ANY ("sid", &opt_setsid) +#endif + IF_EXEC ("sighup", &opt_sighup) + IF_EXEC ("sigint", &opt_sigint) +#ifdef TCP_SIGNATURE_ENABLE + IF_TCP ("signature-enable", &opt_tcp_signature_enable) +#endif + IF_EXEC ("sigquit", &opt_sigquit) +#ifdef SIOCSPGRP + IF_SOCKET ("siocspgrp", &opt_siocspgrp) +#endif + IF_TUN ("slave", &opt_iff_slave) + IF_SOCKET ("sndbuf", &opt_so_sndbuf) + IF_SOCKET ("sndbuf-late", &opt_so_sndbuf_late) +#ifdef SO_SNDLOWAT + IF_SOCKET ("sndlowat", &opt_so_sndlowat) +#endif +#ifdef SO_SNDTIMEO + IF_SOCKET ("sndtimeo", &opt_so_sndtimeo) +#endif +#ifdef SO_ACCEPTCONN /* AIX433 */ + IF_SOCKET ("so-acceptconn", &opt_so_acceptconn) +#endif /* SO_ACCEPTCONN */ +#ifdef SO_ATTACH_FILTER + IF_SOCKET ("so-attach-filter", &opt_so_attach_filter) +#endif +#ifdef SO_AUDIT /* AIX 4.3.3 */ + IF_SOCKET ("so-audit", &opt_so_audit) +#endif /* SO_AUDIT */ +#ifdef SO_BINDTODEVICE + IF_SOCKET ("so-bindtodevice", &opt_so_bindtodevice) +#endif + IF_SOCKET ("so-broadcast", &opt_so_broadcast) +#ifdef SO_BSDCOMPAT + IF_SOCKET ("so-bsdcompat", &opt_so_bsdcompat) +#endif +#ifdef SO_CKSUMRECV + IF_SOCKET ("so-cksumrecv", &opt_so_cksumrecv) +#endif /* SO_CKSUMRECV */ + IF_SOCKET ("so-debug", &opt_so_debug) +#ifdef SO_DETACH_FILTER + IF_SOCKET ("so-detach-filter", &opt_so_detach_filter) +#endif +#ifdef SO_DGRAM_ERRIND + IF_SOCKET ("so-dgram-errind", &opt_so_dgram_errind) +#endif +#ifdef SO_DONTLINGER + IF_SOCKET ("so-dontlinger", &opt_so_dontlinger) +#endif + IF_SOCKET ("so-dontroute", &opt_so_dontroute) + IF_SOCKET ("so-error", &opt_so_error) + IF_SOCKET ("so-keepalive", &opt_so_keepalive) +#ifdef SO_KERNACCEPT /* AIX 4.3.3 */ + IF_SOCKET ("so-kernaccept", &opt_so_kernaccept) +#endif /* SO_KERNACCEPT */ + IF_SOCKET ("so-linger", &opt_so_linger) +#ifdef SO_NO_CHECK + IF_SOCKET ("so-no-check", &opt_so_no_check) +#endif +#ifdef SO_NOREUSEADDR /* AIX 4.3.3 */ + IF_SOCKET ("so-noreuseaddr", &opt_so_noreuseaddr) +#endif /* SO_NOREUSEADDR */ + IF_SOCKET ("so-oobinline", &opt_so_oobinline) +#ifdef SO_PASSCRED + IF_SOCKET ("so-passcred", &opt_so_passcred) +#endif +#ifdef SO_PEERCRED + IF_SOCKET ("so-peercred", &opt_so_peercred) +#endif +#ifdef SO_PRIORITY + IF_SOCKET ("so-priority", &opt_so_priority) +#endif +#ifdef SO_PROTOTYPE + IF_SOCKET ("so-prototype", &opt_so_prototype) +#endif + IF_SOCKET ("so-rcvbuf", &opt_so_rcvbuf) + IF_SOCKET ("so-rcvbuf-late", &opt_so_rcvbuf_late) +#ifdef SO_RCVLOWAT + IF_SOCKET ("so-rcvlowat", &opt_so_rcvlowat) +#endif +#ifdef SO_RCVTIMEO + IF_SOCKET ("so-rcvtimeo", &opt_so_rcvtimeo) +#endif + IF_SOCKET ("so-reuseaddr", &opt_so_reuseaddr) +#ifdef SO_REUSEPORT /* AIX 4.3.3 */ + IF_SOCKET ("so-reuseport", &opt_so_reuseport) +#endif /* defined(SO_REUSEPORT) */ +#ifdef SO_SECURITY_AUTHENTICATION + IF_SOCKET ("so-security-authentication", &opt_so_security_authentication) +#endif +#ifdef SO_SECURITY_ENCRYPTION_NETWORK + IF_SOCKET ("so-security-encryption-network", &opt_so_security_encryption_network) +#endif +#ifdef SO_SECURITY_ENCRYPTION_TRANSPORT + IF_SOCKET ("so-security-encryption-transport", &opt_so_security_encryption_transport) +#endif + IF_SOCKET ("so-sndbuf", &opt_so_sndbuf) + IF_SOCKET ("so-sndbuf-late", &opt_so_sndbuf_late) +#ifdef SO_SNDLOWAT + IF_SOCKET ("so-sndlowat", &opt_so_sndlowat) +#endif +#ifdef SO_SNDTIMEO + IF_SOCKET ("so-sndtimeo", &opt_so_sndtimeo) +#endif + IF_SOCKET ("so-type", &opt_so_type) +#ifdef SO_USE_IFBUFS + IF_SOCKET ("so-use-ifbufs", &opt_so_use_ifbufs) +#endif /* SO_USE_IFBUFS */ +#ifdef SO_USELOOPBACK /* AIX433, Solaris */ + IF_SOCKET ("so-useloopback", &opt_so_useloopback) +#endif /* SO_USELOOPBACK */ + IF_SOCKS4 ("socksport", &opt_socksport) + IF_SOCKS4 ("socksuser", &opt_socksuser) + IF_IPAPP ("sourceport", &opt_sourceport) + IF_IPAPP ("sp", &opt_sourceport) + IF_TERMIOS("start", &opt_vstart) +#if HAVE_RESOLV_H + IF_IP ("stayopen", &opt_res_stayopen) +#endif /* HAVE_RESOLV_H */ + IF_EXEC ("stderr", &opt_stderr) +#ifdef TCP_STDURG + IF_TCP ("stdurg", &opt_tcp_stdurg) +#endif + IF_TERMIOS("stop", &opt_vstop) + IF_ANY ("su", &opt_substuser) + IF_ANY ("su-d", &opt_substuser_delayed) + IF_ANY ("substuser", &opt_substuser) + IF_ANY ("substuser-delayed", &opt_substuser_delayed) + IF_TERMIOS("susp", &opt_vsusp) +#ifdef VSWTC + IF_TERMIOS("swtc", &opt_vswtc) + IF_TERMIOS("swtch", &opt_vswtc) +#endif + IF_PTY ("symbolic-link", &opt_symbolic_link) +#ifdef O_SYNC + IF_OPEN ("sync", &opt_o_sync) +#elif EXT2_SYNC_FL + IF_ANY ("sync", &opt_ext2_sync) +#endif +#ifdef TCP_SYNCNT + IF_TCP ("syncnt", &opt_tcp_syncnt) +#endif +#ifdef TABDLY +# ifdef TAB0 + IF_TERMIOS("tab0", &opt_tab0) +# endif +# ifdef TAB1 + IF_TERMIOS("tab1", &opt_tab1) +# endif +# ifdef TAB2 + IF_TERMIOS("tab2", &opt_tab2) +# endif +# ifdef TAB3 + IF_TERMIOS("tab3", &opt_tab3) +# endif + IF_TERMIOS("tabdly", &opt_tabdly) +#endif + IF_TERMIOS("tandem", &opt_ixoff) +#ifdef TCP_ABORT_THRESHOLD /* HP_UX */ + IF_TCP ("tcp-abort-threshold", &opt_tcp_abort_threshold) +#endif +#ifdef TCP_CONN_ABORT_THRESHOLD /* HP_UX */ + IF_TCP ("tcp-conn-abort-threshold", &opt_tcp_conn_abort_threshold) +#endif +#ifdef TCP_CORK + IF_TCP ("tcp-cork", &opt_tcp_cork) +#endif +#ifdef TCP_DEFER_ACCEPT /* Linux 2.4.0 */ + IF_TCP ("tcp-defer-accept", &opt_tcp_defer_accept) +#endif +#ifdef TCP_INFO /* Linux 2.4.0 */ + IF_TCP ("tcp-info", &opt_tcp_info) +#endif +#ifdef TCP_KEEPCNT /* Linux 2.4.0 */ + IF_TCP ("tcp-keepcnt", &opt_tcp_keepcnt) +#endif +#ifdef TCP_KEEPIDLE /* Linux 2.4.0 */ + IF_TCP ("tcp-keepidle", &opt_tcp_keepidle) +#endif +#ifdef TCP_KEEPINIT /* OSF1 */ + IF_TCP ("tcp-keepinit", &opt_tcp_keepinit) +#endif +#ifdef TCP_KEEPINTVL /* Linux 2.4.0 */ + IF_TCP ("tcp-keepintvl", &opt_tcp_keepintvl) +#endif +#ifdef TCP_LINGER2 /* Linux 2.4.0 */ + IF_TCP ("tcp-linger2", &opt_tcp_linger2) +#endif +#ifdef TCP_MAXSEG + IF_TCP ("tcp-maxseg", &opt_tcp_maxseg) + IF_TCP ("tcp-maxseg-late", &opt_tcp_maxseg_late) +#endif +#ifdef TCP_MD5SIG + IF_TCP ("tcp-md5sig", &opt_tcp_md5sig) +#endif +#ifdef TCP_NODELAY + IF_TCP ("tcp-nodelay", &opt_tcp_nodelay) +#endif +#ifdef TCP_NOOPT + IF_TCP ("tcp-noopt", &opt_tcp_noopt) +#endif +#ifdef TCP_NOPUSH + IF_TCP ("tcp-nopush", &opt_tcp_nopush) +#endif +#ifdef TCP_PAWS /* OSF1 */ + IF_TCP ("tcp-paws", &opt_tcp_paws) +#endif +#ifdef TCP_QUICKACK + IF_TCP ("tcp-quickack", &opt_tcp_quickack) +#endif +#ifdef TCP_RFC1323 + IF_TCP ("tcp-rfc1323", &opt_tcp_rfc1323) +#endif +#ifdef TCP_SACK_DISABLE + IF_TCP ("tcp-sack-disable", &opt_tcp_sack_disable) +#endif +#ifdef TCP_SACKENA /* OSF1 */ + IF_TCP ("tcp-sackena", &opt_tcp_sackena) +#endif +#ifdef TCP_SIGNATURE_ENABLE + IF_TCP ("tcp-signature-enable", &opt_tcp_signature_enable) +#endif +#ifdef TCP_STDURG + IF_TCP ("tcp-stdurg", &opt_tcp_stdurg) +#endif +#ifdef TCP_SYNCNT /* Linux 2.4.0 */ + IF_TCP ("tcp-syncnt", &opt_tcp_syncnt) +#endif +#ifdef TCP_TSOPTENA /* OSF1 */ + IF_TCP ("tcp-tsoptena", &opt_tcp_tsoptena) +#endif +#ifdef TCP_WINDOW_CLAMP /* Linux 2.4.0 */ + IF_TCP ("tcp-window-clamp", &opt_tcp_window_clamp) +#endif +#if WITH_LIBWRAP + IF_IPAPP ("tcpwrap", &opt_tcpwrappers) + IF_IPAPP ("tcpwrap-dir", &opt_tcpwrap_etc) + IF_IPAPP ("tcpwrap-etc", &opt_tcpwrap_etc) +#if WITH_LIBWRAP && defined(HAVE_HOSTS_ALLOW_TABLE) + IF_IPAPP ("tcpwrap-hosts-allow-table", &opt_tcpwrap_hosts_allow_table) +#endif +#if WITH_LIBWRAP && defined(HAVE_HOSTS_DENY_TABLE) + IF_IPAPP ("tcpwrap-hosts-deny-table", &opt_tcpwrap_hosts_deny_table) +#endif + IF_IPAPP ("tcpwrapper", &opt_tcpwrappers) + IF_IPAPP ("tcpwrappers", &opt_tcpwrappers) +#endif +#ifdef O_TEXT + IF_ANY ("text", &opt_o_text) +#endif + IF_UNIX ("tightsocklen", &opt_unix_tightsocklen) + IF_TERMIOS("time", &opt_vtime) + IF_TERMIOS("tiocsctty", &opt_tiocsctty) +#if WITH_EXT2 && defined(EXT2_TOPDIR_FL) + IF_ANY ("topdir", &opt_ext2_topdir) +#endif + IF_IP ("tos", &opt_ip_tos) + IF_TERMIOS("tostop", &opt_tostop) + IF_OPEN ("trunc", &opt_o_trunc) +#if HAVE_FTRUNCATE64 + IF_ANY ("truncate", &opt_ftruncate64) +#else + IF_ANY ("truncate", &opt_ftruncate32) +#endif +#ifdef TCP_TSOPTENA /* OSF1 */ + IF_TCP ("tsoptena", &opt_tcp_tsoptena) +#endif + IF_IP ("ttl", &opt_ip_ttl) + IF_TUN ("tun-device", &opt_tun_device) + IF_TUN ("tun-name", &opt_tun_name) + IF_TUN ("tun-no-pi", &opt_iff_no_pi) + IF_TUN ("tun-type", &opt_tun_type) + IF_SOCKET ("type", &opt_so_type) + IF_ANY ("uid", &opt_user) + IF_NAMED ("uid-e", &opt_user_early) + IF_ANY ("uid-l", &opt_user_late) + IF_NAMED ("umask", &opt_umask) + IF_UNIX ("unix-tightsocklen", &opt_unix_tightsocklen) + IF_NAMED ("unlink", &opt_unlink) + IF_NAMED ("unlink-close", &opt_unlink_close) + IF_NAMED ("unlink-early", &opt_unlink_early) + IF_NAMED ("unlink-late", &opt_unlink_late) +#if WITH_EXT2 && defined(EXT2_UNRM_FL) + IF_ANY ("unrm", &opt_ext2_unrm) +#endif + IF_TUN ("up", &opt_iff_up) +#ifdef SO_USE_IFBUFS + IF_SOCKET ("use-ifbufs", &opt_so_use_ifbufs) + IF_SOCKET ("useifbufs", &opt_so_use_ifbufs) +#endif /* SO_USE_IFBUFS */ +#ifdef SO_USELOOPBACK /* AIX433, Solaris */ + IF_SOCKET ("useloopback", &opt_so_useloopback) +#endif /* SO_USELOOPBACK */ + IF_ANY ("user", &opt_user) + IF_NAMED ("user-early", &opt_user_early) + IF_ANY ("user-late", &opt_user_late) +#if HAVE_RESOLV_H + IF_IP ("usevc", &opt_res_usevc) +#endif /* HAVE_RESOLV_H */ +#ifdef IPV6_V6ONLY + IF_IP6 ("v6only", &opt_ipv6_v6only) +#endif +#ifdef VDISCARD + IF_TERMIOS("vdiscard", &opt_vdiscard) +#endif +#ifdef VDSUSP /* HP-UX */ + IF_TERMIOS("vdsusp", &opt_vdsusp) +#endif + IF_TERMIOS("veof", &opt_veof) + IF_TERMIOS("veol", &opt_veol) + IF_TERMIOS("veol2", &opt_veol2) + IF_TERMIOS("verase", &opt_verase) + IF_OPENSSL("verify", &opt_openssl_verify) + IF_TERMIOS("vintr", &opt_vintr) + IF_TERMIOS("vkill", &opt_vkill) + IF_TERMIOS("vlnext", &opt_vlnext) + IF_TERMIOS("vmin", &opt_vmin) + IF_TERMIOS("vquit", &opt_vquit) +#ifdef VREPRINT + IF_TERMIOS("vreprint", &opt_vreprint) +#endif + IF_TERMIOS("vstart", &opt_vstart) + IF_TERMIOS("vstop", &opt_vstop) + IF_TERMIOS("vsusp", &opt_vsusp) +#ifdef VSWTC + IF_TERMIOS("vswtc", &opt_vswtc) +#endif +#ifdef VTDLY +# ifdef VT0 + IF_TERMIOS("vt0", &opt_vt0) +# endif +# ifdef VT1 + IF_TERMIOS("vt1", &opt_vt1) +# endif + IF_TERMIOS("vtdly", &opt_vtdly) +#endif + IF_TERMIOS("vtime", &opt_vtime) +#ifdef VWERASE + IF_TERMIOS("vwerase", &opt_vwerase) +#endif +#if HAVE_PTY && HAVE_POLL + IF_PTY ("wait-slave", &opt_pty_wait_slave) + IF_ANY ("waitlock", &opt_waitlock) + IF_PTY ("waitslave", &opt_pty_wait_slave) +#endif /* HAVE_PTY && HAVE_POLL */ +#ifdef VWERASE + IF_TERMIOS("werase", &opt_vwerase) +#endif +#ifdef TCP_WINDOW_CLAMP /* Linux 2.4.0 */ + IF_TCP ("window-clamp", &opt_tcp_window_clamp) +#endif +#if WITH_LIBWRAP + IF_IPAPP ("wrap", &opt_tcpwrappers) +#endif + IF_OPEN ("wronly", &opt_o_wronly) +#ifdef XCASE + IF_TERMIOS("xcase", &opt_xcase) +#endif +#if defined(TABDLY) && defined(XTABS) + IF_TERMIOS("xtabs", &opt_xtabs) +#endif + { NULL } +} ; + + +/* walks the text argument a and writes its options that conform to groups + to the array opts. Uses the option table 'optionnames'. + returns 0 on success, -1 on error, 1 on unknown/wrong option +*/ +int parseopts(const char **a, unsigned int groups, struct opt **opts) { + + return parseopts_table(a, groups, opts, optionnames, + sizeof(optionnames)/sizeof(struct optname)-1); +} + + +/* walks the text argument a and writes its options that conform to groups + to the array opts. Uses the specified option table. + returns 0 on success, -1 on error, 1 on unknown/wrong option +*/ +int parseopts_table(const char **a, unsigned int groups, struct opt **opts, + const struct optname optionnames[], size_t optionnum) { + int i=0; + struct opt *opt; + bool assign; + const char *a0 = *a; + unsigned long ulongval; + long slongval; + long long slonglongval; + char token[512], *tokp; size_t len; + int parsres; + int result; + char optbuf[256]; size_t optlen; + const char *endkey[6+1]; + const char *endval[5+1]; + const char *assign_str = "="; + const char *hquotes[] = { + "'", + NULL + } ; + const char *squotes[] = { + "\"", + NULL + } ; + const char *nests[] = { + "(", ")", + "[", "]", + "{", "}", + NULL + } ; + + i = 0; + /*endkey[i++] = xioopts.chainsep;*/ /* default: "|" */ + endkey[i++] = xioopts.pipesep; /* default: "!!" */ + endkey[i++] = ","/*xioopts.comma*/; /* default: "," */ + endkey[i++] = "="; + endkey[i++] = NULL; + + i = 0; + /*endval[i++] = xioopts.chainsep;*/ /* default: "|" */ + endval[i++] = xioopts.pipesep; /* default: "!!" */ + endval[i++] = ","/*xioopts.comma*/; /* default: "," */ + endval[i++] = NULL; + + i = 0; + *opts = Malloc((i+8)*sizeof(struct opt)); + if (*opts == NULL) { + return -1; + } + if (*a == NULL) { + (*opts)[i].desc = ODESC_END; + return 0; + } + + while (true) { + const struct optname *ent; + + if (a == NULL || *a == NULL || **a == '\0') + break; + + while (!strncmp(*a, ",", strlen(","))) { (*a) += strlen(","); } + a0 = *a; + + len = sizeof(token); tokp = token; + parsres = + nestlex(a, &tokp, &len, endkey, hquotes, squotes, nests, + true, true, false); + if (parsres != 0) { + return -1; + } + if (tokp == token) { + /* no option found */ + break; + } + *tokp = '\0'; + + ent = (struct optname *) + keyw((struct wordent *)optionnames, token, optionnum); + if (ent == NULL) { + Error1("parseopts(): unknown option \"%s\"", token); + continue; + } + + if (!(ent->desc->group & groups) && !(ent->desc->group & GROUP_ANY) && + !xioopts_ignoregroups) { + Error1("parseopts(): option \"%s\" not supported with this address type", + token /*a0*/); + Info2("parseopts() groups=%08x, ent->group=%08x", + groups, ent->desc->group); +#if 0 + continue; +#endif + } + (*opts)[i].desc = ent->desc; + + if (!strncmp(*a, assign_str, strlen(assign_str))) { + /* there is an assignment (mostly "=") */ + (*a) += strlen(assign_str); + len = sizeof(token); tokp = token; + parsres = + nestlex(a, &tokp, &len, endval, hquotes, squotes, nests, + true, true, false); + if (parsres != 0) { + return -1; + } + *tokp = '\0'; + assign = true; + + } else { + assign = false; + } + opt = &(*opts)[i]; + + switch (ent->desc->type) { + case TYPE_CONST: + if (assign) { + Error1("no value permitted for option \"%s\"", + ent->desc->defname); + continue; + } + Info1("setting option \"%s\"", ent->desc->defname); + break; + case TYPE_BIN: + if (!assign) { Error1("option \"%s\": value required", a0); + continue; } + optlen = 0; + if ((result = dalan(token, optbuf, &optlen, sizeof(optbuf))) != 0) { + Error1("parseopts(): problem with \"%s\" data", token); + continue; + } + if (((*opts)[i].value.u_bin.b_data = memdup(optbuf, optlen)) == NULL) { + Error1("memdup(, "F_Zu"): out of memory", optlen); + return -1; + } + (*opts)[i].value.u_bin.b_len = optlen; + break; + case TYPE_BYTE: + { + unsigned long ul; + if (token) { + char *rest; + ul = strtoul(token, &rest/*!*/, 0); + } else { + ul = 1; + } + if (ul > UCHAR_MAX) { + Error3("parseopts(%s): byte value exceeds limit (%lu vs. %u), using max", + a0, ul, UCHAR_MAX); + (*opts)[i].value.u_byte = UCHAR_MAX; + } else { + Info2("setting option \"%s\" to %d", ent->desc->defname, + (*opts)[i].value.u_byte); + (*opts)[i].value.u_byte = ul; + } + } + break; + case TYPE_INT: + if (assign) { + char *rest; + (*opts)[i].value.u_int = strtoul(token, &rest/*!*/, 0); + } else { + (*opts)[i].value.u_int = 1; + } + Info2("setting option \"%s\" to %d", ent->desc->defname, + (*opts)[i].value.u_int); + break; + case TYPE_BOOL: + if (!assign) { + (*opts)[i].value.u_bool = 1; + } else { + char *rest; + (*opts)[i].value.u_bool = strtoul(token, &rest, 0); + if (rest && *rest) { + Error1("error in option \"%s\": \"0\" or \"1\" required", a0); + } + } + Info2("setting option \"%s\" to %d", ent->desc->defname, + (*opts)[i].value.u_bool); + break; + +#if HAVE_BASIC_SIZE_T==4 + case TYPE_SIZE_T: +#endif + case TYPE_UINT: + if (!assign) { + (*opts)[i].value.u_uint = 1; + } else { + char *rest; + ulongval = strtoul(token, &rest/*!*/, 0); + if (ulongval > UINT_MAX) { + Error3("parseopts(%s): unsigned int value exceeds limit (%lu vs. %u), using max", + a0, ulongval, UINT_MAX); + } + (*opts)[i].value.u_uint = ulongval; + } + Info2("setting option \"%s\" to %u", ent->desc->defname, + (*opts)[i].value.u_uint); + break; + +#if HAVE_BASIC_SIZE_T==2 + case TYPE_SIZE_T: +#endif + case TYPE_USHORT: + if (!assign) { + (*opts)[i].value.u_ushort = 1; + } else { + char *rest; + ulongval = strtoul(token, &rest/*!*/, 0); + if (ulongval > USHRT_MAX) { + Error3("parseopts(%s): unsigned short value exceeds limit (%lu vs. %u), using max", + a0, ulongval, USHRT_MAX); + } + (*opts)[i].value.u_ushort = ulongval; + } + Info2("setting option \"%s\" to %u", ent->desc->defname, + (*opts)[i].value.u_ushort); + break; + + case TYPE_OFF32: +#if HAVE_STAT64 && defined(HAVE_BASIC_OFF64_T) && HAVE_BASIC_OFF64_T==5 + case TYPE_OFF64: +#endif + case TYPE_LONG: + if (!assign) { + (*opts)[i].value.u_long = 1; + } else { + char *rest; + slongval = strtol(token, &rest, 0); + (*opts)[i].value.u_long = slongval; + } + Info2("setting option \"%s\" to %lu", ent->desc->defname, + (*opts)[i].value.u_long); + break; + +#if HAVE_BASIC_SIZE_T==6 + case TYPE_SIZE_T: +#endif + case TYPE_ULONG: + if (!assign) { + (*opts)[i].value.u_ulong = 1; + } else { + char *rest; + ulongval = strtoul(token, &rest, 0); + (*opts)[i].value.u_ulong = ulongval; + } + Info2("setting option \"%s\" to %lu", ent->desc->defname, + (*opts)[i].value.u_ulong); + break; + +#if HAVE_TYPE_LONGLONG + case TYPE_LONGLONG: +# if HAVE_STAT64 && defined(HAVE_BASIC_OFF64_T) && HAVE_BASIC_OFF64_T==7 + case TYPE_OFF64: +# endif + if (!assign) { + (*opts)[i].value.u_longlong = 1; + } else { + char *rest; +# if HAVE_STRTOLL + slonglongval = strtoll(token, &rest, 0); +# else + /* in this case, input value range is limited */ + slonglongval = strtol(token, &rest, 0); +# endif /* HAVE_STRTOLL */ + (*opts)[i].value.u_longlong = slonglongval; + } + Info2("setting option \"%s\" to %Lu", ent->desc->defname, + (*opts)[i].value.u_longlong); + break; +#endif /* HAVE_TYPE_LONGLONG */ + case TYPE_UIDT: + if (!assign) { + Error1("option \"%s\": value required", a0); + continue; + } + if (isdigit((*token)&0xff)) { + char *rest; + (*opts)[i].value.u_uidt = strtoul(token, &rest/*!*/, 0); + } else { + struct passwd *pwd; + if ((pwd = getpwnam(token)) == NULL) { + Error1("getpwnam(\"%s\"): no such user", token); + continue; + } + (*opts)[i].value.u_uidt = getpwnam(token)->pw_uid; + } + Info2("setting option \"%s\" to %u", ent->desc->defname, + (*opts)[i].value.u_uidt); + break; + case TYPE_GIDT: + if (!assign) { Error1("option \"%s\": value required", a0); + continue; } + if (isdigit((token[0])&0xff)) { + char *rest; + (*opts)[i].value.u_gidt = strtoul(token, &rest/*!*/, 0); + } else { + struct group *grp; + grp = getgrnam(token); + if (grp == NULL) { + Error1("getgrnam(\"%s\"): no such group", token); + continue; + } + (*opts)[i].value.u_gidt = grp->gr_gid; + } + Info2("setting option \"%s\" to %u", ent->desc->defname, + (*opts)[i].value.u_gidt); + break; + case TYPE_MODET: + if (!assign) { Error1("option \"%s\": value required", a0); + continue; + } + { + char *rest; + (*opts)[i].value.u_modet = strtoul(token, &rest/*!*/, 8); + } + Info2("setting option \"%s\" to %u", ent->desc->defname, + (*opts)[i].value.u_modet); + break; + case TYPE_STRING: + if (!assign) { + Error1("option \"%s\": value required", a0); + continue; + } + if (((*opts)[i].value.u_string = strdup(token)) == NULL) { + Error("out of memory"); return -1; + } + Info2("setting option \"%s\" to \"%s\"", ent->desc->defname, + (*opts)[i].value.u_string); + break; + case TYPE_STRING_NULL: + if (!assign) { + (*opts)[i].value.u_string = NULL; + Info1("setting option \"%s\" to NULL", ent->desc->defname); + } else { + (*opts)[i].value.u_string = strdup(token); + Info2("setting option \"%s\" to \"%s\"", ent->desc->defname, + (*opts)[i].value.u_string); + } + break; +#if LATER + case TYPE_INT3: + + break; +#endif + case TYPE_TIMEVAL: + if (!assign) { + Error1("option \"%s\": value required", a0); + continue; + } else { + double val; + val = strtod(token, NULL); + if (val == HUGE_VAL || val == -HUGE_VAL || + val == 0.0 && errno == ERANGE) { + Error2("strtod(\"%s\", NULL): %s", token, strerror(errno)); + val = 0.0; + } + (*opts)[i].value.u_timeval.tv_sec = val; + (*opts)[i].value.u_timeval.tv_usec = + (val-(*opts)[i].value.u_timeval.tv_sec) * 1000000; + } + break; +#if HAVE_STRUCT_TIMESPEC + case TYPE_TIMESPEC: + if (!assign) { + Error1("option \"%s\": value required", a0); + continue; + } else { + double val; + val = strtod(token, NULL); + if (val == HUGE_VAL || val == -HUGE_VAL || + val == 0.0 && errno == ERANGE) { + Error2("strtod(\"%s\", NULL): %s", token, strerror(errno)); + val = 0.0; + } + (*opts)[i].value.u_timespec.tv_sec = val; + (*opts)[i].value.u_timespec.tv_nsec = + (val-(*opts)[i].value.u_timespec.tv_sec) * 1000000000.; + } + break; +#endif /* HAVE_STRUCT_TIMESPEC */ +#if HAVE_STRUCT_LINGER + case TYPE_LINGER: + if (!assign) { + Error1("option \"%s\": value required", a0); + continue; + } + (*opts)[i].value.u_linger.l_onoff = 1; + { + char *rest; + (*opts)[i].value.u_linger.l_linger = strtoul(token, &rest/*!*/, 0); + } + Info3("setting option \"%s\" to {%d,%d}", ent->desc->defname, + (*opts)[i].value.u_linger.l_onoff, + (*opts)[i].value.u_linger.l_linger); + break; +#endif /* HAVE_STRUCT_LINGER */ +#if defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) + case TYPE_IP_MREQN: + { + /* we do not resolve the addresses here because we do not yet know + if we are coping with a IPv4 or IPv6 socat address */ + const char *ends[] = { ":", NULL }; + const char *nests[] = { "[","]", NULL }; + char buff[512], *buffp=buff; size_t bufspc = sizeof(buff)-1; + + /* parse first IP address, expect ':' */ + tokp = token; + /*! result= */ + nestlex((const char **)&tokp, &buffp, &bufspc, + ends, NULL, NULL, nests, + true, false, false); + if (*tokp != ':') { + Error1("syntax in option %s: missing ':'", token); + } + *buffp++ = '\0'; + (*opts)[i].value.u_ip_mreq.multiaddr = strdup(buff); /*!!! NULL */ + + ++tokp; + /* parse second IP address, expect ':' or '\0'' */ + buffp = buff; + /*! result= */ + nestlex((const char **)&tokp, &buffp, &bufspc, + ends, NULL, NULL, nests, + true, false, false); + *buffp++ = '\0'; + (*opts)[i].value.u_ip_mreq.param2 = strdup(buff); /*!!! NULL */ + +#if HAVE_STRUCT_IP_MREQN + if (*tokp++ == ':') { + strncpy((*opts)[i].value.u_ip_mreq.ifindex, tokp, IF_NAMESIZE); + Info4("setting option \"%s\" to {\"%s\",\"%s\",\"%s\"}", + ent->desc->defname, + (*opts)[i].value.u_ip_mreq.multiaddr, + (*opts)[i].value.u_ip_mreq.param2, + (*opts)[i].value.u_ip_mreq.ifindex); + } else { + (*opts)[i].value.u_ip_mreq.ifindex[0] = '\0'; + Info3("setting option \"%s\" to {\"%s\",\"%s\"}", + ent->desc->defname, + (*opts)[i].value.u_ip_mreq.multiaddr, + (*opts)[i].value.u_ip_mreq.param2); + } +#else /* !HAVE_STRUCT_IP_MREQN */ + Info3("setting option \"%s\" to {0x%08x,0x%08x}", + ent->desc->defname, + (*opts)[i].value.u_ip_mreq.multiaddr, + (*opts)[i].value.u_ip_mreq.param2); +#endif /* !HAVE_STRUCT_IP_MREQN */ + } + break; +#endif /* defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) */ + +#if WITH_IP4 + case TYPE_IP4NAME: + { + struct sockaddr_in sa; size_t salen = sizeof(sa); + const char *ends[] = { NULL }; + const char *nests[] = { "[","]", NULL }; + char buff[512], *buffp=buff; size_t bufspc = sizeof(buff)-1; + + tokp = token; + nestlex((const char **)&tokp, &buffp, &bufspc, + ends, NULL, NULL, nests, + true, false, false); + if (*tokp != '\0') { + Error1("trailing data in option \"%s\"", token); + } + *buffp = '\0'; + if (xiogetaddrinfo(buff, NULL, AF_INET, SOCK_DGRAM, IPPROTO_IP, + (union sockaddr_union *)&sa, &salen, + 0, 0/*!!!*/) != STAT_OK) { + opt->desc = ODESC_ERROR; continue; + } + opt->value.u_ip4addr = sa.sin_addr.s_addr; + } + break; +#endif /* defined(WITH_IP4) */ + + default: + Error2("parseopts(): internal error on option \"%s\": unimplemented type %d", + ent->desc->defname, ent->desc->type); + continue; + } + + ++i; + if ((i % 8) == 0) { + *opts = Realloc(*opts, (i+8) * sizeof(struct opt)); + if (*opts == NULL) { + return -1; + } + } + } + + /*(*opts)[i+1].desc = ODESC_END;*/ + (*opts)[i].desc = ODESC_END; + return 0; +} + +/* copy the already parsed options for repeated application, but only those + matching groups ANY and */ +struct opt *copyopts(const struct opt *opts, unsigned int groups) { + struct opt *new; + int i, j, n; + + if (!opts) return NULL; + + /* just count the options in the array */ + i = 0; while (opts[i].desc != ODESC_END) { + ++i; + } + n = i+1; + + new = Malloc(n * sizeof(struct opt)); + if (new == NULL) { + return NULL; + } + + i = 0, j = 0; + while (i < n-1) { + if (opts[i].desc == ODESC_DONE) { + new[j].desc = ODESC_DONE; + } else if ((opts[i].desc->group & (GROUP_ANY&~GROUP_PROCESS)) || + (opts[i].desc->group & groups)) { + new[j++] = opts[i]; + } + ++i; + } + new[j].desc = ODESC_END; + return new; +} + +/* move options to a new options list + move only those matching */ +struct opt *moveopts(struct opt *opts, unsigned int groups) { + struct opt *new; + int i, j, n; + + if (!opts) return NULL; + + /* just count the options in the array */ + i = 0; j = 0; while (opts[i].desc != ODESC_END) { + if (opts[i].desc != ODESC_DONE && + opts[i].desc != ODESC_ERROR) + ++j; + ++i; + } + n = i; + + new = Malloc((j+1) * sizeof(struct opt)); + if (new == NULL) { + return NULL; + } + + i = 0, j = 0; + while (i < n) { + if (opts[i].desc == ODESC_DONE || + opts[i].desc == ODESC_ERROR) { + ++i; continue; + } else if (opts[i].desc->group & groups) { + new[j++] = opts[i]; + opts[i].desc = ODESC_DONE; + } + ++i; + } + new[j].desc = ODESC_END; + return new; +} + +/* return the number of yet unconsumed options; -1 on error */ +int leftopts(const struct opt *opts) { + const struct opt *opt = opts; + int num = 0; + + if (!opts) return 0; + + while (opt->desc != ODESC_END) { + if (opt->desc != ODESC_DONE) { + ++num; + } + ++opt; + } + return num; +} + +/* show as warning which options are still unused */ +int showleft(const struct opt *opts) { + const struct opt *opt = opts; + + while (opt->desc != ODESC_END) { + if (opt->desc != ODESC_DONE) { + Warn1("showleft(): option \"%s\" not inquired", opt->desc->defname); + } + ++opt; + } + return 0; +} + + +/* determines the address group from mode_t */ +/* does not set GROUP_FD; cannot determine GROUP_TERMIOS ! */ +int _groupbits(mode_t mode) { + unsigned int result = 0; + + switch ((mode&S_IFMT)>>12) { + case (S_IFIFO>>12): /* 1, FIFO */ + result = GROUP_FIFO; break; + case (S_IFCHR>>12): /* 2, character device */ + result = GROUP_CHR|GROUP_TERMIOS; break; + case (S_IFDIR>>12): /* 4, directory !!! not supported */ + result = GROUP_NONE; break; + case (S_IFBLK>>12): /* 6, block device */ + result = GROUP_BLK; break; + case (S_IFREG>>12): /* 8, regular file */ + result = GROUP_REG; break; + case (S_IFLNK>>12): /* 10, symbolic link !!! not supported */ + result = GROUP_NONE; break; +#ifdef S_IFSOCK + case (S_IFSOCK>>12): /* 12, socket */ + result = GROUP_SOCKET|GROUP_SOCK_UNIX; break; +#else + default: /* some systems (pure POSIX.1) do not know S_IFSOCK */ + result = GROUP_SOCKET|GROUP_SOCK_UNIX; break; +#endif + } + Debug2("_groupbits(%d) -> %d", mode, result); + return result; +} + +/* does not set GROUP_FD */ +int groupbits(int fd) { +#if HAVE_STAT64 + struct stat64 buf; +#else + struct stat buf; +#endif /* !HAVE_STAT64 */ + int result; + + if ( +#if HAVE_STAT64 + Fstat64(fd, &buf) < 0 +#else + Fstat(fd, &buf) < 0 +#endif /* !HAVE_STAT64 */ + ) { + Error4("groupbits(%d): fstat(%d, %p): %s", + fd, fd, &buf, strerror(errno)); + return -1; + } + result = _groupbits(buf.st_mode&S_IFMT); + if (result == GROUP_CHR) { + if (Isatty(fd) > 0) { + result |= GROUP_TERMIOS; + } + } + return result; +} + +#if 0 /* currently not used */ +int retropt(struct opt *opts, int optcode, union integral *result) { + struct opt *opt = opts; + + while (opt->desc != ODESC_END) { + if (opt->desc != ODESC_DONE && opt->desc->optcode == optcode) { + *result = opt->value; + opt->desc = ODESC_DONE; + return 0; + } + ++opt; + } + return -1; +} +#endif + +static struct opt *xio_findopt(struct opt *opts, int optcode) { + struct opt *opt = opts; + + while (opt->desc != ODESC_END) { + if (opt->desc != ODESC_DONE && opt->desc->optcode == optcode) { + return opt; + } + ++opt; + } + return NULL; +} + +int retropt_timespec(struct opt *opts, int optcode, struct timespec *result) { + struct opt *opt; + + if (!(opt = xio_findopt(opts, optcode))) { + return -1; + } + *result = opt->value.u_timespec; + opt->desc = ODESC_DONE; + return 0; +} + + +/* Looks for the first option of type . If the option is found, + this function stores its bool value in *result, "consumes" the + option, and returns 0. + If the option is not found, *result is not modified, and -1 is returned. */ +int retropt_bool(struct opt *opts, int optcode, bool *result) { + struct opt *opt = opts; + + while (opt->desc != ODESC_END) { + if (opt->desc != ODESC_DONE && opt->desc->optcode == optcode) { + *result = opt->value.u_bool; + opt->desc = ODESC_DONE; + return 0; + } + ++opt; + } + return -1; +} + +#if 0 /* currently not used */ +/* Looks for the first option of type . If the option is found, + this function stores its short value in *result, "consumes" the + option, and returns 0. + If the option is not found, *result is not modified, and -1 is returned. */ +int retropt_short(struct opt *opts, int optcode, short *result) { + struct opt *opt = opts; + + while (opt->desc != ODESC_END) { + if (opt->desc != ODESC_DONE && opt->desc->optcode == optcode) { + *result = opt->value.u_short; + opt->desc = ODESC_DONE; + return 0; + } + ++opt; + } + return -1; +} +#endif + +/* Looks for the first option of type . If the option is found, + this function stores its unsigned short value in *result, "consumes" the + option, and returns 0. + If the option is not found, *result is not modified, and -1 is returned. */ +int retropt_ushort(struct opt *opts, int optcode, unsigned short *result) { + struct opt *opt = opts; + + while (opt->desc != ODESC_END) { + if (opt->desc != ODESC_DONE && opt->desc->optcode == optcode) { + *result = opt->value.u_ushort; + opt->desc = ODESC_DONE; + return 0; + } + ++opt; + } + return -1; +} + +/* Looks for the first option of type . 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. */ +int retropt_int(struct opt *opts, int optcode, int *result) { + struct opt *opt = opts; + + while (opt->desc != ODESC_END) { + if (opt->desc != ODESC_DONE && opt->desc->optcode == optcode) { + *result = opt->value.u_int; + opt->desc = ODESC_DONE; + return 0; + } + ++opt; + } + return -1; +} + +/* Looks for the first option of type . If the option is found, + this function stores its unsigned int value in *result, "consumes" the + option, and returns 0. + If the option is not found, *result is not modified, and -1 is returned. */ +int retropt_uint(struct opt *opts, int optcode, unsigned int *result) { + struct opt *opt = opts; + + while (opt->desc != ODESC_END) { + if (opt->desc != ODESC_DONE && opt->desc->optcode == optcode) { + *result = opt->value.u_uint; + opt->desc = ODESC_DONE; + return 0; + } + ++opt; + } + return -1; +} + +/* Looks for the first option of type . If the option is found, + this function stores its long value in *result, "consumes" the option, + and returns 0. + If the option is not found, *result is not modified, and -1 is returned. */ +int retropt_long(struct opt *opts, int optcode, long *result) { + struct opt *opt = opts; + + while (opt->desc != ODESC_END) { + if (opt->desc != ODESC_DONE && opt->desc->optcode == optcode) { + *result = opt->value.u_long; + opt->desc = ODESC_DONE; + return 0; + } + ++opt; + } + return -1; +} + +/* Looks for the first option of type . If the option is found, + this function stores its unsigned long value in *result, "consumes" the + option, and returns 0. + If the option is not found, *result is not modified, and -1 is returned. */ +int retropt_ulong(struct opt *opts, int optcode, unsigned long *result) { + struct opt *opt = opts; + + while (opt->desc != ODESC_END) { + if (opt->desc != ODESC_DONE && opt->desc->optcode == optcode) { + *result = opt->value.u_ulong; + opt->desc = ODESC_DONE; + return 0; + } + ++opt; + } + return -1; +} + +#if 0 /* currently not used */ +/* get the value of a FLAG typed option, and apply it to the appropriate + bit position. Mark the option as consumed (done). return 0 if options was found and successfully applied, + or -1 if option was not in opts */ +int retropt_flag(struct opt *opts, int optcode, flags_t *result) { + struct opt *opt = opts; + + while (opt->desc != ODESC_END) { + if (opt->desc != ODESC_DONE && opt->desc->optcode == optcode) { + if (opt->value.u_bool) { + *result |= opt->desc->major; + } else { + *result &= ~opt->desc->major; + } + opt->desc = ODESC_DONE; + return 0; + } + ++opt; + } + return -1; +} +#endif + +/* Looks for the first option of type . If the option is found, + this function stores its character pointer value in *result, "consumes" the + option, and returns 0. Note that, for options of type STRING_NULL, the + character pointer might degenerate to NULL. + The resulting string is malloc'ed and should be freed after use. + If the option is not found, *result is not modified, and -1 is returned. + */ +int retropt_string(struct opt *opts, int optcode, char **result) { + struct opt *opt = opts; + + while (opt->desc != ODESC_END) { + if (opt->desc != ODESC_DONE && opt->desc->optcode == optcode) { + if (opt->value.u_string == NULL) { + *result = NULL; + } else if ((*result = strdup(opt->value.u_string)) == NULL) { + Error1("strdup("F_Zu"): out of memory", + strlen(opt->value.u_string)); + return -1; + } + opt->desc = ODESC_DONE; + return 0; + } + ++opt; + } + return -1; +} + + +#if WITH_SOCKET +/* looks for an bind option and, if found, overwrites the complete contents of + sa with the appropriate value(s). + 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 */ +/* currently only for IP (v4, v6) */ +int retropt_bind(struct opt *opts, + int af, + int socktype, + int ipproto, + struct sockaddr *sa, + socklen_t *salen, + int feats, /* TCP etc: 1..address allowed, + 3..address and port allowed */ + unsigned long res_opts0, unsigned long res_opts1) { + const char portsep[] = ":"; + const char *ends[] = { portsep, NULL }; + const char *nests[] = { "[", "]", NULL }; + bool addrallowed, portallowed; + char *bindname, *bindp; + char hostname[512], *hostp = hostname, *portp = NULL; + size_t hostlen = sizeof(hostname)-1; + int result; + + if (retropt_string(opts, OPT_BIND, &bindname) < 0) { + return STAT_NOACTION; + } + addrallowed = true; + portallowed = (feats>=2); + bindp = bindname; + nestlex((const char **)&bindp, &hostp, &hostlen, ends, NULL, NULL, nests, + true, false, false); + *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); + } + } + + switch (af) { +#if WITH_IP4 || WITH_IP6 +#if WITH_IP4 + case AF_INET: +#endif +#if WITH_IP6 + case AF_INET6: +#endif /*WITH_IP6 */ + if ((result = + xiogetaddrinfo(hostname[0]!='\0'?hostname:NULL, portp, + af, socktype, ipproto, + (union sockaddr_union *)sa, salen, + res_opts0, res_opts1)) + != STAT_OK) { + Error("error resolving bind option"); + return STAT_NORETRY; + } + break; +#endif /* WITH_IP4 || WITH_IP6 */ + +#if WITH_UNIX + case AF_UNIX: + { + bool tight = false; + struct sockaddr_un *s_un = (struct sockaddr_un *)sa; + *salen = xiosetunix(s_un, bindname, false, tight); + } + break; +#endif /* WITH_UNIX */ + + default: + Error1("bind: unknown address family %d", af); + return STAT_NORETRY; + } + return STAT_OK; +} +#endif /* WITH_SOCKET */ + + +/* applies to fd all options belonging to phase */ +/* 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), + OFUNC_TERMIOS_FLAG, OFUNC_TERMIOS_PATTERN, and some OFUNC_SPEC */ +int applyopts(int fd, struct opt *opts, unsigned int phase) { + struct opt *opt; + + opt = opts; while (opt && opt->desc != ODESC_END) { + if (opt->desc == ODESC_DONE || + (phase != PH_ALL && opt->desc->phase != phase)) { + ++opt; continue; } + + if (opt->desc->func == OFUNC_SEEK32) { + if (Lseek(fd, opt->value.u_long, opt->desc->major) < 0) { + Error4("lseek(%d, %ld, %d): %s", + fd, opt->value.u_long, opt->desc->major, strerror(errno)); + } +#if HAVE_LSEEK64 + } else if (opt->desc->func == OFUNC_SEEK64) { + + /*! this depends on off64_t atomic type */ + if (Lseek64(fd, opt->value.u_off64, opt->desc->major) < 0) { + Error4("lseek64(%d, %Ld, %d): %s", + fd, opt->value.u_off64, opt->desc->major, strerror(errno)); + } +#endif /* HAVE_LSEEK64 */ + + } else if (opt->desc->func == OFUNC_FCNTL) { + int flag; + + /* retrieve existing flag setttings */ + if ((flag = Fcntl(fd, opt->desc->major-1)) < 0) { + Error3("fcntl(%d, %d): %s", + fd, opt->desc->major, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } else { + if (opt->value.u_bool) { + flag |= opt->desc->minor; + } else { + flag &= ~opt->desc->minor; + } + if (Fcntl_l(fd, opt->desc->major, flag) < 0) { + Error4("fcntl(%d, %d, %d): %s", + fd, opt->desc->major, flag, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + } + + } else if (opt->desc->func == OFUNC_IOCTL) { + if (Ioctl(fd, opt->desc->major, (void *)&opt->value) < 0) { + Error4("ioctl(%d, 0x%x, %p): %s", + fd, opt->desc->major, (void *)&opt->value, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + + } else if (opt->desc->func == OFUNC_IOCTL_MASK_LONG) { + long val; + int getreq = opt->desc->major; + int setreq = opt->desc->minor; + long mask = opt->desc->arg3; + + if (Ioctl(fd, getreq, (void *)&val) < 0) { + Error4("ioctl(%d, 0x%x, %p): %s", + fd, opt->desc->major, (void *)&val, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + val &= ~mask; + if (opt->value.u_bool) val |= mask; + if (Ioctl(fd, setreq, (void *)&val) < 0) { + Error4("ioctl(%d, 0x%x, %p): %s", + fd, opt->desc->major, (void *)&val, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + +#if WITH_SOCKET + } else if (opt->desc->func == OFUNC_SOCKOPT) { + if (0) { + ; +#if 0 && HAVE_STRUCT_LINGER + } else if (opt->desc->optcode == OPT_SO_LINGER) { + struct linger lingstru; + lingstru.l_onoff = (opt->value.u_int>=0 ? 1 : 0); + lingstru.l_linger = opt->value.u_int; + if (Setsockopt(fd, opt->desc->major, opt->desc->minor, &lingstru, + sizeof(lingstru)) < 0) { + Error6("setsockopt(%d, %d, %d, {%d,%d}, "F_Zu, + fd, opt->desc->major, opt->desc->minor, lingstru.l_onoff, + lingstru.l_linger, sizeof(lingstru)); + opt->desc = ODESC_ERROR; ++opt; continue; + } +#endif /* HAVE_STRUCT_LINGER */ + } else { + switch (opt->desc->type) { + case TYPE_BIN: + if (Setsockopt(fd, opt->desc->major, opt->desc->minor, + opt->value.u_bin.b_data, opt->value.u_bin.b_len) + < 0) { + Error6("setsockopt(%d, %d, %d, %p, %d): %s", + fd, opt->desc->major, opt->desc->minor, + opt->value.u_bin.b_data, opt->value.u_bin.b_len, + strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + break; + case TYPE_BOOL: + if (Setsockopt(fd, opt->desc->major, opt->desc->minor, + &opt->value.u_bool, sizeof(opt->value.u_bool)) + < 0) { + Error6("setsockopt(%d, %d, %d, {%d}, "F_Zu"): %s", fd, + opt->desc->major, opt->desc->minor, + opt->value.u_bool, sizeof(opt->value.u_bool), + strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + break; + case TYPE_BYTE: + if (Setsockopt(fd, opt->desc->major, opt->desc->minor, + &opt->value.u_byte, sizeof(uint8_t)) < 0) { + Error6("setsockopt(%d, %d, %d, {%u}, "F_Zu"): %s", + fd, opt->desc->major, opt->desc->minor, + opt->value.u_byte, sizeof(uint8_t), strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + break; + case TYPE_INT: + if (Setsockopt(fd, opt->desc->major, opt->desc->minor, + &opt->value.u_int, sizeof(int)) < 0) { + Error6("setsockopt(%d, %d, %d, {%d}, "F_Zu"): %s", + fd, opt->desc->major, opt->desc->minor, + opt->value.u_int, sizeof(int), strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + break; + case TYPE_LONG: + if (Setsockopt(fd, opt->desc->major, opt->desc->minor, + &opt->value.u_long, sizeof(long)) < 0) { + Error6("setsockopt(%d, %d, %d, {%ld}, "F_Zu"): %s", + fd, opt->desc->major, opt->desc->minor, + opt->value.u_long, sizeof(long), strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + break; + case TYPE_STRING: + if (Setsockopt(fd, opt->desc->major, opt->desc->minor, + opt->value.u_string, + strlen(opt->value.u_string)+1) < 0) { + Error6("setsockopt(%d, %d, %d, \"%s\", "F_Zu"): %s", + fd, opt->desc->major, opt->desc->minor, + opt->value.u_string, strlen(opt->value.u_string)+1, + strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + break; + case TYPE_UINT: + if (Setsockopt(fd, opt->desc->major, opt->desc->minor, + &opt->value.u_uint, sizeof(unsigned int)) < 0) { + Error6("setsockopt(%d, %d, %d, {%u}, "F_Zu"): %s", + fd, opt->desc->major, opt->desc->minor, + opt->value.u_uint, sizeof(unsigned int), + strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + break; + case TYPE_TIMEVAL: + if (Setsockopt(fd, opt->desc->major, opt->desc->minor, + &opt->value.u_timeval, sizeof(struct timeval)) < 0) { + Error7("setsockopt(%d, %d, %d, {%ld,%ld}, "F_Zu"): %s", + fd, opt->desc->major, opt->desc->minor, + opt->value.u_timeval.tv_sec, opt->value.u_timeval.tv_usec, + sizeof(struct timeval), strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + break; +#if HAVE_STRUCT_LINGER + case TYPE_LINGER: + { + struct linger lingstru; + lingstru.l_onoff = (opt->value.u_linger.l_onoff>=0 ? 1 : 0); + lingstru.l_linger = opt->value.u_linger.l_linger; + if (Setsockopt(fd, opt->desc->major, opt->desc->minor, + &lingstru, sizeof(lingstru)) < 0) { + Error6("setsockopt(%d, %d, %d, {%d,%d}): %s", + fd, opt->desc->major, opt->desc->minor, + lingstru.l_onoff, lingstru.l_linger, + strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + } + break; +#endif /* HAVE_STRUCT_LINGER */ +#if defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) + case TYPE_IP_MREQN: + /* handled in applyopts_single */ + ++opt; continue; +#endif /* defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) */ + + /*! still many types missing; implement on demand */ +#if WITH_IP4 + case TYPE_IP4NAME: + if (Setsockopt(fd, opt->desc->major, opt->desc->minor, + &opt->value.u_ip4addr, sizeof(opt->value.u_ip4addr)) < 0) { + Error6("setsockopt(%d, %d, %d, {0x%x}, "F_Zu"): %s", + fd, opt->desc->major, opt->desc->minor, + opt->value.u_ip4addr, sizeof(opt->value.u_ip4addr), + strerror(errno)); + } + break; +#endif /* defined(WITH_IP4) */ + default: +#if !NDEBUG + Error1("applyopts(): type %d not implemented", + opt->desc->type); +#else + Warn1("applyopts(): type %d not implemented", + opt->desc->type); +#endif + opt->desc = ODESC_ERROR; ++opt; continue; + } + } + + } else if (opt->desc->func == OFUNC_SOCKOPT_APPEND) { + switch (opt->desc->type) { + uint8_t data[256]; + socklen_t oldlen, newlen; + case TYPE_BIN: + oldlen = sizeof(data); + if (Getsockopt(fd, opt->desc->major, opt->desc->minor, + data, &oldlen) + < 0) { + Error6("getsockopt(%d, %d, %d, %p, {"F_Zu"}): %s", + fd, opt->desc->major, opt->desc->minor, data, oldlen, + strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + memcpy(&data[oldlen], opt->value.u_bin.b_data, + MIN(opt->value.u_bin.b_len, sizeof(data)-oldlen)); + newlen = oldlen + MIN(opt->value.u_bin.b_len, sizeof(data)-oldlen); + if (Setsockopt(fd, opt->desc->major, opt->desc->minor, + data, newlen) + < 0) { + Error6("setsockopt(%d, %d, %d, %p, %d): %s", + fd, opt->desc->major, opt->desc->minor, data, newlen, + strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + break; + default: + Error2("internal: option \"%s\": unimplemented type %d", + opt->desc->defname, opt->desc->type); + break; + } +#endif /* WITH_SOCKET */ + +#if HAVE_FLOCK + } else if (opt->desc->func == OFUNC_FLOCK) { + if (Flock(fd, opt->desc->major) < 0) { + Error3("flock(%d, %d): %s", + fd, opt->desc->major, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } +#endif /* defined(HAVE_FLOCK) */ + + } else if (opt->desc->func == OFUNC_SPEC || + opt->desc->func == OFUNC_FLAG) { + switch (opt->desc->optcode) { + case OPT_USER: + case OPT_USER_LATE: + if (Fchown(fd, opt->value.u_uidt, -1) < 0) { + Error3("fchown(%d, "F_uid", -1): %s", + fd, opt->value.u_uidt, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + break; + case OPT_GROUP: + case OPT_GROUP_LATE: + if (Fchown(fd, -1, opt->value.u_gidt) < 0) { + Error3("fchown(%d, -1, "F_gid"): %s", + fd, opt->value.u_gidt, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + break; + case OPT_PERM: + case OPT_PERM_LATE: + if (Fchmod(fd, opt->value.u_modet) < 0) { + Error3("fchmod(%d, %u): %s", + fd, opt->value.u_modet, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + break; + case OPT_FTRUNCATE32: + if (Ftruncate(fd, opt->value.u_long) < 0) { + Error3("ftruncate(%d, %ld): %s", + fd, opt->value.u_long, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + break; +#if HAVE_FTRUNCATE64 + case OPT_FTRUNCATE64: + if (Ftruncate64(fd, opt->value.u_long) < 0) { + Error3("ftruncate64(%d, %ld): %s", + fd, opt->value.u_long, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } +#endif /* HAVE_FTRUNCATE64 */ + break; + case OPT_F_SETLK_RD: + case OPT_F_SETLK_WR: + case OPT_F_SETLKW_RD: + case OPT_F_SETLKW_WR: + { + struct flock l; /* Linux: */ + l.l_type = opt->desc->minor; + l.l_whence = SEEK_SET; + l.l_start = 0; + l.l_len = LONG_MAX; + l.l_pid = 0; /* hope this uses our current process */ + if (Fcntl_lock(fd, opt->desc->major, &l) < 0) { + Error3("fcntl(%d, %d, {type=F_WRLCK,whence=SEEK_SET,start=0,len=LONG_MAX,pid=0}): %s", fd, opt->desc->major, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + } + break; + case OPT_SETUID_EARLY: + case OPT_SETUID: + if (Setuid(opt->value.u_uidt) < 0) { + Error2("setuid("F_uid"): %s", opt->value.u_uidt, + strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + break; + case OPT_SETGID_EARLY: + case OPT_SETGID: + if (Setgid(opt->value.u_gidt) < 0) { + Error2("setgid("F_gid"): %s", opt->value.u_gidt, + strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + break; + case OPT_SUBSTUSER: + { + struct passwd *pwd; + if ((pwd = getpwuid(opt->value.u_uidt)) == NULL) { + Error1("getpwuid("F_uid"): no such user", + opt->value.u_uidt); + opt->desc = ODESC_ERROR; ++opt; continue; + } + if (Initgroups(pwd->pw_name, pwd->pw_gid) < 0) { + Error3("initgroups(%s, "F_gid"): %s", + pwd->pw_name, pwd->pw_gid, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + if (Setgid(pwd->pw_gid) < 0) { + Error2("setgid("F_gid"): %s", pwd->pw_gid, + strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + if (Setuid(opt->value.u_uidt) < 0) { + Error2("setuid("F_uid"): %s", opt->value.u_uidt, + strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } +#if 1 + if (setenv("USER", pwd->pw_name, 1) < 0) + Error1("setenv(\"USER\", \"%s\", 1): insufficient space", + pwd->pw_name); + if (setenv("LOGNAME", pwd->pw_name, 1) < 0) + Error1("setenv(\"LOGNAME\", \"%s\", 1): insufficient space", + pwd->pw_name); + if (setenv("HOME", pwd->pw_dir, 1) < 0) + Error1("setenv(\"HOME\", \"%s\", 1): insufficient space", + pwd->pw_dir); + if (setenv("SHELL", pwd->pw_shell, 1) < 0) + Error1("setenv(\"SHELL\", \"%s\", 1): insufficient space", + pwd->pw_shell); +#endif + } + break; + case OPT_SUBSTUSER_DELAYED: + { + struct passwd *pwd; + + if ((pwd = getpwuid(opt->value.u_uidt)) == NULL) { + Error1("getpwuid("F_uid"): no such user", + opt->value.u_uidt); + opt->desc = ODESC_ERROR; ++opt; continue; + } + delayeduser_uid = opt->value.u_uidt; + delayeduser_gid = pwd->pw_gid; + if ((delayeduser_name = strdup(pwd->pw_name)) == NULL) { + Error1("strdup("F_Zu"): out of memory", + strlen(pwd->pw_name)+1); + opt->desc = ODESC_ERROR; ++opt; continue; + } + if ((delayeduser_dir = strdup(pwd->pw_dir)) == NULL) { + Error1("strdup("F_Zu"): out of memory", + strlen(pwd->pw_dir)+1); + opt->desc = ODESC_ERROR; ++opt; continue; + } + if ((delayeduser_shell = strdup(pwd->pw_shell)) == NULL) { + Error1("strdup("F_Zu"): out of memory", + strlen(pwd->pw_shell)+1); + opt->desc = ODESC_ERROR; ++opt; continue; + } + /* function to get all supplementary groups of user */ + delayeduser_ngids = sizeof(delayeduser_gids)/sizeof(gid_t); + getusergroups(delayeduser_name, delayeduser_gids, + &delayeduser_ngids); + delayeduser = true; + } + break; + case OPT_CHROOT_EARLY: + case OPT_CHROOT: + if (Chroot(opt->value.u_string) < 0) { + Error2("chroot(\"%s\"): %s", opt->value.u_string, + strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + if (Chdir("/") < 0) { + Error1("chdir(\"/\"): %s", strerror(errno)); + } + break; + case OPT_SETSID: + if (Setsid() < 0) { + Warn1("setsid(): %s", strerror(errno)); + if (Setpgid(getpid(), getppid()) < 0) { + Warn3("setpgid(%d, %d): %s", + getpid(), getppid(), strerror(errno)); + } else { + if (Setsid() < 0) { + Error1("setsid(): %s", strerror(errno)); + } + } + } + break; + case OPT_SETPGID: + if (Setpgid(0, opt->value.u_int) < 0) { + Warn2("setpgid(0, "F_pid"): %s", + opt->value.u_int, strerror(errno)); + } + break; + case OPT_TIOCSCTTY: + { + int mytty; + /* this code idea taken from ssh/pty.c: make pty controlling term. */ + if ((mytty = Open("/dev/tty", O_NOCTTY, 0640)) < 0) { + Warn1("open(\"/dev/tty\", O_NOCTTY, 0640): %s", strerror(errno)); + } else { + /*0 Info1("open(\"/dev/tty\", O_NOCTTY, 0640) -> %d", mytty);*/ +#ifdef TIOCNOTTY + if (Ioctl(mytty, TIOCNOTTY, NULL) < 0) { + Warn2("ioctl(%d, TIOCNOTTY, NULL): %s", + mytty, strerror(errno)); + } +#endif + if (Close(mytty) < 0) { + Info2("close(%d): %s", + mytty, strerror(errno)); + } + } +#ifdef TIOCSCTTY + if (Ioctl(fd, TIOCSCTTY, NULL) < 0) { + Warn2("ioctl(%d, TIOCSCTTY, NULL): %s", fd, strerror(errno)); + } +#endif + if (Tcsetpgrp(0, getpid()) < 0) { + Warn2("tcsetpgrp("F_pid"): %s", getpid(), strerror(errno)); + } + } + break; + default: Error1("applyopts(): option \"%s\" not implemented", + opt->desc->defname); + opt->desc = ODESC_ERROR; ++opt; continue; + } + +#if WITH_TERMIOS + } else if (opt->desc->func == OFUNC_TERMIOS_FLAG) { +#if 0 + union { + struct termios termarg; + tcflag_t flags[4]; + } tdata; + if (Tcgetattr(fd, &tdata.termarg) < 0) { + Error3("tcgetattr(%d, %p): %s", + fd, &tdata.termarg, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + if (opt->value.u_bool) { + tdata.flags[opt->desc->major] |= opt->desc->minor; + } else { + tdata.flags[opt->desc->major] &= ~opt->desc->minor; + } + if (Tcsetattr(fd, TCSADRAIN, &tdata.termarg) < 0) { + Error3("tcsetattr(%d, TCSADRAIN, %p): %s", + fd, &tdata.termarg, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } +#else + if (xiotermiosflag_applyopt(fd, opt) < 0) { + opt->desc = ODESC_ERROR; ++opt; continue; + } +#endif + + } else if (opt->desc->func == OFUNC_TERMIOS_VALUE) { + union { + struct termios termarg; + tcflag_t flags[4]; + } tdata; + if (((opt->value.u_uint << opt->desc->arg3) & opt->desc->minor) != + (opt->value.u_uint << opt->desc->arg3)) { + Error2("option %s: invalid value %u", + opt->desc->defname, opt->value.u_uint); + opt->desc = ODESC_ERROR; ++opt; continue; + } + if (Tcgetattr(fd, &tdata.termarg) < 0) { + Error3("tcgetattr(%d, %p): %s", + fd, &tdata.termarg, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + + tdata.flags[opt->desc->major] &= ~opt->desc->minor; + tdata.flags[opt->desc->major] |= + ((opt->value.u_uint << opt->desc->arg3) & opt->desc->minor); + if (Tcsetattr(fd, TCSADRAIN, &tdata.termarg) < 0) { + Error3("tcsetattr(%d, TCSADRAIN, %p): %s", + fd, &tdata.termarg, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + + } else if (opt->desc->func == OFUNC_TERMIOS_PATTERN) { + union { + struct termios termarg; + tcflag_t flags[4]; + } tdata; + if (Tcgetattr(fd, &tdata.termarg) < 0) { + Error3("tcgetattr(%d, %p): %s", + fd, &tdata.termarg, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + tdata.flags[opt->desc->major] &= ~opt->desc->arg3; + tdata.flags[opt->desc->major] |= opt->desc->minor; + if (Tcsetattr(fd, TCSADRAIN, &tdata.termarg) < 0) { + Error3("tcsetattr(%d, TCSADRAIN, %p): %s", + fd, &tdata.termarg, strerror(errno)); + opt->desc = ODESC_ERROR;++opt; continue; + } + + } else if (opt->desc->func == OFUNC_TERMIOS_CHAR) { + struct termios termarg; + if (Tcgetattr(fd, &termarg) < 0) { + Error3("tcgetattr(%d, %p): %s", + fd, &termarg, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + termarg.c_cc[opt->desc->major] = opt->value.u_byte; + if (Tcsetattr(fd, TCSADRAIN, &termarg) < 0) { + Error3("tcsetattr(%d, TCSADRAIN, %p): %s", + fd, &termarg, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + +#ifdef HAVE_TERMIOS_ISPEED + } else if (opt->desc->func == OFUNC_TERMIOS_SPEED) { + union { + struct termios termarg; + speed_t speeds[sizeof(struct termios)/sizeof(speed_t)]; + } tdata; + if (Tcgetattr(fd, &tdata.termarg) < 0) { + Error3("tcgetattr(%d, %p): %s", + fd, &tdata.termarg, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + tdata.speeds[opt->desc->major] = opt->value.u_uint; + if (Tcsetattr(fd, TCSADRAIN, &tdata.termarg) < 0) { + Error3("tcsetattr(%d, TCSADRAIN, %p): %s", + fd, &tdata.termarg, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } +#endif /* HAVE_TERMIOS_ISPEED */ + + } else if (opt->desc->func == OFUNC_TERMIOS_SPEC) { + struct termios termarg; + if (Tcgetattr(fd, &termarg) < 0) { + Error3("tcgetattr(%d, %p): %s", + fd, &termarg, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + switch (opt->desc->optcode) { + case OPT_RAW: + termarg.c_iflag &= + ~(IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXOFF +#ifdef IUCLC + |IUCLC +#endif + |IXANY|IMAXBEL); + termarg.c_iflag |= (0); + termarg.c_oflag &= ~(OPOST); + termarg.c_oflag |= (0); + termarg.c_cflag &= ~(0); + termarg.c_cflag |= (0); + termarg.c_lflag &= ~(ISIG|ICANON +#ifdef XCASE + |XCASE +#endif + ); + termarg.c_lflag |= (0); + termarg.c_cc[VMIN] = 1; + termarg.c_cc[VTIME] = 0; + break; + case OPT_SANE: + /* cread -ignbrk brkint -inlcr -igncr icrnl + -ixoff -iuclc -ixany imaxbel opost -olcuc -ocrnl + onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 + vt0 ff0 isig icanon iexten echo echoe echok -echonl + -noflsh -xcase -tostop -echoprt echoctl echoke, and + also sets all special characters to their default + values. +*/ + termarg.c_iflag &= ~(IGNBRK|INLCR|IGNCR|IXOFF +#ifdef IUCLC + |IUCLC +#endif + |IXANY); + termarg.c_iflag |= (BRKINT|ICRNL|IMAXBEL); + termarg.c_oflag &= ~(0 /* for canonical reasons */ +#ifdef OLCUC + |OLCUC +#endif +#ifdef OCRNL + |OCRNL +#endif +#ifdef ONOCR + |ONOCR +#endif +#ifdef ONLRET + |ONLRET +#endif +#ifdef OFILL + |OFILL +#endif +#ifdef OFDEL + |OFDEL +#endif +#ifdef NLDLY + |NLDLY +#endif +#ifdef CRDLY + |CRDLY +#endif +#ifdef TABDLY + |TABDLY +#endif +#ifdef BSDLY + |BSDLY +#endif +#ifdef VTDLY + |VTDLY +#endif +#ifdef FFDLY + |FFDLY +#endif + ); + termarg.c_oflag |= (OPOST|ONLCR +#ifdef NL0 + |NL0 +#endif +#ifdef CR0 + |CR0 +#endif +#ifdef TAB0 + |TAB0 +#endif +#ifdef BS0 + |BS0 +#endif +#ifdef VT0 + |VT0 +#endif +#ifdef FF0 + |FF0 +#endif + ); + termarg.c_cflag &= ~(0); + termarg.c_cflag |= (CREAD); + termarg.c_lflag &= ~(ECHONL|NOFLSH +#ifdef XCASE + |XCASE +#endif + |TOSTOP +#ifdef ECHOPRT + |ECHOPRT +#endif + ); + termarg.c_lflag |= (ISIG|ICANON|IEXTEN|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE); + /*! "sets characters to their default values... - which? */ + break; + default: + Error("TERMIOS option not handled - internal error?"); + } + if (Tcsetattr(fd, TCSADRAIN, &termarg) < 0) { + Error3("tcsetattr(%d, TCSADRAIN, %p): %s", + fd, &termarg, strerror(errno)); + opt->desc = ODESC_ERROR; ++opt; continue; + } + +#endif /* WITH_TERMIOS */ + + } else { + /*Error1("applyopts(): function %d not implemented", + opt->desc->func);*/ + if (opt->desc->func != OFUNC_EXT && opt->desc->func != OFUNC_SIGNAL) { + Error1("applyopts(): option \"%s\" does not apply", + opt->desc->defname); + opt->desc = ODESC_ERROR; + ++opt; + continue; + } + ++opt; + continue; + } + opt->desc = ODESC_DONE; + ++opt; + } + return 0; +} + +/* applies to fd all options belonging to phases */ +/* 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), + OFUNC_TERMIOS_FLAG, OFUNC_TERMIOS_PATTERN, and some OFUNC_SPEC */ +int applyopts2(int fd, struct opt *opts, unsigned int from, unsigned int to) { + unsigned int i; + int stat; + + for (i = from; i <= to; ++i) { + if ((stat = applyopts(fd, opts, i)) < 0) + return stat; + } + return 0; +} + +/* apply and consume all options of type FLAG and group. + Return 0 if everything went right, or -1 if an error occurred. */ +int applyopts_flags(struct opt *opts, int group, flags_t *result) { + struct opt *opt = opts; + + if (!opts) return 0; + + while (opt->desc != ODESC_END) { + if (opt->desc != ODESC_DONE && + (opt->desc->group & group)) { + if (opt->desc->func == OFUNC_FLAG) { + if (opt->value.u_bool) { + *result |= opt->desc->major; + } else { + *result &= ~opt->desc->major; + } + opt->desc = ODESC_DONE; + } else if (opt->desc->func == OFUNC_FLAG_PATTERN) { + *result &= ~opt->desc->minor; + *result |= opt->desc->major; + opt->desc = ODESC_DONE; + } + } + ++opt; + } + return 0; +} + + + +/* set the FD_CLOEXEC fcntl if the options do not set it to 0 */ +int applyopts_cloexec(int fd, struct opt *opts) { + bool docloexec = 1; + + if (!opts) return 0; + + retropt_bool(opts, OPT_CLOEXEC, &docloexec); + if (docloexec) { + if (Fcntl_l(fd, F_SETFD, FD_CLOEXEC) < 0) { + Warn2("fcntl(%d, F_SETFD, FD_CLOEXEC): %s", fd, strerror(errno)); + } + } + return 0; +} + +int applyopts_fchown(int fd, struct opt *opts) { + uid_t user = -1; + gid_t group = -1; + + retropt_uidt(opts, OPT_USER, &user); + retropt_gidt(opts, OPT_GROUP, &group); + + if (user != (uid_t)-1 || group != (gid_t)-1) { + if (Fchown(fd, user, group) < 0) { + Error4("fchown(%d, "F_uid", "F_gid"): %s", fd, user, group, + strerror(errno)); + return STAT_RETRYLATER; + } + } + return 0; +} + +/* caller must make sure that option is not yet consumed */ +static int applyopt_offset(struct single *xfd, struct opt *opt) { + unsigned char *ptr; + + ptr = (unsigned char *)xfd + opt->desc->major; + switch (opt->desc->type) { + case TYPE_BOOL: + *(bool *)ptr = opt->value.u_bool; break; + case TYPE_DOUBLE: + *(double *)ptr = opt->value.u_double; break; + case TYPE_TIMEVAL: + *(struct timeval *)ptr = opt->value.u_timeval; break; + case TYPE_STRING_NULL: + if (opt->value.u_string == NULL) { + *(char **)ptr = NULL; + break; + } + /* PASSTHROUGH */ + case TYPE_STRING: + if ((*(char **)ptr = strdup(opt->value.u_string)) == NULL) { + Error1("strdup("F_Zu"): out of memory", + strlen(opt->value.u_string)+1); + } + break; + case TYPE_CONST: + *(int *)ptr = opt->desc->minor; + break; + default: + Error1("applyopt_offset(): type %d not implemented", + opt->desc->type); + return -1; + } + opt->desc = ODESC_DONE; + return 0; +} + +int applyopts_offset(struct single *xfd, struct opt *opts) { + struct opt *opt; + + opt = opts; while (opt->desc != ODESC_END) { + if ((opt->desc == ODESC_DONE) || + opt->desc->func != OFUNC_OFFSET) { + ++opt; continue; } + + applyopt_offset(xfd, opt); + opt->desc = ODESC_DONE; + ++opt; + } + return 0; +} + +/* applies to xfd all OFUNC_EXT options belonging to phase + returns -1 if an error occurred */ +int applyopts_single(struct single *xfd, struct opt *opts, enum e_phase phase) { + struct opt *opt; + int lockrc; + + if (!opts) return 0; + + opt = opts; while (opt->desc != ODESC_END) { + if ((opt->desc == ODESC_DONE) || + (opt->desc->phase != phase && phase != PH_ALL)) { + /* option not handled in this function */ + ++opt; continue; + } else { + switch (opt->desc->func) { + + case OFUNC_OFFSET: + applyopt_offset(xfd, opt); + break; + + case OFUNC_EXT: + switch (opt->desc->optcode) { +#if 0 + case OPT_IGNOREEOF: + xfd->ignoreeof = true; + break; + case OPT_CR: + xfd->lineterm = LINETERM_CR; + break; + case OPT_CRNL: + xfd->lineterm = LINETERM_CRNL; + break; +#endif /* 0 */ + case OPT_READBYTES: + xfd->readbytes = opt->value.u_sizet; + xfd->actbytes = xfd->readbytes; + break; + case OPT_LOCKFILE: + if (xfd->lock.lockfile) { + Error("only one use of options lockfile and waitlock allowed"); + } + xfd->lock.lockfile = strdup(opt->value.u_string); + xfd->lock.intervall.tv_sec = 1; + xfd->lock.intervall.tv_nsec = 0; + + if ((lockrc = xiolock(&xfd->lock)) < 0) { + /* error message already printed */ + return -1; + } + if (lockrc) { + Error1("could not obtain lock \"%s\"", xfd->lock.lockfile); + } else { + xfd->havelock = true; + } + break; + case OPT_WAITLOCK: + if (xfd->lock.lockfile) { + Error("only one use of options lockfile and waitlock allowed"); + } + xfd->lock.lockfile = strdup(opt->value.u_string); + xfd->lock.waitlock = true; + xfd->lock.intervall.tv_sec = 1; + xfd->lock.intervall.tv_nsec = 0; + + /*! this should be integrated into central select loop */ + if (xiolock(&xfd->lock) < 0) { + return -1; + } + xfd->havelock = true; + break; + + default: + /* just store the value in the correct component of struct single */ + if (opt->desc->type == TYPE_CONST) { + /* only for integral types compatible to int */ + *(int *)(&((char *)xfd)[opt->desc->major]) = opt->desc->arg3; + } else { + memcpy(&((char *)xfd)[opt->desc->major], &opt->value, opt->desc->minor); + } + } + break; + + case OFUNC_OFFSET_MASKS: + { + void *masks = (char *)xfd + opt->desc->major; + size_t masksize = opt->desc->minor; + unsigned long bit = opt->desc->arg3; + switch (masksize) { + case sizeof(uint16_t): + if (opt->value.u_bool) { + ((uint16_t *)masks)[0] |= bit; + } else { + ((uint16_t *)masks)[1] |= bit; + } + break; + case sizeof(uint32_t): + if (opt->value.u_bool) { + ((uint32_t *)masks)[0] |= bit; + } else { + ((uint32_t *)masks)[1] |= bit; + } + break; + default: + Info1("sizeof(uint32_t)="F_Zu, sizeof(uint32_t)); + Error1("applyopts_single: masksize "F_Zu" not implemented", + masksize); + } + } + break; + +#if WITH_SOCKET + case OFUNC_SOCKOPT: + switch (opt->desc->optcode) { +#if WITH_IP4 && (defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)) + case OPT_IP_ADD_MEMBERSHIP: + { + union { +#if HAVE_STRUCT_IP_MREQN + struct ip_mreqn mreqn; +#endif + struct ip_mreq mreq; + } ip4_mreqn = {{{0}}}; + /* IPv6 not supported - seems to have different handling */ +/* +mc:addr:ifname|ifind +mc:ifname|ifind +mc:addr +*/ + union sockaddr_union sockaddr1; + size_t socklen1 = sizeof(sockaddr1.ip4); + union sockaddr_union sockaddr2; + size_t socklen2 = sizeof(sockaddr2.ip4); + + /* first parameter is alway multicast address */ + /*! result */ + xiogetaddrinfo(opt->value.u_ip_mreq.multiaddr, NULL, + xfd->para.socket.la.soa.sa_family, + SOCK_DGRAM, IPPROTO_IP, + &sockaddr1, &socklen1, 0, 0); + ip4_mreqn.mreq.imr_multiaddr = sockaddr1.ip4.sin_addr; + if (0) { + ; /* for canonical reasons */ +#if HAVE_STRUCT_IP_MREQN + } else if (opt->value.u_ip_mreq.ifindex[0] != '\0') { + /* three parameters */ + /* second parameter is interface address */ + xiogetaddrinfo(opt->value.u_ip_mreq.param2, NULL, + xfd->para.socket.la.soa.sa_family, + SOCK_DGRAM, IPPROTO_IP, + &sockaddr2, &socklen2, 0, 0); + ip4_mreqn.mreq.imr_interface = sockaddr2.ip4.sin_addr; + /* third parameter is interface */ + if (ifindex(opt->value.u_ip_mreq.ifindex, + (unsigned int *)&ip4_mreqn.mreqn.imr_ifindex) + < 0) { + Error1("cannot resolve interface \"%s\"", + opt->value.u_ip_mreq.ifindex); + } +#endif /* HAVE_STRUCT_IP_MREQN */ + } else { + /* two parameters */ + if (0) { + ; /* for canonical reasons */ +#if HAVE_STRUCT_IP_MREQN + /* there is a form with two parameters that uses mreqn */ + } else if (ifindex(opt->value.u_ip_mreq.param2, + (unsigned int *)&ip4_mreqn.mreqn.imr_ifindex) + >= 0) { + /* yes, second param converts to interface */ + ip4_mreqn.mreq.imr_interface.s_addr = htonl(0); +#endif /* HAVE_STRUCT_IP_MREQN */ + } else { + /*! result */ + xiogetaddrinfo(opt->value.u_ip_mreq.param2, NULL, + xfd->para.socket.la.soa.sa_family, + SOCK_DGRAM, IPPROTO_IP, + &sockaddr2, &socklen2, 0, 0); + ip4_mreqn.mreq.imr_interface = sockaddr2.ip4.sin_addr; + } + } + +#if LATER + if (0) { + ; /* for canonical reasons */ + } else if (xfd->para.socket.la.soa.sa_family == PF_INET) { + } else if (xfd->para.socket.la.soa.sa_family == PF_INET6) { + ip6_mreqn.mreq.imr_multiaddr = sockaddr1.ip6.sin6_addr; + ip6_mreqn.mreq.imr_interface = sockaddr2.ip6.sin6_addr; + } +#endif + +#if HAVE_STRUCT_IP_MREQN + if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor, + &ip4_mreqn.mreqn, sizeof(ip4_mreqn.mreqn)) < 0) { + Error8("setsockopt(%d, %d, %d, {0x%08x,0x%08x,%d}, "F_Zu"): %s", + xfd->fd, opt->desc->major, opt->desc->minor, + ip4_mreqn.mreqn.imr_multiaddr.s_addr, + ip4_mreqn.mreqn.imr_address.s_addr, + ip4_mreqn.mreqn.imr_ifindex, + sizeof(ip4_mreqn.mreqn), + strerror(errno)); + opt->desc = ODESC_ERROR; continue; + } +#else + if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor, + &ip4_mreqn.mreq, sizeof(ip4_mreqn.mreq)) < 0) { + Error7("setsockopt(%d, %d, %d, {0x%08x,0x%08x}, "F_Zu"): %s", + xfd->fd, opt->desc->major, opt->desc->minor, + ip4_mreqn.mreq.imr_multiaddr, + ip4_mreqn.mreq.imr_interface, + sizeof(ip4_mreqn.mreq), + strerror(errno)); + opt->desc = ODESC_ERROR; continue; + } +#endif + break; + } + break; +#endif /* WITH_IP4 && (defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)) */ + + + +#if WITH_IP6 && defined(HAVE_STRUCT_IPV6_MREQ) + case OPT_IPV6_JOIN_GROUP: + { + struct ipv6_mreq ip6_mreq = {{{{0}}}}; + union sockaddr_union sockaddr1; + size_t socklen1 = sizeof(sockaddr1.ip6); + + /* always two parameters */ + /* first parameter is multicast address */ + /*! result */ + xiogetaddrinfo(opt->value.u_ip_mreq.multiaddr, NULL, + xfd->para.socket.la.soa.sa_family, + SOCK_DGRAM, IPPROTO_IP, + &sockaddr1, &socklen1, 0, 0); + ip6_mreq.ipv6mr_multiaddr = sockaddr1.ip6.sin6_addr; + if (ifindex(opt->value.u_ip_mreq.param2, + &ip6_mreq.ipv6mr_interface) < 0) { + Error1("interface \"%s\" not found", + opt->value.u_ip_mreq.param2); + ip6_mreq.ipv6mr_interface = htonl(0); + } + + if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor, + &ip6_mreq, sizeof(ip6_mreq)) < 0) { + Error6("setsockopt(%d, %d, %d, {...,0x%08x}, "F_Zu"): %s", + xfd->fd, opt->desc->major, opt->desc->minor, + ip6_mreq.ipv6mr_interface, + sizeof(ip6_mreq), + strerror(errno)); + opt->desc = ODESC_ERROR; continue; + } + } + break; +#endif /* WITH_IP6 && defined(HAVE_STRUCT_IPV6_MREQ) */ + default: + /* ignore here */ + ++opt; continue; + } + break; +#endif /* WITH_SOCKET */ + + default: + ++opt; + continue; + } + opt->desc = ODESC_DONE; + ++opt; + } + } + return 0; +} + + +/* xfd->para.exec.pid must be set */ +int applyopts_signal(struct single *xfd, struct opt *opts) { + struct opt *opt; + + if (!opts) return 0; + + opt = opts; while (opt->desc != ODESC_END) { + if (opt->desc == ODESC_DONE || opt->desc->func != OFUNC_SIGNAL) { + ++opt; continue; + } + + if (xio_opt_signal(xfd->para.exec.pid, opt->desc->major) < 0) { + opt->desc = ODESC_ERROR; continue; + } + opt->desc = ODESC_DONE; + ++opt; + } + return 0; +} + +/* apply remaining options to file descriptor, and tell us if something is + still unused */ +int _xio_openlate(struct single *fd, struct opt *opts) { + int numleft; + int result; + + _xioopen_setdelayeduser(); + + if ((result = applyopts(fd->fd, opts, PH_LATE)) < 0) { + return result; + } + if ((result = applyopts_single(fd, opts, PH_LATE)) < 0) { + return result; + } + if ((result = applyopts(fd->fd, opts, PH_LATE2)) < 0) { + return result; + } + + if ((numleft = leftopts(opts)) > 0) { + showleft(opts); + Error1("%d option(s) could not be used", numleft); + return -1; + } + return 0; +} + +int dropopts(struct opt *opts, unsigned int phase) { + struct opt *opt; + + /*!*/ + if (phase == PH_ALL) { + free(opts); + return 0; + } + opt = opts; while (opt && opt->desc != ODESC_END) { + if (opt->desc != ODESC_DONE && opt->desc->phase == phase) { + Debug1("ignoring option \"%s\"", opt->desc->defname); + opt->desc = ODESC_DONE; + } + ++opt; + } + return 0; +} + +int dropopts2(struct opt *opts, unsigned int from, unsigned int to) { + unsigned int i; + + for (i = from; i <= to; ++i) { + dropopts(opts, i); + } + return 0; +} + diff --git a/xioopts.h b/xioopts.h new file mode 100644 index 0000000..7d13ea5 --- /dev/null +++ b/xioopts.h @@ -0,0 +1,872 @@ +/* $Id: xioopts.h,v 1.70 2007/03/06 21:19:46 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xioopts_h_included +#define __xioopts_h_included 1 + +#define ODESC_END ((void *)0) /* indicates end of actual option array */ +#define ODESC_DONE ((void *)-1) /* indicates that option has been applied */ +#define ODESC_ERROR ODESC_DONE /* maybe later */ + +/* atomic structure for use in the option search table; keep compatible with + struct wordent! */ +struct optname { + const char *name; + const struct optdesc *desc; +} ; + +/* keep consistent with xiohelp.c:optiontypenames[] ! */ +enum e_types { + TYPE_CONST, /* keyword means a fix value */ + TYPE_BIN, /* raw binary data, length determined by data */ + TYPE_BOOL, /* value is 0 or 1 (no-value is interpreted as 1) */ + TYPE_BYTE, /* unsigned char */ + TYPE_INT, /* int */ + TYPE_LONG, /* long */ + TYPE_STRING, /* char * */ + TYPE_NAME = TYPE_STRING, + TYPE_FILENAME = TYPE_STRING, + TYPE_PTRDIFF, /* ptrdiff_t */ + TYPE_SHORT, /* short */ + TYPE_SIZE_T, /* size_t */ + TYPE_SOCKADDR, /* struct sockaddr * */ + TYPE_UINT, /* unsigned int */ + TYPE_ULONG, /* unsigned long */ + TYPE_USHORT, /* unsigned short */ + TYPE_MODET, /* representation of mode_t */ + TYPE_GIDT, /* representation of gid_t */ + TYPE_UIDT, /* representation of uid_t */ + /*TYPE_FLAG,*/ + TYPE_INT3, /* int[3] */ + TYPE_TIMEVAL, /* struct timeval: {long;long;}, seconds and microsec. */ + TYPE_TIMESPEC, /* struct timespec: {time_t;long;}, seconds and nanosec. */ +#if HAVE_STRUCT_LINGER + TYPE_LINGER, /* struct linger */ +#endif /* HAVE_STRUCT_LINGER */ + TYPE_DOUBLE, /* double */ + TYPE_STRING_NULL, /* char *; string or NULL */ + TYPE_LONGLONG, /* long long */ + TYPE_OFF32, /* off_t */ + TYPE_OFF64, /* off64_t */ + TYPE_IP_MREQN, /* for struct ip_mreq or struct ip_mreqn */ + TYPE_IP4NAME, /* IPv4 hostname or address */ + + TYPE_2BYTE = TYPE_USHORT +} ; + +enum e_func { + OFUNC_NONE, /* no function - should not occur */ + OFUNC_FLAG, /* no function, but bitposition, only with bool; arg1 is mask */ + OFUNC_FLAG_PATTERN, /* no function, but bitpattern: arg1 is pattern, arg2 is mask */ + OFUNC_SEEK32, /* lseek(): arg1 is whence (SEEK_SET etc.) */ + OFUNC_SEEK64, /* lseek64(): arg1 is whence (SEEK_SET etc.) */ + OFUNC_FCNTL, /* fcntl(, ): arg1 is cmd */ + OFUNC_IOCTL, /* ioctl(): arg1 is request */ + OFUNC_IOCTL_MASK_LONG, /* arg1 is getrequest, arg2 is setrequest: + ioctl(arg1, ); |= arg3; ioctl(arg2, ); */ + OFUNC_SOCKOPT, /* setsockopt() */ + OFUNC_SOCKOPT_APPEND,/* getsockopt(), append data, setsockopt() */ + OFUNC_FLOCK, /* flock() */ + OFUNC_TERMIO, /* termio() ? */ + OFUNC_SPEC, /* special, i.e. no generalizable function call */ + OFUNC_OFFSET, /* put a value into xiofile struct; major is offset */ + OFUNC_OFFSET_MASKS, /* !!! */ + /*OFUNC_APPL,*/ /* special, i.e. application must know which f. */ + OFUNC_EXT, /* with extended file descriptors only */ + OFUNC_TERMIOS_FLAG, /* a flag in struct termios: major..tcflag, minor..bit + */ + OFUNC_TERMIOS_PATTERN, /* a multibit: major..tcflag, minor..pattern, + arg3..mask */ + OFUNC_TERMIOS_VALUE, /* a variable value: major..tcflag, minor..mask, arg3..shift */ + OFUNC_TERMIOS_CHAR, /* a termios functional character: major..c_cc index */ + OFUNC_TERMIOS_SPEED, /* termios c_ispeed etc on FreeBSD */ + OFUNC_TERMIOS_SPEC, /* termios combined modes */ + OFUNC_SIGNAL, /* a signal that should be passed to child process */ + OFUNC_RESOLVER, /* a bit position used on _res.options */ + OFUNC_IFFLAG /* interface flag: locical-or a 1bit mask */ +} ; + +/* for simpler handling of option-to-connection-type relations we define + groups. to keep the search for options simple, we allow each option to + belong to at most one group only. (we have a dummy GROUP_NONE for those + that don't want to belong to any...) + The caller of parseopts() specifies per bitpatter a set of groups where it + accepts options from. +*/ + +/*- the group bits are: +- 000ooooo 00000000 000000uf 0000ssss +- ooooo: more detailed description to ssss (e.g., socket family) +- ssss: the type of stream, as in stat.h: S_IF... +- f: has a named entry in the file system +- u: has user and group +*/ +/* keep consistent with xiohelp.c:addressgroupnames[] ! */ +/* a dummy group */ +#define GROUP_NONE 0x00000000 + +#define GROUP_FD 0x00000001 /* everything applyable to a fd */ +#define GROUP_FIFO 0x00000002 +#define GROUP_CHR 0x00000004 +#define GROUP_BLK 0x00000008 +#define GROUP_REG 0x00000010 +#define GROUP_FILE GROUP_REG +#define GROUP_SOCKET 0x00000020 +#define GROUP_READLINE 0x00000040 + +#define GROUP_NAMED 0x00000100 /* file system entry */ +#define GROUP_OPEN 0x00000200 /* flags for open() */ +#define GROUP_EXEC 0x00000400 /* program or script execution */ +#define GROUP_FORK 0x00000800 /* communication with forked process */ + +#define GROUP_LISTEN 0x00001000 /* socket in listening mode */ +/* 0x00002000 */ +#define GROUP_CHILD 0x00004000 /* autonom child process */ +#define GROUP_RETRY 0x00008000 /* when open/connect etc. fails */ +#define GROUP_TERMIOS 0x00010000 +#define GROUP_RANGE 0x00020000 /* differs from GROUP_LISTEN */ +#define GROUP_PTY 0x00040000 /* address pty or exec...,pty */ +#define GROUP_PARENT 0x00080000 /* for parent of communicating child */ + +#define GROUP_SOCK_UNIX 0x00100000 +#define GROUP_SOCK_IP4 0x00200000 +#define GROUP_SOCK_IP6 0x00400000 +#define GROUP_SOCK_IP (GROUP_SOCK_IP4|GROUP_SOCK_IP6) +#define GROUP_INTERFACE 0x00800000 +#define GROUP_TUN GROUP_INTERFACE + +#define GROUP_IP_UDP 0x01000000 +#define GROUP_IP_TCP 0x02000000 +#define GROUP_IPAPP (GROUP_IP_UDP|GROUP_IP_TCP) /* true: indicates one of UDP, TCP */ +#define GROUP_IP_SOCKS4 0x04000000 +#define GROUP_OPENSSL 0x08000000 + +#define GROUP_PROCESS 0x10000000 /* a process related option */ +#define GROUP_APPL 0x20000000 /* option handled by data loop */ +#define GROUP_HTTP 0x40000000 /* any HTTP client */ + +#define GROUP_ANY (GROUP_PROCESS|GROUP_APPL) +#define GROUP_ALL 0xffffffff + + +/* no IP multicasts, no error queue yet */ +/* the only reason for keeping this enum sorted is to help detecting name + conflicts. */ +/* optcode's */ +enum e_optcode { + OPT_ADDRESS_FAMILY = 1, + /* these are not alphabetically, I know... */ + OPT_B0, /* termios.c_cflag */ + OPT_B50, /* termios.c_cflag */ + OPT_B75, /* termios.c_cflag */ + OPT_B110, /* termios.c_cflag */ + OPT_B134, /* termios.c_cflag */ + OPT_B150, /* termios.c_cflag */ + OPT_B200, /* termios.c_cflag */ + OPT_B300, /* termios.c_cflag */ + OPT_B600, /* termios.c_cflag */ + OPT_B900, /* termios.c_cflag - HP-UX */ + OPT_B1200, /* termios.c_cflag */ + OPT_B1800, /* termios.c_cflag */ + OPT_B2400, /* termios.c_cflag */ + OPT_B3600, /* termios.c_cflag - HP-UX */ + OPT_B4800, /* termios.c_cflag */ + OPT_B7200, /* termios.c_cflag - HP-UX */ + OPT_B9600, /* termios.c_cflag */ + OPT_B19200, /* termios.c_cflag */ + OPT_B38400, /* termios.c_cflag */ + OPT_B57600, /* termios.c_cflag */ + OPT_B115200, /* termios.c_cflag */ + OPT_B230400, /* termios.c_cflag */ + OPT_B460800, /* termios.c_cflag */ + OPT_B500000, /* termios.c_cflag */ + OPT_B576000, /* termios.c_cflag */ + OPT_B921600, /* termios.c_cflag */ + OPT_B1000000, /* termios.c_cflag */ + OPT_B1152000, /* termios.c_cflag */ + OPT_B1500000, /* termios.c_cflag */ + OPT_B2000000, /* termios.c_cflag */ + OPT_B2500000, /* termios.c_cflag */ + OPT_B3000000, /* termios.c_cflag */ + OPT_B3500000, /* termios.c_cflag */ + OPT_B4000000, /* termios.c_cflag */ + OPT_BACKLOG, + OPT_BIND, /* a socket address as character string */ + OPT_BRKINT, /* termios.c_iflag */ +#ifdef BSDLY +# ifdef BS0 + OPT_BS0, /* termios.c_oflag */ +# endif +# ifdef BS1 + OPT_BS1, /* termios.c_oflag */ +# endif + OPT_BSDLY, /* termios.c_oflag */ +#endif + OPT_CHROOT, /* chroot() past file system access */ + 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 */ +#ifdef CR0 + OPT_CR0, /* termios.c_oflag */ +#endif +#ifdef CR1 + OPT_CR1, /* termios.c_oflag */ +#endif +#ifdef CR2 + OPT_CR2, /* termios.c_oflag */ +#endif +#ifdef CR3 + OPT_CR3, /* termios.c_oflag */ +#endif +#ifdef CRDLY + OPT_CRDLY, /* termios.c_oflag */ +#endif + OPT_CREAD, /* termios.c_cflag */ + OPT_CRNL, /* customized */ +#ifdef CRTSCTS + OPT_CRTSCTS, /* termios.c_cflag */ +#endif + OPT_CS5, /* termios.c_cflag */ + OPT_CS6, /* termios.c_cflag */ + OPT_CS7, /* termios.c_cflag */ + OPT_CS8, /* termios.c_cflag */ + OPT_CSIZE, /* termios.c_cflag */ + OPT_CSTOPB, /* termios.c_cflag */ + OPT_DASH, /* exec() */ + OPT_ECHO, /* termios.c_lflag */ + OPT_ECHOCTL, /* termios.c_lflag */ + OPT_ECHOE, /* termios.c_lflag */ + OPT_ECHOK, /* termios.c_lflag */ + OPT_ECHOKE, /* termios.c_lflag */ + OPT_ECHONL, /* termios.c_lflag */ +#ifdef ECHOPRT + OPT_ECHOPRT, /* termios.c_lflag */ +#endif + OPT_END_CLOSE, /* xfd.stream.howtoend = END_CLOSE */ + OPT_EXT2_SECRM, + OPT_EXT2_UNRM, + OPT_EXT2_COMPR, + OPT_EXT2_SYNC, + OPT_EXT2_IMMUTABLE, + OPT_EXT2_APPEND, + OPT_EXT2_NODUMP, + OPT_EXT2_NOATIME, + OPT_EXT2_JOURNAL_DATA, + OPT_EXT2_NOTAIL, + OPT_EXT2_DIRSYNC, + OPT_EXT2_TOPDIR, + OPT_FDIN, + OPT_FDOUT, +#ifdef FFDLY +# ifdef FF0 + OPT_FF0, /* termios.c_oflag */ +# endif +# ifdef FF1 + OPT_FF1, /* termios.c_oflag */ +# endif + OPT_FFDLY, /* termios.c_oflag */ +#endif +#ifdef FIOSETOWN + OPT_FIOSETOWN, /* asm/sockios.h */ +#endif + OPT_FLOCK_EX, /* flock(fd, LOCK_EX) */ + OPT_FLOCK_EX_NB, /* flock(fd, LOCK_EX|LOCK_NB) */ + OPT_FLOCK_SH, /* flock(fd, LOCK_SH) */ + OPT_FLOCK_SH_NB, /* flock(fd, LOCK_SH|LOCK_NB) */ + OPT_FLUSHO, /* termios.c_lflag */ + /*0 OPT_FORCE,*/ + OPT_FOREVER, + OPT_FORK, + OPT_FTRUNCATE32, /* ftruncate() */ + OPT_FTRUNCATE64, /* ftruncate64() */ + OPT_F_SETLKW_RD, /* fcntl with struct flock - read-lock, wait */ + OPT_F_SETLKW_WR, /* fcntl with struct flock - write-lock, wait */ + OPT_F_SETLK_RD, /* fcntl with struct flock - read-lock */ + OPT_F_SETLK_WR, /* fcntl with struct flock - write-lock */ + OPT_GROUP, + OPT_GROUP_EARLY, + OPT_GROUP_LATE, + OPT_HISTORY_FILE, /* readline history file */ + OPT_HUPCL, /* termios.c_cflag */ + OPT_ICANON, /* termios.c_lflag */ + OPT_ICRNL, /* termios.c_iflag */ + OPT_IEXTEN, /* termios.c_lflag */ + OPT_IFF_ALLMULTI, /* struct ifreq.ifr_flags */ + OPT_IFF_AUTOMEDIA, /* struct ifreq.ifr_flags */ + OPT_IFF_BROADCAST, /* struct ifreq.ifr_flags */ + OPT_IFF_DEBUG, /* struct ifreq.ifr_flags */ + /*OPT_IFF_DYNAMIC,*/ /* struct ifreq.ifr_flags */ + OPT_IFF_LOOPBACK, /* struct ifreq.ifr_flags */ + OPT_IFF_MASTER, /* struct ifreq.ifr_flags */ + OPT_IFF_MULTICAST, /* struct ifreq.ifr_flags */ + OPT_IFF_NOARP, /* struct ifreq.ifr_flags */ + OPT_IFF_NOTRAILERS, /* struct ifreq.ifr_flags */ + OPT_IFF_NO_PI, /* tun: IFF_NO_PI */ + OPT_IFF_PORTSEL, /* struct ifreq.ifr_flags */ + OPT_IFF_POINTOPOINT, /* struct ifreq.ifr_flags */ + OPT_IFF_PROMISC, /* struct ifreq.ifr_flags */ + OPT_IFF_RUNNING, /* struct ifreq.ifr_flags */ + OPT_IFF_SLAVE, /* struct ifreq.ifr_flags */ + OPT_IFF_UP, /* struct ifreq.ifr_flags */ + OPT_IGNBRK, /* termios.c_iflag */ + OPT_IGNCR, /* termios.c_iflag */ + OPT_IGNORECR, /* HTTP */ + OPT_IGNOREEOF, /* customized */ + OPT_IGNPAR, /* termios.c_iflag */ + OPT_IMAXBEL, /* termios.c_iflag */ + OPT_INLCR, /* termios.c_iflag */ + OPT_INPCK, /* termios.c_iflag */ + OPT_INTERVALL, + OPT_IPV6_JOIN_GROUP, + OPT_IPV6_V6ONLY, +#if 0 /* see Linux: man 7 netlink; probably not what we need yet */ + OPT_IO_SIOCGIFNAME, +#endif + OPT_IP_ADD_MEMBERSHIP, +#ifdef IP_HDRINCL + OPT_IP_HDRINCL, +#endif +#ifdef IP_FREEBIND + OPT_IP_FREEBIND, +#endif +#ifdef IP_MTU + OPT_IP_MTU, +#endif +#ifdef IP_MTU_DISCOVER + OPT_IP_MTU_DISCOVER, +#endif + OPT_IP_MULTICAST_IF, + OPT_IP_MULTICAST_LOOP, + OPT_IP_MULTICAST_TTL, + OPT_IP_OPTIONS, +#ifdef IP_PKTINFO + OPT_IP_PKTINFO, +#endif +#ifdef IP_PKTOPTIONS + OPT_IP_PKTOPTIONS, +#endif +#ifdef IP_RECVERR + OPT_IP_RECVERR, +#endif +#ifdef IP_RECVOPTS + OPT_IP_RECVOPTS, +#endif +#ifdef IP_RECVTOS + OPT_IP_RECVTOS, +#endif +#ifdef IP_RECVTTL + OPT_IP_RECVTTL, +#endif +#ifdef IP_RETOPTS + OPT_IP_RETOPTS, +#endif +#ifdef IP_ROUTER_ALERT + OPT_IP_ROUTER_ALERT, +#endif + OPT_IP_TOS, + OPT_IP_TTL, + OPT_ISIG, /* termios.c_lflag */ + OPT_ISPEED, /* termios.c_ispeed */ + OPT_ISTRIP, /* termios.c_iflag */ +#ifdef IUCLC + OPT_IUCLC, /* termios.c_iflag */ +#endif + OPT_IXANY, /* termios.c_iflag */ + OPT_IXOFF, /* termios.c_iflag */ + OPT_IXON, /* termios.c_iflag */ + OPT_LOCKFILE, + OPT_LOWPORT, +#ifdef NLDLY +# ifdef NL0 + OPT_NL0, /* termios.c_oflag */ +# endif +# ifdef NL0 + OPT_NL1, /* termios.c_oflag */ +# endif + OPT_NLDLY, /* termios.c_oflag */ +#endif + OPT_NOECHO, /* readline */ + OPT_NOFLSH, /* termios.c_lflag */ + OPT_NOFORK, /* exec, system */ + OPT_NOPROMPT, /* readline */ +#ifdef OCRNL + OPT_OCRNL, /* termios.c_oflag */ +#endif +#ifdef OFDEL + OPT_OFDEL, /* termios.c_oflag */ +#endif +#ifdef OFILL + OPT_OFILL, /* termios.c_oflag */ +#endif +#ifdef OLCUC + OPT_OLCUC, /* termios.c_oflag */ +#endif + OPT_ONLCR, /* termios.c_oflag */ +#ifdef ONLRET + OPT_ONLRET, /* termios.c_oflag */ +#endif +#ifdef ONOCR + OPT_ONOCR, /* termios.c_oflag */ +#endif +#if HAVE_OPENPTY + OPT_OPENPTY, +#endif + OPT_OPENSSL_CAFILE, + OPT_OPENSSL_CAPATH, + OPT_OPENSSL_CERTIFICATE, + OPT_OPENSSL_CIPHERLIST, + OPT_OPENSSL_DHPARAM, + OPT_OPENSSL_EGD, + OPT_OPENSSL_FIPS, + OPT_OPENSSL_KEY, + OPT_OPENSSL_METHOD, + OPT_OPENSSL_PSEUDO, + OPT_OPENSSL_VERIFY, + OPT_OPOST, /* termios.c_oflag */ + OPT_OSPEED, /* termios.c_ospeed */ + OPT_O_APPEND, +#ifdef O_ASYNC + OPT_O_ASYNC, +#endif + OPT_O_BINARY, /* Cygwin */ + OPT_O_CREATE, +#ifdef O_DEFER + OPT_O_DEFER, +#endif +#ifdef O_DELAY + OPT_O_DELAY, +#endif +#ifdef O_DIRECT + OPT_O_DIRECT, +#endif +#ifdef O_DIRECTORY + OPT_O_DIRECTORY, +#endif +#ifdef O_DSYNC + OPT_O_DSYNC, +#endif + OPT_O_EXCL, +#ifdef O_LARGEFILE + OPT_O_LARGEFILE, +#endif +#if defined(O_NDELAY) && (!defined(O_NONBLOCK) || O_NDELAY != O_NONBLOCK) + OPT_O_NDELAY, +#endif + OPT_O_NOATIME, + OPT_O_NOCTTY, +#ifdef O_NOFOLLOW + OPT_O_NOFOLLOW, +#endif + OPT_O_NOINHERIT, /* Cygwin */ + OPT_O_NONBLOCK, +#ifdef O_NSHARE + OPT_O_NSHARE, +#endif +#ifdef O_PRIV + OPT_O_PRIV, +#endif + OPT_O_RDONLY, /* open() */ + OPT_O_RDWR, /* open() */ +#ifdef O_RSHARE + OPT_O_RSHARE, +#endif +#ifdef O_RSYNC + OPT_O_RSYNC, +#endif +#ifdef O_SYNC + OPT_O_SYNC, +#endif + OPT_O_TEXT, /* Cygwin */ + OPT_O_TRUNC, /* open(): O_TRUNC */ + OPT_O_WRONLY, /* open() */ + OPT_PARENB, /* termios.c_cflag */ + OPT_PARMRK, /* termios.c_iflag */ + OPT_PARODD, /* termios.c_cflag */ + OPT_PATH, +#ifdef PENDIN + OPT_PENDIN, /* termios.c_lflag */ +#endif + OPT_PERM, + OPT_PERM_EARLY, + OPT_PERM_LATE, + OPT_PIPES, + /*OPT_PORT,*/ + OPT_PROMPT, /* readline */ + OPT_PROTOCOL_FAMILY, + OPT_PROXYPORT, + OPT_PROXY_AUTHORIZATION, + OPT_PROXY_RESOLVE, +#if HAVE_DEV_PTMX || HAVE_DEV_PTC + OPT_PTMX, +#endif + OPT_PTY, + OPT_PTY_INTERVALL, + OPT_PTY_WAIT_SLAVE, + OPT_RANGE, /* restrict client socket address */ + OPT_RAW, /* termios */ + OPT_READBYTES, + OPT_RES_AAONLY, /* resolver(3) */ + OPT_RES_DEBUG, /* resolver(3) */ + OPT_RES_DEFNAMES, /* resolver(3) */ + OPT_RES_DNSRCH, /* resolver(3) */ + OPT_RES_IGNTC, /* resolver(3) */ + OPT_RES_PRIMARY, /* resolver(3) */ + OPT_RES_RECURSE, /* resolver(3) */ + OPT_RES_STAYOPEN, /* resolver(3) */ + OPT_RES_USEVC, /* resolver(3) */ + OPT_RETRY, + OPT_SANE, /* termios */ + OPT_SEEK32_CUR, + OPT_SEEK32_END, + OPT_SEEK32_SET, + OPT_SEEK64_CUR, + OPT_SEEK64_END, + OPT_SEEK64_SET, + OPT_SETGID, + OPT_SETGID_EARLY, + OPT_SETPGID, + OPT_SETSID, + OPT_SETUID, + OPT_SETUID_EARLY, + OPT_SIGHUP, + OPT_SIGINT, + OPT_SIGQUIT, +#ifdef SIOCSPGRP + OPT_SIOCSPGRP, +#endif +#ifdef SO_ACCEPTCONN + OPT_SO_ACCEPTCONN, +#endif /* SO_ACCEPTCONN */ +#ifdef SO_ATTACH_FILTER + OPT_SO_ATTACH_FILTER, +#endif +#ifdef SO_AUDIT /* AIX 4.3.3 */ + OPT_SO_AUDIT, +#endif /* SO_AUDIT */ +#ifdef SO_BINDTODEVICE + OPT_SO_BINDTODEVICE, +#endif + OPT_SO_BROADCAST, +#ifdef SO_BSDCOMPAT + OPT_SO_BSDCOMPAT, +#endif +#ifdef SO_CKSUMRECV + OPT_SO_CKSUMRECV, +#endif /* SO_CKSUMRECV */ + OPT_SO_DEBUG, +#ifdef SO_DETACH_FILTER + OPT_SO_DETACH_FILTER, +#endif +#ifdef SO_DGRAM_ERRIND + OPT_SO_DGRAM_ERRIND, +#endif +#ifdef SO_DONTLINGER + OPT_SO_DONTLINGER, +#endif + OPT_SO_DONTROUTE, + OPT_SO_ERROR, + OPT_SO_KEEPALIVE, +#ifdef SO_KERNACCEPT /* AIX 4.3.3 */ + OPT_SO_KERNACCEPT, +#endif /* SO_KERNACCEPT */ + OPT_SO_LINGER, +#ifdef SO_NO_CHECK + OPT_SO_NO_CHECK, +#endif +#ifdef SO_NOREUSEADDR /* AIX 4.3.3 */ + OPT_SO_NOREUSEADDR, +#endif /* SO_NOREUSEADDR */ + OPT_SO_OOBINLINE, +#ifdef SO_PASSCRED + OPT_SO_PASSCRED, +#endif +#ifdef SO_PEERCRED + OPT_SO_PEERCRED, +#endif +#ifdef SO_PRIORITY + OPT_SO_PRIORITY, +#endif +#ifdef SO_PROTOTYPE + OPT_SO_PROTOTYPE, +#endif + OPT_SO_RCVBUF, + OPT_SO_RCVBUF_LATE, +#ifdef SO_RCVLOWAT + OPT_SO_RCVLOWAT, +#endif +#ifdef SO_RCVTIMEO + OPT_SO_RCVTIMEO, +#endif + OPT_SO_REUSEADDR, +#ifdef SO_REUSEPORT + OPT_SO_REUSEPORT, +#endif /* defined(SO_REUSEPORT) */ +#ifdef SO_SECURITY_AUTHENTICATION + OPT_SO_SECURITY_AUTHENTICATION, +#endif +#ifdef SO_SECURITY_ENCRYPTION_NETWORK + OPT_SO_SECURITY_ENCRYPTION_NETWORK, +#endif +#ifdef SO_SECURITY_ENCRYPTION_TRANSPORT + OPT_SO_SECURITY_ENCRYPTION_TRANSPORT, +#endif + OPT_SO_SNDBUF, + OPT_SO_SNDBUF_LATE, +#ifdef SO_SNDLOWAT + OPT_SO_SNDLOWAT, +#endif +#ifdef SO_SNDTIMEO + OPT_SO_SNDTIMEO, +#endif + OPT_SO_TYPE, +#ifdef SO_USELOOPBACK + OPT_SO_USELOOPBACK, +#endif /* SO_USELOOPBACK */ +#ifdef SO_USE_IFBUFS + OPT_SO_USE_IFBUFS, +#endif /* SO_USE_IFBUFS */ +#if 1 || defined(WITH_SOCKS4) + OPT_SOCKSPORT, + OPT_SOCKSUSER, +#endif + OPT_SOURCEPORT, + OPT_STDERR, /* with exec, system */ + OPT_SUBSTUSER, + OPT_SUBSTUSER_DELAYED, + OPT_SYMBOLIC_LINK, /* with pty */ +#ifdef TABDLY +# ifdef TAB0 + OPT_TAB0, /* termios.c_oflag */ +# endif +# ifdef TAB1 + OPT_TAB1, /* termios.c_oflag */ +# endif +# ifdef TAB2 + OPT_TAB2, /* termios.c_oflag */ +# endif +# ifdef TAB3 + OPT_TAB3, /* termios.c_oflag */ +# endif + OPT_TABDLY, /* termios.c_oflag */ +#endif + OPT_TCPWRAPPERS, /* libwrap */ + OPT_TCPWRAP_ETC, /* libwrap */ + OPT_TCPWRAP_HOSTS_ALLOW_TABLE, /* libwrap */ + OPT_TCPWRAP_HOSTS_DENY_TABLE, /* libwrap */ + OPT_TCP_ABORT_THRESHOLD, /* HP-UX */ + OPT_TCP_CONN_ABORT_THRESHOLD, /* HP-UX */ +#ifdef TCP_CORK + OPT_TCP_CORK, +#endif +#ifdef TCP_DEFER_ACCEPT + OPT_TCP_DEFER_ACCEPT, /* Linux 2.4.0 */ +#endif +#ifdef TCP_INFO + OPT_TCP_INFO, /* Linux 2.4.0 */ +#endif +#ifdef TCP_KEEPCNT + OPT_TCP_KEEPCNT, /* Linux 2.4.0 */ +#endif +#ifdef TCP_KEEPIDLE + OPT_TCP_KEEPIDLE, /* Linux 2.4.0 */ +#endif + OPT_TCP_KEEPINIT, /* OSF1 */ +#ifdef TCP_KEEPINTVL + OPT_TCP_KEEPINTVL, /* Linux 2.4.0 */ +#endif +#ifdef TCP_LINGER2 + OPT_TCP_LINGER2, /* Linux 2.4.0 */ +#endif +#ifdef TCP_MAXSEG + OPT_TCP_MAXSEG, + OPT_TCP_MAXSEG_LATE, +#endif + OPT_TCP_MD5SIG, /* FreeBSD */ +#ifdef TCP_NODELAY + OPT_TCP_NODELAY, +#endif + OPT_TCP_NOOPT, /* FreeBSD */ + OPT_TCP_NOPUSH, /* FreeBSD */ + OPT_TCP_PAWS, /* OSF1 */ +#ifdef TCP_QUICKACK + OPT_TCP_QUICKACK, /* Linux 2.4 */ +#endif +#ifdef TCP_RFC1323 + OPT_TCP_RFC1323, /* AIX 4.3.3 */ +#endif + OPT_TCP_SACKENA, /* OSF1 */ + OPT_TCP_SACK_DISABLE, /* OpenBSD */ + OPT_TCP_SIGNATURE_ENABLE, /* OpenBSD */ +#ifdef TCP_STDURG + OPT_TCP_STDURG, /* AIX 4.3.3; Linux: see man 7 tcp */ +#endif +#ifdef TCP_SYNCNT + OPT_TCP_SYNCNT, /* Linux 2.4.0 */ +#endif + OPT_TCP_TSOPTENA, /* OSF1 */ +#ifdef TCP_WINDOW_CLAMP + OPT_TCP_WINDOW_CLAMP, /* Linux 2.4.0 */ +#endif + OPT_TIOCSCTTY, + OPT_TOSTOP, /* termios.c_lflag */ + OPT_TUN_DEVICE, /* tun: /dev/net/tun ... */ + OPT_TUN_NAME, /* tun: tun0 */ + OPT_TUN_TYPE, /* tun: tun|tap */ + OPT_UMASK, + OPT_UNIX_TIGHTSOCKLEN, /* UNIX domain sockets */ + OPT_UNLINK, + OPT_UNLINK_CLOSE, + OPT_UNLINK_EARLY, + OPT_UNLINK_LATE, + OPT_USER, + OPT_USER_EARLY, + OPT_USER_LATE, +#ifdef VDISCARD + OPT_VDISCARD, /* termios.c_cc */ +#endif + OPT_VDSUSP, /* termios.c_cc - HP-UX */ + OPT_VEOF, /* termios.c_cc */ + OPT_VEOL, /* termios.c_cc */ + OPT_VEOL2, /* termios.c_cc */ + OPT_VERASE, /* termios.c_cc */ + OPT_VINTR, /* termios.c_cc */ + OPT_VKILL, /* termios.c_cc */ + OPT_VLNEXT, /* termios.c_cc */ + OPT_VMIN, /* termios.c_cc */ + OPT_VQUIT, /* termios.c_cc */ + OPT_VREPRINT, /* termios.c_cc */ + OPT_VSTART, /* termios.c_cc */ + OPT_VSTOP, /* termios.c_cc */ + OPT_VSUSP, /* termios.c_cc */ + OPT_VSWTC, /* termios.c_cc */ + OPT_VTIME, /* termios.c_cc */ +#ifdef VTDLY +# ifdef VT0 + OPT_VT0, /* termios.c_oflag */ +# endif +# ifdef VT1 + OPT_VT1, /* termios.c_oflag */ +# endif + OPT_VTDLY, /* termios.c_oflag */ +#endif +#ifdef VWERASE + OPT_VWERASE, /* termios.c_cc */ +#endif + OPT_WAITLOCK, +#ifdef XCASE + OPT_XCASE, /* termios.c_lflag */ +#endif +#if defined(TABDLY) && defined(XTABS) + OPT_XTABS, /* termios.c_oflag */ +#endif + OPT_nocomma /* make aix xlc happy, no trailing comma */ +} ; + +/* keep consistent with xiohelp.c:optionphasenames ! */ +enum e_phase { + PH_ALL, /* not for options; use in apply funcs to say "all phases" */ + PH_INIT, /* retrieving info from original state */ + PH_EARLY, /* before any other processing */ + PH_PREOPEN, /* before file descriptor is created/opened */ + PH_OPEN, /* during filesystem entry creation/open */ + PH_PASTOPEN, /* past filesystem entry creation/open */ + PH_PRESOCKET, /* before socket call */ + PH_SOCKET, /* for socket call */ + PH_PASTSOCKET, /* after socket call */ + PH_PREBIGEN, /* before socketpair() pipe() openpty() */ + PH_BIGEN, /* during socketpair() pipe() openpty() */ + PH_PASTBIGEN, /* past socketpair() pipe() openpty() */ + PH_FD, /* soon after FD creation or identification */ + PH_PREBIND, /* before socket bind() */ + PH_BIND, /* during socket bind() ? */ + PH_PASTBIND, /* past socket bind() - for client and server sockets! */ + PH_PRELISTEN, /* before socket listen() */ + PH_LISTEN, /* during socket listen() ? */ + PH_PASTLISTEN, /* after socket listen() */ + PH_PRECONNECT, /* before socket connect() */ + PH_CONNECT, /* during socket connect() ? */ + PH_PASTCONNECT, /* after socket connect() */ + PH_PREACCEPT, /* before socket accept() */ + PH_ACCEPT, /* during socket accept() ? */ + PH_PASTACCEPT, /* after socket accept() */ + PH_CONNECTED, /* for sockets, after connect() or accept() */ + PH_PREFORK, /* before fork() (with both listen and exec!) */ + PH_FORK, /* during fork() (with both listen and exec!) */ + PH_PASTFORK, /* after fork() (with both listen and exec!) */ + PH_LATE, /* FD is ready, before start of data loop */ + PH_LATE2, /* FD is ready, dropping privileges */ + PH_PREEXEC, /* before exec() or system() */ + PH_EXEC, /* during exec() or system() */ + PH_SPEC /* specific to situation, not fix */ +} ; + +/* atomic structure to describe the syntax and more important semantics of an + option */ +struct optdesc { + const char *defname; /* default name */ + const char *nickname; /* usual name */ + enum e_optcode optcode; /* short form of option name */ + unsigned int group; + enum e_phase phase; /* when this option is to be used */ + enum e_types type; /* the data type as expected on input, and stored */ + enum e_func func; /* which function can apply this option, e.g. ioctl(), + getsockopt(), or just a bit pattern */ + int major; /* major id for func: level (SOL_...) for setsockopt(), + request for ioctl() */ + int minor; /* minor id for func: SO_..., IP_..., */ + long arg3; +} ; + +extern bool xioopts_ignoregroups; +extern const struct optname optionnames[]; + + +extern int retropt_bool(struct opt *opts, int optcode, bool *result); +extern int retropt_short(struct opt *opts, int optcode, short *result); +extern int retropt_ushort(struct opt *opts, int optcode, unsigned short *result); +extern int retropt_int(struct opt *opts, int optcode, int *result); +extern int retropt_uint(struct opt *opts, int optcode, unsigned int *result); +extern int retropt_long(struct opt *opts, int optcode, long *result); +extern int retropt_ulong(struct opt *opts, int optcode, unsigned long *result); +extern int retropt_flag(struct opt *opts, int optcode, flags_t *result); +extern int retropt_string(struct opt *opts, int optcode, char **result); +extern int retropt_timespec(struct opt *opts, int optcode, struct timespec *result); +extern int retropt_bind(struct opt *opts, + int af, + int socktype, + int ipproto, + struct sockaddr *sa, + socklen_t *salen, + int feats, /* TCP etc: 1..address allowed, + 3..address and port allowed */ + unsigned long res_opts0, unsigned long res_opts1); +extern int applyopts(int fd, struct opt *opts, unsigned int phase); +extern int applyopts2(int fd, struct opt *opts, unsigned int from, + unsigned int to); +extern int applyopts_flags(struct opt *opts, int group, flags_t *result); +extern int applyopts_cloexec(int fd, struct opt *opts); +extern int applyopts_early(const char *path, struct opt *opts); +extern int applyopts_fchown(int fd, struct opt *opts); +extern int applyopts_single(struct single *fd, struct opt *opts, enum e_phase phase); +extern int applyopts_offset(struct single *xfd, struct opt *opts); +extern int applyopts_signal(struct single *xfd, struct opt *opts); +extern int _xio_openlate(struct single *fd, struct opt *opts); +extern int parseopts(const char **a, unsigned int groups, struct opt **opts); +extern int parseopts_table(const char **a, unsigned int groups, + struct opt **opts, + const struct optname optionnames[], size_t optionnum); +extern struct opt *copyopts(const struct opt *opts, unsigned int groups); +extern struct opt *moveopts(struct opt *opts, unsigned int groups); +extern int leftopts(const struct opt *opts); +extern int showleft(const struct opt *opts); +extern int groupbits(int fd); +extern int _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); + +#endif /* !defined(__xioopts_h_included) */ diff --git a/xioparam.c b/xioparam.c new file mode 100644 index 0000000..4cbd11d --- /dev/null +++ b/xioparam.c @@ -0,0 +1,67 @@ +/* $Id: xioparam.c,v 1.10 2006/06/19 20:30:24 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for xio options handling */ + +#include "xiosysincludes.h" +#include "xioopen.h" + +/*#include "xioparam.h" are all in xio.h */ + +/* options that can be applied to this module */ +xioopts_t xioopts = { + false, /* strictopts */ + "!!", /* pipesep */ + ":", /* paramsep */ + ",", /* optionsep */ + ':', /* ip4portsep */ + ':', /* ip6portsep */ + '\0', /* logopt */ + NULL, /* syslogfac */ + '4', /* default_ip */ + '4' /* preferred_ip */ +} ; + + +/* allow application to set xioopen options */ +int xiosetopt(char what, const char *arg) { + switch (what) { + case 's': xioopts.strictopts = true; break; + case 'p': if ((xioopts.pipesep = strdup(arg)) == NULL) { + Error1("strdup("F_Zu"): out of memory", strlen(arg)+1); + return -1; + } + break; + case 'o': xioopts.ip4portsep = arg[0]; + if (arg[1] != '\0') { + Error2("xiosetopt('%c', \"%s\"): port separator must be single character", + what, arg); + return -1; + } + break; + case 'l': xioopts.logopt = *arg; break; + case 'y': xioopts.syslogfac = arg; break; + default: + Error2("xiosetopt('%c', \"%s\"): unknown option", + what, arg?arg:"NULL"); + return -1; + } + return 0; +} + + +int xioinqopt(char what, char *arg, size_t n) { + switch (what) { + case 's': return xioopts.strictopts; + case 'p': strncpy(arg, xioopts.pipesep, n); + return 0; + case 'o': return xioopts.ip4portsep; + case 'l': return xioopts.logopt; + default: + Error3("xioinqopt('%c', \"%s\", "F_Zu"): unknown option", + what, arg, n); + return -1; + } + return 0; +} diff --git a/xioread.c b/xioread.c new file mode 100644 index 0000000..9d8b94d --- /dev/null +++ b/xioread.c @@ -0,0 +1,401 @@ +/* $Id: xioread.c,v 1.38 2007/03/06 21:20:07 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this is the source of the extended read function */ + +#include "xiosysincludes.h" +#include "xioopen.h" + +#include "xio-termios.h" +#include "xio-socket.h" +#include "xio-readline.h" +#include "xio-openssl.h" + + +/* xioread() performs read() or recvfrom() + If result is < 0, errno is valid */ +ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) { + ssize_t bytes; +#if WITH_IP6 && 0 + int nexthead; +#endif + struct single *pipe; + int _errno; + + if (file->tag == XIO_TAG_INVALID) { + Error1("xioread(): invalid xiofile descriptor %p", file); + errno = EINVAL; + return -1; + } + + if (file->tag == XIO_TAG_DUAL) { + pipe = file->dual.stream[0]; + if (pipe->tag == XIO_TAG_INVALID) { + Error1("xioread(): invalid xiofile sub descriptor %p[0]", file); + errno = EINVAL; + return -1; + } + } else { + pipe = &file->stream; + } + + if (pipe->readbytes) { + if (pipe->actbytes == 0) { + return 0; /* EOF by count */ + } + + if (pipe->actbytes < bufsiz) { + bufsiz = pipe->actbytes; + } + } + + switch (pipe->dtype & XIODATA_READMASK) { + case XIOREAD_STREAM: + do { + bytes = Read(pipe->fd, buff, bufsiz); + } while (bytes < 0 && errno == EINTR); + if (bytes < 0) { + _errno = errno; + switch (_errno) { +#if 1 + case EPIPE: case ECONNRESET: + Warn4("read(%d, %p, "F_Zu"): %s", + pipe->fd, buff, bufsiz, strerror(_errno)); + break; +#endif + default: + Error4("read(%d, %p, "F_Zu"): %s", + pipe->fd, buff, bufsiz, strerror(_errno)); + } + errno = _errno; + return -1; + } + break; + + case XIOREAD_PTY: + do { + bytes = Read(pipe->fd, buff, bufsiz); + } while (bytes < 0 && errno == EINTR); + if (bytes < 0) { + _errno = errno; + if (_errno == EIO) { + Notice4("read(%d, %p, "F_Zu"): %s (probably PTY closed)", + pipe->fd, buff, bufsiz, strerror(_errno)); + return 0; + } else { + Error4("read(%d, %p, "F_Zu"): %s", + pipe->fd, buff, bufsiz, strerror(_errno)); + } + errno = _errno; + return -1; + } + break; + +#if WITH_READLINE + case XIOREAD_READLINE: + if ((bytes = xioread_readline(pipe, buff, bufsiz)) < 0) { + return -1; + } + break; +#endif /* WITH_READLINE */ + +#if WITH_OPENSSL + case XIOREAD_OPENSSL: + /* this function prints its error messages */ + if ((bytes = xioread_openssl(pipe, buff, bufsiz)) < 0) { + return -1; + } + break; +#endif /* WITH_OPENSSL */ + +#if WITH_SOCKET + case XIOREAD_RECV: + if (pipe->dtype & XIOREAD_RECV_FROM) { +#if WITH_RAWIP || WITH_UDP || WITH_UNIX + union sockaddr_union from = {{0}}; + socklen_t fromlen = sizeof(from); + char infobuff[256]; + + do { + bytes = + Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen); + } while (bytes < 0 && errno == EINTR); + if (bytes < 0) { + char infobuff[256]; + _errno = errno; + Error6("recvfrom(%d, %p, "F_Zu", 0, %s, {"F_socklen"}): %s", + pipe->fd, buff, bufsiz, + sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)), + fromlen, strerror(errno)); + errno = _errno; + return -1; + } + Notice2("received packet with "F_Zu" bytes from %s", + bytes, + sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff))); + if (bytes == 0) { + if (!pipe->para.socket.emptyiseof) { + errno = EAGAIN; return -1; + } + return bytes; + } + + if (pipe->peersa.soa.sa_family != PF_UNSPEC) { + /* a peer address is defined, so we need to check if it matches */ +#if 0 /* with UNIX sockets we find inconsistent lengths */ + if (fromlen != pipe->salen) { + Info("recvfrom(): wrong peer address length, ignoring packet"); + errno = EAGAIN; return -1; + } +#endif + if (pipe->dtype & XIOREAD_RECV_SKIPIP) { + if (pipe->peersa.soa.sa_family != from.soa.sa_family) { + Info("recvfrom(): wrong peer protocol, ignoring packet"); + errno = EAGAIN; return -1; + } +#if WITH_IP4 + switch (pipe->peersa.soa.sa_family) { + case PF_INET: + if (pipe->peersa.ip4.sin_addr.s_addr != + from.ip4.sin_addr.s_addr) { + Info("recvfrom(): wrong peer address, ignoring packet"); + errno = EAGAIN; return -1; + } + break; + } +#endif /* WITH_IP4 */ + } else { + switch (pipe->peersa.soa.sa_family) { +#if 0 + case PF_UNIX: + if (strncmp(pipe->peersa.un.sun_path, from.un.sun_path, + sizeof(from.un.sun_path))) { + Info("recvfrom(): wrong peer address, ignoring packet"); + errno = EAGAIN; return -1; + } + break; +#endif +#if WITH_IP6 + case PF_INET6: + /* e.g. Solaris recvfrom sets a __sin6_src_id component */ + if (memcmp(&from.ip6.sin6_addr, &pipe->peersa.ip6.sin6_addr, + sizeof(from.ip6.sin6_addr)) || + from.ip6.sin6_port != pipe->peersa.ip6.sin6_port) { + Info("recvfrom(): wrong peer address, ignoring packet"); + errno = EAGAIN; return -1; + } + break; +#endif /* WITH_IP6 */ + default: + if (memcmp(&from, &pipe->peersa, fromlen)) { + Info("recvfrom(): wrong peer address, ignoring packet"); + errno = EAGAIN; return -1; + } + } + } + } + + switch(from.soa.sa_family) { + int headlen; +#if WITH_IP4 + case AF_INET: + if (pipe->dtype & XIOREAD_RECV_SKIPIP) { + /* IP4 raw sockets include the header when passing a packet to the + application - we don't need it here. */ +#if HAVE_STRUCT_IP_IP_HL + headlen = 4*((struct ip *)buff)->ip_hl; +#else /* happened on Tru64 */ + headlen = 4*((struct ip *)buff)->ip_vhl; +#endif + if (headlen > bytes) { + Warn1("xioread(%d, ...)/IP4: short packet", pipe->fd); + bytes = 0; + } else { + memmove(buff, ((char *)buff)+headlen, bytes-headlen); + bytes -= headlen; + } + } + break; +#endif +#if WITH_IP6 + case AF_INET6: + /* does not seem to include header on Linux */ + /* but sometimes on AIX */ + break; +#endif + default: + /* do nothing, for now */ + break; + } + if (pipe->dtype & XIOREAD_RECV_ONESHOT) { +#if 1 + pipe->eof = 2; +#else + Shutdown(pipe->fd, SHUT_RD); +#endif + if (pipe->ppid > 0) { + Kill(pipe->ppid, SIGUSR1); + } + } + +#if 0 + if (fromlen != pipe->fd[0].salen) { + Debug("recvfrom(): wrong peer address length, ignoring packet"); + continue; + } + if (memcmp(&from, &pipe->fd[0].peersa.sa, fromlen)) { + Debug("recvfrom(): other peer address, ignoring packet"); + Debug16("peer: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + pipe->fd[0].peersa.space[0], + pipe->fd[0].peersa.space[1], + pipe->fd[0].peersa.space[2], + pipe->fd[0].peersa.space[3], + pipe->fd[0].peersa.space[4], + pipe->fd[0].peersa.space[5], + pipe->fd[0].peersa.space[6], + pipe->fd[0].peersa.space[7], + pipe->fd[0].peersa.space[8], + pipe->fd[0].peersa.space[9], + pipe->fd[0].peersa.space[10], + pipe->fd[0].peersa.space[11], + pipe->fd[0].peersa.space[12], + pipe->fd[0].peersa.space[13], + pipe->fd[0].peersa.space[14], + pipe->fd[0].peersa.space[15]); + Debug16("from: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + from.space[0], from.space[1], + from.space[2], from.space[3], + from.space[4], from.space[5], + from.space[6], from.space[7], + from.space[8], from.space[9], + from.space[10], from.space[11], + from.space[12], from.space[13], + from.space[14], from.space[15]); + continue; + } +#endif +#else /* !WITH_RAWIP */ + Fatal("address requires raw sockets, but they are not compiled in"); + return -1; +#endif /* !WITH_RAWIP || WITH_UDP || WITH_UNIX */ + + } else /* ~XIOREAD_RECV_FROM */ { + union sockaddr_union from; socklen_t fromlen = sizeof(from); + char infobuff[256]; + + socket_init(pipe->para.socket.la.soa.sa_family, &from); + /* get source address */ + if (xiogetpacketsrc(pipe->fd, &from, &fromlen) < 0) { + return STAT_RETRYNOW; + } + if (xiocheckpeer(pipe, &from, &pipe->para.socket.la) < 0) { + Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen); /* drop */ + errno = EAGAIN; return -1; + } + Info1("permitting packet from %s", + sockaddr_info((struct sockaddr *)&from, fromlen, + infobuff, sizeof(infobuff))); + + do { + bytes = + Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen); + } while (bytes < 0 && errno == EINTR); + if (bytes < 0) { + char infobuff[256]; + _errno = errno; + Error6("recvfrom(%d, %p, "F_Zu", 0, %s, "F_socklen"): %s", + pipe->fd, buff, bufsiz, + sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)), + fromlen, strerror(errno)); + errno = _errno; + return -1; + } + Notice2("received packet with "F_Zu" bytes from %s", + bytes, + sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff))); + if (bytes == 0) { + if (!pipe->para.socket.emptyiseof) { + errno = EAGAIN; return -1; + } + return bytes; + } + + switch(from.soa.sa_family) { + int headlen; +#if WITH_IP4 + case AF_INET: + if (pipe->dtype & XIOREAD_RECV_SKIPIP) { + /* IP4 raw sockets include the header when passing a packet to the + application - we don't need it here. */ +#if HAVE_STRUCT_IP_IP_HL + headlen = 4*((struct ip *)buff)->ip_hl; +#else /* happened on Tru64 */ + headlen = 4*((struct ip *)buff)->ip_vhl; +#endif + if (headlen > bytes) { + Warn1("xioread(%d, ...)/IP4: short packet", pipe->fd); + bytes = 0; + } else { + memmove(buff, ((char *)buff)+headlen, bytes-headlen); + bytes -= headlen; + } + } + break; +#endif +#if WITH_IP6 + case AF_INET6: /* does not seem to include header... */ + break; +#endif + default: + /* do nothing, for now */ + break; + } + + } + break; +#endif /* WITH_SOCKET */ + + default: + Error("internal: undefined read operation"); + errno = EINVAL; return -1; + } + pipe->actbytes -= bytes; + return bytes; +} + + +/* this function is intended only for some special address types where the + select() call cannot strictly determine if (more) read data is available. + currently this is for the OpenSSL based addresses. +*/ +ssize_t xiopending(xiofile_t *file) { + struct single *pipe; + + if (file->tag == XIO_TAG_INVALID) { + Error1("xiopending(): invalid xiofile descriptor %p", file); + errno = EINVAL; + return -1; + } + + if (file->tag == XIO_TAG_DUAL) { + pipe = file->dual.stream[0]; + if (pipe->tag == XIO_TAG_INVALID) { + Error1("xiopending(): invalid xiofile sub descriptor %p[0]", file); + errno = EINVAL; + return -1; + } + } else { + pipe = &file->stream; + } + + switch (pipe->dtype & XIODATA_READMASK) { +#if WITH_OPENSSL + case XIOREAD_OPENSSL: + return xiopending_openssl(pipe); +#endif /* WITH_OPENSSL */ + default: + return 0; + } +} + diff --git a/xioshutdown.c b/xioshutdown.c new file mode 100644 index 0000000..8e2ddb9 --- /dev/null +++ b/xioshutdown.c @@ -0,0 +1,134 @@ +/* $Id: xioshutdown.c,v 1.21 2007/01/25 21:36:11 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this is the source of the extended shutdown function */ + + +#include "xiosysincludes.h" +#include "xioopen.h" + +static pid_t socat_kill_pid; /* here we pass the pid to be killed in sighandler */ + +static void signal_kill_pid(int dummy) { + Notice("SIGALRM while waiting for w/o child process to die, killing it now"); + Kill(socat_kill_pid, SIGTERM); +} + +int xioshutdown(xiofile_t *sock, int how) { + int result = 0; + + if (sock->tag == XIO_TAG_INVALID) { + Error("xioshutdown(): invalid file descriptor"); + errno = EINVAL; + return -1; + } + + if (sock->tag == XIO_TAG_DUAL) { + if ((how+1)&1) { + result = xioshutdown((xiofile_t *)sock->dual.stream[0], 0); + } + if ((how+1)&2) { + result |= xioshutdown((xiofile_t *)sock->dual.stream[1], 1); + } + +#if WITH_OPENSSL + } else if ((sock->stream.dtype & XIODATA_MASK) == XIODATA_OPENSSL) { + sycSSL_shutdown (sock->stream.para.openssl.ssl); + /*! what about half/full close? */ +#endif /* WITH_OPENSSL */ + + } else if ((sock->stream.dtype & XIODATA_MASK) == XIODATA_PIPE) { + if ((how+1)&1) { + if (Close(sock->stream.fd) < 0) { + Info2("close(%d): %s", + sock->stream.fd, strerror(errno)); + } + } + if ((how+1)&2) { + if (Close(sock->stream.para.bipipe.fdout) < 0) { + Info2("close(%d): %s", + sock->stream.para.bipipe.fdout, strerror(errno)); + } + } + + } else if ((sock->stream.dtype & XIODATA_MASK) == XIODATA_2PIPE) { + if ((how+1)&1) { + if (Close(sock->stream.fd) < 0) { + Info2("close(%d): %s", + sock->stream.fd, strerror(errno)); + } + } + if ((how+1)&2) { + if (Close(sock->stream.para.exec.fdout) < 0) { + Info2("close(%d): %s", + sock->stream.para.exec.fdout, strerror(errno)); + } + } +#if WITH_SOCKET + } else if (sock->stream.howtoend == END_SHUTDOWN) { + if ((result = Shutdown(sock->stream.fd, how)) < 0) { + Info3("shutdown(%d, %d): %s", + sock->stream.fd, how, strerror(errno)); + } + } else if (sock->stream.howtoend == END_SHUTDOWN_KILL) { + if ((result = Shutdown(sock->stream.fd, how)) < 0) { + Info3("shutdown(%d, %d): %s", + sock->stream.fd, how, strerror(errno)); + } + if ((sock->stream.flags&XIO_ACCMODE) == XIO_WRONLY) { + /* the child process might want to flush some data before terminating + */ + int status = 0; + + /* we wait for the child process to die, but to prevent timeout + we raise an alarm after some time. + NOTE: the alarm does not terminate waitpid() on Linux/glibc (BUG?), + therefore we have to do the kill in the signal handler */ + Signal(SIGALRM, signal_kill_pid); + socat_kill_pid = sock->stream.para.exec.pid; +#if HAVE_SETITIMER + /*! with next feature release, we get usec resolution and an option */ +#else + Alarm(1 /*! sock->stream.para.exec.waitdie */); +#endif /* !HAVE_SETITIMER */ + if (Waitpid(sock->stream.para.exec.pid, &status, 0) < 0) { + Warn3("waitpid("F_pid", %p, 0): %s", + sock->stream.para.exec.pid, &status, strerror(errno)); + } + Alarm(0); + } + } else if ((sock->stream.dtype & XIODATA_MASK) == XIODATA_RECVFROM) { + if (how >= 1) { + if (Close(sock->stream.fd) < 0) { + Info2("close(%d): %s", + sock->stream.fd, strerror(errno)); + } + sock->stream.eof = 2; + sock->stream.fd = -1; + } +#endif /* WITH_SOCKET */ +#if 0 + } else { + Error1("xioshutdown(): bad data type specification %d", sock->stream.dtype); + return -1; +#endif + + } +#if 0 + else if (sock->stream.howtoend == END_CLOSE && + sock->stream.dtype == DATA_STREAM) { + return result; + } +#if WITH_TERMIOS + if (sock->stream.ttyvalid) { + if (Tcsetattr(sock->stream.fd, 0, &sock->stream.savetty) < 0) { + Warn2("cannot restore terminal settings on fd %d: %s", + sock->stream.fd, strerror(errno)); + } + } +#endif /* WITH_TERMIOS */ +#endif + + return result; +} diff --git a/xiosigchld.c b/xiosigchld.c new file mode 100644 index 0000000..39c03f9 --- /dev/null +++ b/xiosigchld.c @@ -0,0 +1,159 @@ +/* $Id: xiosigchld.c,v 1.21 2006/12/28 14:38:38 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2006 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this is the source of the extended child signal handler */ + + +#include "xiosysincludes.h" +#include "xioopen.h" + + +/*!! with socat, at most 4 exec children exist */ +pid_t diedunknown1; /* child died before it is registered */ +pid_t diedunknown2; +pid_t diedunknown3; +pid_t diedunknown4; + + +/* register for a xio filedescriptor a callback (handler). + when a SIGCHLD occurs, the signal handler will ??? */ +int xiosetsigchild(xiofile_t *xfd, int (*callback)(struct single *)) { + if (xfd->tag != XIO_TAG_DUAL) { + xfd->stream.sigchild = callback; + } else { + xfd->dual.stream[0]->sigchild = callback; + xfd->dual.stream[1]->sigchild = callback; + } + return 0; +} + +/* exec'd child has died, perform appropriate changes to descriptor */ +static int sigchld_stream(struct single *file) { + /*!! call back to application */ + file->para.exec.pid = 0; + if (file->sigchild) { + return (*file->sigchild)(file); + } + return 0; +} + +/* return 0 if socket is not responsible for deadchild */ +static int xio_checkchild(xiofile_t *socket, int socknum, pid_t deadchild) { + int retval; + if (socket != NULL) { + if (socket->tag != XIO_TAG_DUAL) { + if ((socket->stream.howtoend == END_KILL || + socket->stream.howtoend == END_CLOSE_KILL || + socket->stream.howtoend == END_SHUTDOWN_KILL) && + socket->stream.para.exec.pid == deadchild) { + Info2("exec'd process %d on socket %d terminated", + socket->stream.para.exec.pid, socknum); + sigchld_stream(&socket->stream); + return 1; + } + } else { + if (retval = xio_checkchild((xiofile_t *)socket->dual.stream[0], socknum, deadchild)) + return retval; + else + return xio_checkchild((xiofile_t *)socket->dual.stream[1], socknum, deadchild); + } + } + return 0; +} + +/* this is the "physical" signal handler for SIGCHLD */ +/* the current socat/xio implementation knows two kinds of children: + exec/system addresses perform a fork: these children are registered and + there death influences the parents flow; + listen-socket with fork children: these children are "anonymous" and their + death does not affect the parent process (now; maybe we have a child + process counter later) */ +void childdied(int signum) { + pid_t pid; + int _errno; + int status = 0; + bool wassig = false; + int i; + + _errno = errno; /* save current value; e.g., select() on Cygwin seems + to set it to EINTR _before_ handling the signal, and + then passes the value left by the signal handler to + the caller of select(), accept() etc. */ + /* is not thread/signal save, but confused messages in rare cases are better + than no messages at all */ + Info1("childdied(signum=%d)", signum); + do { + pid = Waitpid(-1, &status, WNOHANG); + if (pid == 0) { + Msg(wassig?E_INFO:E_WARN, + "waitpid(-1, {}, WNOHANG): no child has exited"); + Info("childdied() finished"); + errno = _errno; + return; + } else if (pid < 0 && errno == ECHILD) { + Msg1(wassig?E_INFO:E_WARN, + "waitpid(-1, {}, WNOHANG): %s", strerror(errno)); + Info("childdied() finished"); + errno = _errno; + return; + } + wassig = true; + if (pid < 0) { + Warn2("waitpid(-1, {%d}, WNOHANG): %s", status, strerror(errno)); + Info("childdied() finished"); + errno = _errno; + return; + } + /*! indent */ + /* check if it was a registered child process */ + i = 0; + while (i < XIO_MAXSOCK) { + if (xio_checkchild(sock[i], i, pid)) break; + ++i; + } + if (i == XIO_MAXSOCK) { + Info2("childdied(%d): cannot identify child %d", signum, pid); + if (diedunknown1 == 0) { + diedunknown1 = pid; + Debug("saving pid in diedunknown1"); + } else if (diedunknown2 == 0) { + diedunknown2 = pid; + Debug("saving pid in diedunknown2"); + } else if (diedunknown3 == 0) { + diedunknown3 = pid; + Debug("saving pid in diedunknown3"); + } else { + diedunknown4 = pid; + Debug("saving pid in diedunknown4"); + } + } + + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) == 0) { + Info2("waitpid(): child %d exited with status %d", + pid, WEXITSTATUS(status)); + } else { + Warn2("waitpid(): child %d exited with status %d", + pid, WEXITSTATUS(status)); + } + } else if (WIFSIGNALED(status)) { + Info2("waitpid(): child %d exited on signal %d", + pid, WTERMSIG(status)); + } else if (WIFSTOPPED(status)) { + Info2("waitpid(): child %d stopped on signal %d", + pid, WSTOPSIG(status)); + } else { + Warn1("waitpid(): cannot determine status of child %d", pid); + } + +#if !HAVE_SIGACTION + /* we might need to re-register our handler */ + if (Signal(SIGCHLD, childdied) == SIG_ERR) { + Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno)); + } +#endif /* !HAVE_SIGACTION */ + } while (1); + Info("childdied() finished"); + errno = _errno; +} diff --git a/xiosignal.c b/xiosignal.c new file mode 100644 index 0000000..405ff98 --- /dev/null +++ b/xiosignal.c @@ -0,0 +1,107 @@ +/* $Id: xiosignal.c,v 1.2 2003/12/23 21:22:38 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2003 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains code for handling signals (except SIGCHLD) */ + +#include "config.h" +#include "xioconfig.h" /* what features are enabled */ + +#include "sysincludes.h" + +#include "mytypes.h" +#include "compat.h" +#include "error.h" + +#include "sycls.h" + + +#define SOCAT_MAXPIDS 4 + +struct socat_sig_desc { + int sig_use; + pid_t sig_pids[SOCAT_MAXPIDS]; +} ; + +#if 0 +size_t socat_sigint_use; /* how many pids are set in following array */ +static pid_t socat_sigint_pids[SOCAT_MAXPIDS]; +size_t socat_sigquit_use; /* how many pids are set in following array */ +static pid_t socat_sigquit_pids[SOCAT_MAXPIDS]; +#else +static struct socat_sig_desc socat_sighup; +static struct socat_sig_desc socat_sigint; +static struct socat_sig_desc socat_sigquit; +#endif + + +static struct socat_sig_desc *socat_get_sig_desc(int signum) { + struct socat_sig_desc *sigdesc; + switch (signum) { + case SIGHUP: sigdesc = &socat_sighup; break; + case SIGINT: sigdesc = &socat_sigint; break; + case SIGQUIT: sigdesc = &socat_sigquit; break; + default: sigdesc = NULL; break; + } + return sigdesc; +} + +/* a signal handler that eventually passes the signal to sub processes */ +void socatsignalpass(int sig) { + int i; + struct socat_sig_desc *sigdesc; + + Debug1("socatsignalpass(%d)", sig); + if ((sigdesc = socat_get_sig_desc(sig)) == NULL) { + return; + } + + for (i=0; isig_use; ++i) { + if (sigdesc->sig_pids[i]) { + if (Kill(sigdesc->sig_pids[i], sig) < 0) { + Warn3("kill("F_pid", %d): %s", + sigdesc->sig_pids[i], sig, strerror(errno)); + } + } + } +#if !HAVE_SIGACTION + Signal(sig, socatsignalpass); +#endif /* !HAVE_SIGACTION */ + Debug("socatsignalpass() ->"); +} + + +/* register the sub process pid for passing of signals of type signum. + Only for SIGHUP, SIGINT, and SIGQUIT! + returns 0 on success or <0 if an error occurred */ +int xio_opt_signal(pid_t pid, int signum) { + struct socat_sig_desc *sigdesc; + + if ((sigdesc = socat_get_sig_desc(signum)) == NULL) { + Error("sub process registered for unsupported signal"); + return -1; + } + + if (sigdesc->sig_use >= SOCAT_MAXPIDS) { + Error1("too many sub processes registered for signal %d", signum); + return -1; + } + if (sigdesc->sig_use == 0) { + /* the special signal handler has not been registered yet - do it now */ +#if HAVE_SIGACTION + struct sigaction act; + memset(&act, 0, sizeof(struct sigaction)); + act.sa_flags = SA_RESTART; + act.sa_handler = socatsignalpass; + if (Sigaction(signum, &act, NULL) < 0) { + /*! man does not say that errno is defined */ + Warn3("sigaction(%d, %p, NULL): %s", signum, &act, strerror(errno)); + } +#else + Signal(signum, socatsignalpass); +#endif /* !HAVE_SIGACTION */ + } + sigdesc->sig_pids[sigdesc->sig_use++] = pid; + return 0; +} + diff --git a/xiosysincludes.h b/xiosysincludes.h new file mode 100644 index 0000000..e30ef13 --- /dev/null +++ b/xiosysincludes.h @@ -0,0 +1,13 @@ +/* $Id: xiosysincludes.h,v 1.4 2001/12/27 16:52:34 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xiosysincludes_h_included +#define __xiosysincludes_h_included 1 + +#include "config.h" +#include "xioconfig.h" /* what features are enabled */ + +#include "sysincludes.h" + +#endif /* !defined(__xiosysincludes_h_included) */ diff --git a/xiowrite.c b/xiowrite.c new file mode 100644 index 0000000..d5e0cce --- /dev/null +++ b/xiowrite.c @@ -0,0 +1,168 @@ +/* $Id: xiowrite.c,v 1.29 2007/02/08 18:27:00 gerhard Exp $ */ +/* Copyright Gerhard Rieger 2001-2007 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this is the source of the extended write function */ + + +#include "xiosysincludes.h" +#include "xioopen.h" + +#include "xio-readline.h" +#include "xio-openssl.h" + + +/* ... + note that the write() call can block even if the select() call reported the + FD writeable: in case the FD is not nonblocking and a lock defers the + operation. + on return value < 0: errno reflects the value from write() */ +ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) { + ssize_t writt; + struct single *pipe; + int _errno; + + if (file->tag == XIO_TAG_INVALID) { + Error1("xiowrite(): invalid xiofile descriptor %p", file); + errno = EINVAL; + return -1; + } + + if (file->tag == XIO_TAG_DUAL) { + pipe = file->dual.stream[1]; + if (pipe->tag == XIO_TAG_INVALID) { + Error1("xiowrite(): invalid xiofile sub descriptor %p[1]", file); + errno = EINVAL; + return -1; + } + } else { + pipe = &file->stream; + } + +#if WITH_READLINE + /* try to extract a prompt from the write data */ + if ((pipe->dtype & XIODATA_READMASK) == XIOREAD_READLINE) { + xioscan_readline(pipe, buff, bytes); + } +#endif /* WITH_READLINE */ + + switch (pipe->dtype & XIODATA_WRITEMASK) { + + case XIOWRITE_STREAM: + do { + writt = Write(pipe->fd, buff, bytes); + } while (writt < 0 && errno == EINTR); + if (writt < 0) { + _errno = errno; + switch (_errno) { + case EPIPE: + case ECONNRESET: + if (pipe->cool_write) { + Notice4("write(%d, %p, "F_Zu"): %s", + pipe->fd, buff, bytes, strerror(_errno)); + break; + } + /*PASSTRHOUGH*/ + default: + Error4("write(%d, %p, "F_Zu"): %s", + pipe->fd, buff, bytes, strerror(_errno)); + } + errno = _errno; + return -1; + } + if ((size_t)writt < bytes) { + Warn2("write() only wrote "F_Zu" of "F_Zu" bytes", + writt, bytes); + } + break; + +#if WITH_SOCKET + case XIOWRITE_SENDTO: + /*union { + char space[sizeof(struct sockaddr_un)]; + struct sockaddr sa; + } from;*/ + /*socklen_t fromlen;*/ + + do { + writt = Sendto(pipe->fd, buff, bytes, 0, + &pipe->peersa.soa, pipe->salen); + } while (writt < 0 && errno == EINTR); + if (writt < 0) { + char infobuff[256]; + _errno = errno; + Error6("sendto(%d, %p, "F_Zu", 0, %s, "F_socklen"): %s", + pipe->fd, buff, bytes, + sockaddr_info(&pipe->peersa.soa, pipe->salen, + infobuff, sizeof(infobuff)), + pipe->salen, strerror(_errno)); + errno = _errno; + return -1; + } + if ((size_t)writt < bytes) { + char infobuff[256]; + Warn7("sendto(%d, %p, "F_Zu", 0, %s, "F_socklen") only wrote "F_Zu" of "F_Zu" bytes", + pipe->fd, buff, bytes, + sockaddr_info(&pipe->peersa.soa, pipe->salen, + infobuff, sizeof(infobuff)), + pipe->salen, writt, bytes); + } else { + } + { + char infobuff[256]; + union sockaddr_union us; + socklen_t uslen = sizeof(us); + Getsockname(pipe->fd, &us.soa, &uslen); + Notice1("local address: %s", + sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff))); + } + break; +#endif /* WITH_SOCKET */ + + case XIOWRITE_PIPE: + do { + writt = Write(pipe->para.bipipe.fdout, buff, bytes); + } while (writt < 0 && errno == EINTR); + _errno = errno; + if (writt < 0) { + Error4("write(%d, %p, "F_Zu"): %s", + pipe->para.bipipe.fdout, buff, bytes, strerror(_errno)); + errno = _errno; + return -1; + } + if ((size_t)writt < bytes) { + Warn2("write() only wrote "F_Zu" of "F_Zu" bytes", + writt, bytes); + } + break; + + case XIOWRITE_2PIPE: + do { + writt = Write(pipe->para.exec.fdout, buff, bytes); + } while (writt < 0 && errno == EINTR); + _errno = errno; + if (writt < 0) { + Error4("write(%d, %p, "F_Zu"): %s", + pipe->para.exec.fdout, buff, bytes, strerror(_errno)); + errno = _errno; + return -1; + } + if ((size_t)writt < bytes) { + Warn2("write() only processed "F_Zu" of "F_Zu" bytes", + writt, bytes); + } + break; + +#if WITH_OPENSSL + case XIOWRITE_OPENSSL: + /* this function prints its own error messages */ + return xiowrite_openssl(pipe, buff, bytes); +#endif /* WITH_OPENSSL */ + + default: + Error1("xiowrite(): bad data type specification %d", pipe->dtype); + errno = EINVAL; + return -1; + } + return writt; +}