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; +}