netpipes-4.2.orig/0040755000175000017500000000000007706302263014120 5ustar knoppixknoppixnetpipes-4.2.orig/COPYING0100644000175000017500000004307505165674437015175 0ustar knoppixknoppix 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 he 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 Appendix: 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. netpipes-4.2.orig/Makefile0100644000175000017500000001271306615677313015572 0ustar knoppixknoppix# faucet and hose: network pipe utilities # Copyright (C) 1992,1993 Robert Forsman # # 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. # You probably want to change this: #INSTROOT = ${HOME} INSTROOT = /depot/collections0/netpipes4.1 #INSTROOT = /usr/local INSTBIN = ${INSTROOT}/bin INSTMAN = ${INSTROOT}/man # For those who wish to use gcc instead of the vendor's compiler. #CC=gcc -Wall # This might be necessary for HPUX #LDLIBS=-lBSD # I'm told this is required for Sequent SysV #LDLIBS=-lsocket -linet -lnsl # This will be necessary for Sun Solaris (the abomination) # Also necessary for SCO #LDLIBS=-lsocket -lnsl ###################################################################### # CFLAGS ###################################################################### # For SunOS, add -DNO_MEMMOVE. It doesn't have this very handy function. # If you don't want to use (or don't have) fcntl(2) try the -DUSE_IOCTL. # Add -DNO_STRERROR if your system doesn't have strerror(3) # Add -DPOSIX_SIG for POSIX signal handling, or -DSYSV for reliable signals # under SVR3. # Add -DNO_SETSID if your system doesn't have the setsid() system call. # (that system call is used by the -daemon argument to detach faucet from # the controlling terminal) # SunOS 4.1.4 #CFLAGS = -DUSE_IOCTL -DNO_MEMMOVE -DNO_STRERROR $(CDEBUGFLAGS) # GNU libc Linux (i.e. RedHat 5.0) #CFLAGS = -DPOSIX_SIG -DHAVE_INET_ATON $(CDEBUGFLAGS) # Linux (developed with RedHat 4.2, libc5) CFLAGS = -DUSE_IOCTL -DPOSIX_SIG -DHAVE_INET_ATON $(CDEBUGFLAGS) # SGI #CFLAGS = -DSYSV $(CDEBUGFLAGS) # Digital Unix ? #CFLAGS = -DSYSV $(CDEBUGFLAGS) # Solaris 2.5 #CFLAGS = -DPOSIX_SIG $(CDEBUGFLAGS) # FreeBSD #CFLAGS = -DPOSIX_SIG $(CDEBUGFLAGS) # AIX 4.1.4 and 3.2.5 #CFLAGS = -DPOSIX_SIG -DAIX $(CDEBUGFLAGS) # DG/UX R4.11MU04 -- AViiON mc88110 #CFLAGS = -DPOSIX_SIG $(CDEBUGFLAGS) # GNU Win32, the unix-like environment for Win95, # but it doesn't have Unix domain sockets. # Does not work yet (I suspect there are bugs in GNUWin32). #CFLAGS = -DNOUNIXSOCKETS -DPOSIX_SIG $(CDEBUGFLAGS) # gcc can handle both -O and -g at once #CDEBUGFLAGS = -g # -Wall -DDEBUG CDEBUGFLAGS = -O ###################################################################### FOBJS = faucet.o common.o version.o HOBJS = hose.o common.o version.o memmove.o SOBJS = sockdown.o version.o GOBJS = getpeername.o version.o TOBJS = timelimit.o version.o EOBJS = encapsulate.o common.o version.o memmove.o SSLOBJS = ssl-auth.o ssl-criteria.o common.o version.o memmove.o SSLDIR = /usr/local/ssl SSLINC = -I${SSLDIR}/include #SSLLIB = -L${SSLDIR}/lib -lssl -lcrypto SSLLIB = -L../SSLeay-0.8.1 -lssl -lcrypto MANPAGES = netpipes.1 faucet.1 hose.1 \ sockdown.1 getpeername.1 timelimit.1 encapsulate.1 \ ssl-auth.1 PROGRAMS = faucet hose sockdown getpeername timelimit encapsulate all : ${PROGRAMS} faucet : ${FOBJS} ${CC} ${CFLAGS} -o $@ ${FOBJS} ${LDLIBS} hose : ${HOBJS} ${CC} ${CFLAGS} -o $@ ${HOBJS} ${LDLIBS} sockdown: ${SOBJS} ${CC} ${CFLAGS} -o $@ ${SOBJS} ${LDLIBS} getpeername: ${GOBJS} ${CC} ${CFLAGS} -o $@ ${GOBJS} ${LDLIBS} timelimit: ${TOBJS} ${CC} ${CFLAGS} -o $@ ${TOBJS} ${LDLIBS} encapsulate: ${EOBJS} ${CC} ${CFLAGS} -o $@ ${EOBJS} ${LDLIBS} ssl-auth: ${SSLOBJS} ${CC} ${CFLAGS} -o $@ ${SSLOBJS} ${LDLIBS} ${SSLLIB} ssl-auth.o: ssl-auth.c ${CC} ${CFLAGS} ${SSLINC} -c $< ssl-criteria.o: ssl-criteria.c ${CC} ${CFLAGS} ${SSLINC} -c $< install : all test -d ${INSTROOT} || mkdir ${INSTROOT} test -d ${INSTBIN} || mkdir ${INSTBIN} cp ${PROGRAMS} ${INSTBIN}/ - rm -f ${INSTBIN}/getsockname ln -s getpeername ${INSTBIN}/getsockname - [ -x ssl-auth ] && cp ssl-auth ${INSTBIN}/ test -d ${INSTMAN} || mkdir ${INSTMAN} test -d ${INSTMAN}/man1 || mkdir ${INSTMAN}/man1 cp ${MANPAGES} ${INSTMAN}/man1/ # clean : rm -f ${FOBJS} ${HOBJS} ${SOBJS} ${GOBJS} ${TOBJS} ${EOBJS} ${SSLOBJS} spotless: clean rm -f *~ core ${PROGRAMS} # common.o encapsulate.o faucet.o getpeername.o hose.o sockdown.o \ ssl-auth.o ssl-criteria.o timelimit.o: common.h encapsulate.o hose.o ssl-auth.o: memmove.h ssl-auth.o ssl-critera.o: ssl-criteria.h # # These targets aren't for normal builders, # just for me when I make a distribution. # HTML2MAN = perl ./html2man.perl manpages: for i in *.html; do \ $(HTML2MAN) < $$i > `basename $$i .html`.1; \ done #sslexp-readkey: sslexp-readkey.c # $(CC) ${CFLAGS} ${SSLINC} -o $@ sslexp-readkey.c ${LDLIBS} ${SSLLIB} #sslexp-readcert: sslexp-readcert.c # $(CC) ${CFLAGS} ${SSLINC} -o $@ sslexp-readcert.c ${LDLIBS} ${SSLLIB} # .PHONY: release release: - rm -rf release mkdir release cd release; \ ln -s ../RCS .; co -r$(RELEASE) RCS/*,v; rm RCS ; chmod u+w *; \ ln ../COPYING . ; make HTML2MAN="perl ../html2man.perl" manpages cd release; tar cf ../netpipes-$(RELEASE)-noexport.tar * cd release; tar cf ../netpipes-$(RELEASE)-export.tar `ls | egrep -v '^ssl.*\.[ch]$$'` netpipes-4.2.orig/README0100644000175000017500000001317306615677313015013 0ustar knoppixknoppix Enjoy NETPIPES 4 by Robert Forsman thoth@purplefrog.com primary ftp site: ftp://ftp.purplefrog.com/pub/netpipes/ HTML docs: http://web.purplefrog.com/~thoth/netpipes/netpipes.html ssl-auth archive site: http://www.cryptography.org/ , then look in the network/ subdirectory ---- WHY NOW? (10/28/1998) I've been sitting on some new features and general fixes for too long. It would be 4.1.2, but I added the --netslave* flags and a couple of new criteria for ssl-auth. Have a slice of 4.2 pie! yummy! It seems to work for me, but I'm sure it has bugs ("Hey, Bob, beautiful car, but WHERE'S THE STEERING WHEEL?!"). ``Break it and send me the pieces.'' -attribution lost ---- BUILDING Check the Makefile. You will want to change where it installs stuff. Some systems require extra libraries and each one requires slightly different compile flags. Type "make". Witness the miracle of compilation. If you have the US/Canada version, the SSLeay-0.8.1 library and wish to build ssl-auth, then instead type "make all ssl-auth". To install the binaries and manual pages, "make INSTROOT=/usr/local install". Change INSTROOT to taste (it defaults to /depot/collections0/netpipes-x.x). ---- CHANGES 4.2 added the -netslave* flags to hose. These flags are introduced to cope with servers who do not gracefully deal with a close of half of the connection. Also new is "support" for GNU Win32. This basically involves removing the UNIX-domain sockets. Unfortunately, I think there are bugs in GNU Win32 because the subprocesses are unable to perform I/O on the descriptors as reliably as under UNIX. It also includes some porting patches. In ssl-auth, we've added some new criteria: --public-key-match-cert, --cert-md5-digest, and --write-pem-cert. 4.1 switched over to HTML as the primary means of documentation. I build the .man pages from the HTML using a mind-numbingly primitive and barely functional perl script. Faucet & hose now set SO_REUSEADDR by default. They had no such capability before. This should cut down on the "address in use" errors. Faucet now supports a backlog parameter to listen(2) like TCP Suite. Encapsulate now supports a "--slave"-like mode. Encapsulate should now support specifying the SCP session id. Hose used to core dump when you forgot to specify the subcommand; no more. 4.0 adds a pair of new utilities. The classic faucet and hose should be very solid, but encapsulate, and timelimit have seen very limited testing, and might not even build out-of-the-box. As always, send me email with your problems. 3.0 changed the way that the subcommand is specified. It is MUCH better than the ancient way. Read the manual pages. --- EMAIL LIST! Join the email list. This way I will have a list of interested folks to whom I can announce each release. Send email to majordomo@purplefrog.com with a message containing either subscribe netpipes or subscribe netpipes-announce The netpipes list is for netpipes-related discussion, trading magic spells, help compiling, etc. but not for politics or jokes. The netpipes-announce list is strictly for me to announce new releases and patches and includes everyone on the netpipes list (so don't subscribe to both). --- BABBLINGS OF A MAN DRIVEN INSANE BY HIS INSIGHT INTO THE WORKINGS OF THE UNIVERSE (or, GUY WHO READ TOO MUCH H.P.LOVECRAFT) Someone suggested using setsid(2) to disassociate myself from the terminal. Sounds great. I hope everyone has it. Also, I need portable ways to clean up child processes. Maybe I'll just read the perl source one day or buy the Stevens Advanced UNIX Programming book. This program has, in the past, been compiled and tested on a DEC 5100, an RS6k, an HP9k, an SGI, SCO v5.0.2, a Solaris box, SunOS 4.1.3, DG/UX 4.11 MU04, and sees almost daily usage under Linux 2.0.x. If you compile this program on an architecture/OS not mentioned above, drop me a line. If you have problems compiling on any architecture, I want to hear about it (and I'll try to help you fix the problem and make sure that the next version compiles out of the box). Normally, I say all software sucks, but I can now proudly say that NETPIPES RULES! If you disagree, tell me why and I'll see if I can fix it. --- SSL-AUTH Since SSL-AUTH uses cryptography libraries, I can't distribute it with the main NetPipes package. However, I finally found a site that can distribute it for me. If you are in the U.S. or Canada and are a citizen of those countries, you can download the full version of NetPipes from http://www.cryptography.org/ . You will have to fill out a simple HTTP form to affirm that you can legally download the software, and then it will give you access. --- THINGS NOT INCLUDED SSLeay-0.8.1 . You need to go get your own version of this. ftp://ftp.psy.uq.oz.au/pub/Crypto/SSL I want to re-distribute multitee by Dan Bernstein. It's rather awkward to use properly, but when you can get the invocation just right, it is a nuclear-powered power-tool! I'm currently too rushed to properly integrate it into the build tree, so you should just go get it yourself. Assuming you can find it :/ --- OTHER PACKAGES LIKE NETPIPES The idea behind NetPipes is like the wheel. Everybody reinvents it. Here are some other packages that do similar stuff, some of which might predate netpipes: ucspi-tcp 0.73 beta Apr 10, 1997 Dan Bernstein http://pobox.com/~djb/ucspi-tcp.html netcat 1.10 Mar 20, 1996 popular with "elite hackers" Avian Research ftp://avian.org/src/hacks/nc110.tgz Weld's NT version: http://l0pht.com/~weld/netcat/ Socket 1.1 September 1992 Jürgen Nickelsen http://www.snafu.de/~jn/socket.html netpipes-4.2.orig/common.c0100644000175000017500000002051306615677313015563 0ustar knoppixknoppix/* $Id: common.c,v 1.20 1998/08/13 14:53:30 thoth Exp $, part of faucet and hose: network pipe utilities Copyright (C) 1992-98 Robert Forsman 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. */ #include #include #include #include #include #include #include #ifndef NOUNIXSOCKETS #include #endif /*NOUNIXSOCKETS*/ #include #include #include #include #include "common.h" #define EXITCODE_CONNECTION 127 #define EXITCODE_ARGS 126 /**********************************************************************/ int *fds=0; int nfds; int fdsize=0; int how_shutdown = -2; void add_fd(fd) int fd; { if (fds==0) { fds = (int*)malloc(sizeof(*fds)*(fdsize=4)); } else if (nfds >= fdsize) { fds = (int*)realloc(fds, sizeof(*fds)*(fdsize*=2)); if (fds==0) { fprintf(stderr, "%s: Out of memory\n", progname); exit(1); } } fds[nfds++] = fd; if (fd>2) /* We should reserve this spot in the file descriptor table. If we don't it could get allocated by the socket(2) call and we would have an awful mess on our hands. */ dup2(0, fd); } void reserve_fds(placeholder) int placeholder; /* I usually pass in 0, assuming that the process will have a stdin, even if it's attached to /dev/null */ { int i; for (i=0; i=0) shutdown(socket, how_shutdown!=0); for (i=0; is_port; } else { int port; if (sscanf(portname,"%i",&port)!=1) { return 0; } else return htons(port); } } struct in_addr ** /* addr_array */ convert_hostname(name, count_ret) char *name; int *count_ret; { struct hostent *hp; struct in_addr **rval; hp = gethostbyname(name); if (hp != NULL) { int i; if (hp->h_length != sizeof(struct in_addr)) { fprintf(stderr, "%s: Funky: (hp->h_length = %d) != (sizeof(struct in_addr) = %ld)\n", progname, hp->h_length, (long) sizeof(struct in_addr)); } for (i = 0; hp->h_addr_list[i]; i++) { } *count_ret = i; rval = (struct in_addr **)malloc(sizeof(*rval) * (i+1)); for (i=0; i<*count_ret; i++) { rval[i] = (struct in_addr*)malloc(hp->h_length); memcpy((char*)rval[i], hp->h_addr_list[i], hp->h_length); } rval[*count_ret] = 0; return rval; } else { #ifndef HAVE_INET_ATON int count, len; unsigned int a1,a2,a3,a4; #endif rval = (struct in_addr**)malloc(2*sizeof(*rval)); rval[0] = (struct in_addr*)malloc(sizeof(struct in_addr)); #ifdef HAVE_INET_ATON if (0==inet_aton(name, rval[0])) { *count_ret = 0; free(rval[0]); free(rval); return 0; } #else count = sscanf(name,"%i.%i.%i.%i%n", &a1, &a2, &a3, &a4, &len); if (4!=count || 0!=name[len] ) return 0; rval[0]->s_addr = (((((a1 << 8) | a2) << 8) | a3) << 8) | a4; #endif *count_ret = 1; rval[1] = 0; return rval; } } /* print an internet host address prettily */ void printhost(fp, addr) FILE *fp; struct in_addr *addr; { struct hostent *h; char *s,**p; h = gethostbyaddr((char*)addr, sizeof(*addr),AF_INET); s = (h==NULL) ? NULL : (char*)/*gratuitous cast away const*/h->h_name; fputs(inet_ntoa(*addr), fp); fprintf(fp, "(%s",s?s:"name unknown"); if (s) for (p=h->h_aliases; *p; p++) fprintf(fp, ",%s",*p); fprintf(fp, ")"); } #ifdef NO_STRERROR /* Added for those systems without */ extern char *sys_errlist[]; extern int sys_nerr; char * strerror(num) int num; { static char ebuf[40]; /* overflow this, baby */ if (num < sys_nerr) return sys_errlist[num]; else sprintf(ebuf, "Unknown error: %i\n", num); return ebuf; } #endif /* bind to a port on the local machine. */ int bindlocal(fd, name, addrname, domain, reuseaddr) int fd, domain; char *name, *addrname; int reuseaddr; { struct sockaddr *laddr; int addrlen; int countdown; int rval; if (reuseaddr && domain == AF_INET) { #ifdef SO_REUSEADDR /* The below fix is based on articles that came from comp.sys.hp.hpux with the problem of having FIN_WAIT_2 statuses on sockets. But even on Solaris the sockets with TIME_WAIT block the bind() call, so I thought it would be a good idea to try the setsockopt() call. 1998/01/18 Thomas Endo */ int enable = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&enable, sizeof(enable)) < 0) { fprintf(stderr,"%s: error in setsockopt (%s)\n",progname, strerror(errno)); exit(EXITCODE_CONNECTION); } #else fprintf(stderr, "%s: Warning. SO_REUSEADDR is not available\n", progname); #endif } if (domain==AF_INET) { static struct sockaddr_in srv; static int initted=0; laddr = (struct sockaddr*)&srv; addrlen = sizeof(srv); if (!initted) { srv.sin_family = AF_INET; if (addrname) { int count; struct in_addr **addresses; addresses = convert_hostname(addrname, &count); if (addresses == 0) { fprintf(stderr, "%s: Unable to convert %s to an internet address\n", progname, addrname); errno=0; return 0; } srv.sin_addr = *(addresses[0]); } else { srv.sin_addr.s_addr = INADDR_ANY; } srv.sin_port = name_to_inet_port(name); if (srv.sin_port==0) { fprintf(stderr, "%s: port %s unknown\n", progname, name); errno = 0; return 0; } } initted = 1; /* bindlocal is only called once in each netpipes program */ } #ifndef NOUNIXSOCKETS else if (domain == AF_UNIX) { static struct sockaddr_un srv; laddr = (struct sockaddr*)&srv; addrlen = sizeof(srv); srv.sun_family = AF_UNIX; strncpy(srv.sun_path, name, sizeof(srv.sun_path)); srv.sun_path[sizeof(srv.sun_path) -1] = 0; /* NUL terminate that string*/ } #endif else { fprintf(stderr, "%s: unknown address family %d in bindlocal()\n", progname, domain); exit(EXITCODE_ARGS); } countdown= (domain!=AF_INET || reuseaddr)?1:10; do { rval = bind(fd, laddr, addrlen); if (rval != 0) { if (errno==EADDRINUSE && --countdown>0) { fprintf(stderr,"%s: Address %s in use, sleeping 10.\n", progname, name); sleep (10); fprintf(stderr,"%s: Trying again . . .\n", progname); } else return 0; } } while (rval); return 1; } /* check to see if the descriptor is assigned to a pipe/file/socket (valid) or is unused (INvalid) */ int valid_descriptor(int fd) { int rval; fd_set fds; struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; /* POLL */ FD_ZERO(&fds); FD_SET(fd, &fds); rval = select(fd+1, &fds, (fd_set *)0, (fd_set *)0, &tv); if (rval<0 && errno == EBADF) { #ifdef DEBUG fprintf(stderr, "%s: descriptor %d not in use\n", progname, fd); #endif return 0; } else { #ifdef DEBUG fprintf(stderr, "%s: descriptor %d already in use\n", progname, fd); #endif return 1; } } netpipes-4.2.orig/common.h0100644000175000017500000000525006615677313015571 0ustar knoppixknoppix/* $id$, part of faucet and hose: network pipe utilities Copyright (C) 1992-98 Robert Forsman 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. */ #ifndef common_h_ #define common_h_ /* set from argv[0] by the main() routine */ extern char *programname; /* list of file descriptors to dup from the socket */ extern int *fds; extern int nfds; /* the mode to use when shutting down the socket <0: don't do any shutdown 0 : shut down recieves (write-only) >0: shut down sends (read-only) */ extern int how_shutdown; /* add a file descriptor to the list */ void add_fd(/* int fd */); /* add a file descriptor to the list */ void reserve_fds(/* int placeholder */); /* do the dup from the argument socket to the list of file descriptors, perform the requested shutdown... */ void dup_n(/*int socket */); /**********************************************************************/ int name_to_inet_port(/* char* */); /**********************************************************************/ struct in_addr ** /* addr_array */ convert_hostname(/* char *, int * */); /**********************************************************************/ void printhost(/* struct in_addr * */); /**********************************************************************/ int bindlocal(/* int, char *, char*, int, int */); /**********************************************************************/ void /* this is in version.c */ emit_version(/* char*, int */); /* this is also in version.c */ extern char *progname; void set_progname(/* char *argv0 */); /* system dependencies */ #ifdef NO_STRERROR /* XXX assumption here that no strerror() means */ /* no definition of sys_errlist in errno.h */ extern char *sys_errlist[]; char * strerror(/*int*/); #endif #ifdef POSIX_SIG #define signal(a, b) { \ struct sigaction sa; \ sa.sa_handler = b; \ sigemptyset(&sa.sa_mask); \ sa.sa_flags = 0; \ sigaction(a, &sa, NULL); \ } #endif #ifdef SYSV #define signal(a, b) sigset(a, b) #endif int valid_descriptor(/*int fd */); #endif /* common_h_ */ netpipes-4.2.orig/encapsulate.10100644000175000017500000002763606615677325016535 0ustar knoppixknoppix.\" t .\"$Id: encapsulate.html,v 1.4 1998/10/28 16:07:57 thoth Exp $ .\"Copyright 1997-98 by Robert Forsman .\" .TH ENCAPSULATE 1 "June 19, 1997" .SH NAME encapsulate \- multiplex several channels over a single socket with sampling of remote process exit status, and provide conversation termination without closing the socket. netpipes 4.2 .SH SYNOPSIS \fBencapsulate\fP \fB\-\-fd\fP \fIn\fP [ \fB\-\-verbose\fP ] [ \fB\-\-subproc\fP [ \fB\-\-infd\fP \fIn\fP[\fB=\fP\fIsid\fP] ] [ \fB\-\-outfd\fP \fIn\fP[\fB=\fP\fIsid\fP] ] [ \fB\-\-duplex\fP \fIn\fP[\fB=\fP\fIsid\fP] ] [ \fB\-\-Duplex\fP \fIn\fP[\fB=\fP\fIsid\fP] ] [ \fB\-\-DUPLEX\fP \fIn\fP[\fB=\fP\fIsid\fP] ] [ \fB\-\-prefer\-local\fP ] [ \fB\-\-prefer\-remote\fP ] [ \fB\-\-local\-only\fP ] [ \fB\-\-remote\-only\fP ] ] [ \fB\-\-client\fP ] [ \fB\-\-server\fP ] \fB\-\fP[\fB#\fP\fIn\fP][\fBv\fP][\fBs\fP[\fBi\fP\fIn\fP][\fBo\fP\fIn\fP][\fBd\fP\fIn\fP][\fBio\fP\fIn\fP][\fBoi\fP\fIn\fP][\fBl\fP][\fBr\fP][\fBL\fP][\fBR\fP]] \fIcommand args ...\fP .SH DESCRIPTION \fBencapsulate \fP implements the Session Control Protocol (SCP) in a limited manner. \fBencapsulate\fP multiplexes several virtual channels over a single socket using SCP. \fBencapsulate\fP transmits the exit status of the local program to the remote end over a reserved SCP channel and receives the remote exit status back. \fBencapsulate\fP provides conversation boundaries without closing the socket. Flags may appear in any order. The first argument that isn't a flag is the command to spawn (assuming \fB\-\-subproc\fP is specified, an error otherwise). .SH OPTIONS \fB\-\-fd\fP \fIn\fP, \fB\-#\fP\fIn\fP : specify the file descriptor of the socket we will be multiplexing subprocess channels over. This argument is required \fB\-\-verbose\fP, \fB\-v\fP : Print extra information (including a copyright notice) to stderr. \fB\-\-subproc\fP, \fB\-s\fP : spawn a subprocess. You must supply a \fIcommand\fP and \fIargs\fP. If you omit this flag, then you must \fBnot\fP supply a \fIcommand\fP and \fIargs\fP. If you omit this flag, \fBencapsulate\fP will copy input from stdin to an outgoing channel in the SCP-muxed socket and copy to stdout from an incoming channel in the SCP-muxed socket. If you omit this flag, all of the input and output channel flags are illegal. \fB\-\-infd\fP \fIn\fP, \fB\-i\fP\fIn\fP : specify an input channel. If there is a subprocess, it will be able to read from descriptor \fIn\fP. If there is no subprocess \fBencapsulate\fP will read from its descriptor \fIn\fP (these are opposite polarities for the SCP channel). \fB\-\-outfd\fP \fIn\fP, \fB\-o\fP\fIn\fP : specify an output channel. If there is a subprocess, it will be able to write to descriptor \fIn\fP. If there is no subprocess \fBencapsulate\fP will write to its descriptor \fIn\fP (these are opposite polarities for the SCP channel). \fB\-\-duplex\fP \fIn\fP, \fB\-io\fP\fIn\fP : specify a bidirectional channel. The remote \fBencapsulate\fP will send the SCP SYN packet, and the local will respond with a SYN for the same session. The subprocess will be able to read and write to file descriptor \fIn\fP. The subprocess should use the \fBsockdown\fP(1) program if it must close one direction while leaving the other direction open. \fB\-\-Duplex\fP \fIn\fP, \fB\-d\fP\fIn\fP : specify a bidirectional channel. The \fB\-\-client\fP end of the \fBencapsulate\fP connection sends the SCP SYN packet and \fB\-\-server\fP responds with a SYN for the same session. The subprocess will be able to read and write to file descriptor \fIn\fP. The subprocess should use the \fBsockdown\fP(1) program if it must close one direction while leaving the other direction open. \fB\-\-DUPLEX\fP \fIn\fP, \fB\-oi\fP\fIn\fP : specify a bidirectional channel. The local \fBencapsulate\fP will send the SCP SYN packet, and the remote will respond with a SYN for the same session. The subprocess will be able to read and write to file descriptor \fIn\fP. The subprocess should use the \fBsockdown\fP(1) program if it must close one direction while leaving the other direction open. All of the long forms of the bidirectional channel have an optional \fB=\fP\fIsid\fP component that can be used to specify the SCP Session ID. This is not very useful when connecting encapsulate to another instance of itself, but could be handy when connecting to another piece of software that implements SCP. \fB\-\-prefer\-local\fP, \fB\-l\fP : if both the remote and local subprocesses exit with non-zero (erroneous) codes, \fBencapsulate\fP will exit with the same code as the local subprocess. \fBThis is the default.\fP \fB\-\-prefer\-remote\fP, \fB\-r\fP : if both the remote and local subprocesses exit with non-zero (erroneous) codes, \fBencapsulate\fP will exit with the same code as the remote subprocess. \fB\-\-local\-only\fP, \fB\-L\fP : \fBencapsulate\fP exits with the local status and ignores the remote status. \fB\-\-remote\-only\fP, \fB\-R\fP : \fBencapsulate\fP exits with the remote status and ignores the local status. .SH SESSION IDs AND SUBPROCESS CHANNELS When specifying channels for the subprocess, the order of the flags is very important. Every flag to the local \fBencapsulate\fP must have a corresponding flag on the remote \fBencapsulate\fP that is in the exact same position (in the list of channels). The descriptor numbers need not correspond, but the position and type of each channel must. A lamentably complicating factor is that the data flow implied by \fB\-\-infd\fP and \fB\-\-outfd\fP are different when you specify a subprocess. .TS H lw(2i) lw(2i) lw(2i) lw(2i). .TB Local Remote \fB\-\-infd\fP w/subproc \fB\-\-outfd\fP w/subproc \fB\-\-infd\fP w/subproc \fB\-\-infd\fP \fB\-\-infd\fP \fB\-\-infd\fP w/subproc \fB\-\-infd\fP \fB\-\-outfd\fP \fB\-\-outfd\fP w/subproc \fB\-\-infd\fP w/subproc \fB\-\-outfd\fP w/subproc \fB\-\-outfd\fP \fB\-\-outfd\fP \fB\-\-outfd\fP w/subproc \fB\-\-outfd\fP \fB\-\-infd\fP \fB\-\-duplex\fP \fB\-\-DUPLEX\fP \fB\-\-Duplex\fP \fB\-\-Duplex\fP \fB\-\-DUPLEX\fP \fB\-\-duplex\fP .TE RIGHT: .nf l$ encapsulate \-\-infd 0 \-\-duplex 5 r$ encapsulate \-\-outfd 1 \-\-DUPLEX 5 .fi WRONG: .nf l$ encapsulate \-\-infd 0 \-\-duplex 5 r$ encapsulate \-\-outfd 1 \-\-duplex 5 .fi \fB\-\-duplex\fP must have a corresponding \fB\-\-DUPLEX\fP on the remote end. .nf l$ encapsulate \-\-infd 0 \-\-duplex 5 r$ encapsulate \-\-DUPLEX 5 \-\-outfd 1 .fi \fB\-\-infd\fP must have a corresponding \fB\-\-outfd\fP on the remote end. It's out of order and the channels will be allocated incorrectly leading to protocol errors. If you understand the source code for \fBencapsulate\fP, you can violate these guidelines, but it is unnecessary, error-prone, and ill-advised; besides, you don't really understand the source code. Don't do it. .SH CLIENT \-VS\- SERVER The SCP has an implicit polarity. One end is the server and the other end is the client. You can specify which end is which using \fB\-\-client\fP and \fB\-\-server\fP. If you do not specify one, then \fBencapsulate\fP will compare the addresses of both ends of the socket (specified with \fB\-\-fd\fP) and use a deterministic algorithm to pick one to be the server and one to be the client. If the remote address of the socket does not correspond to the remote \fBencapsulate\fP (e.g. the packets are being forwarded through a plugged gateway, the addresses are being masqueraded, or are otherwise percieved inconsistently by the two ends) then this algorithm has a good chance of "failing" and assigning both to be server or both to be client. The only time you should ever let \fBencapsulate\fP choose between client and server is in interactive situations. It is very likely that a software system built around \fBencapsulate\fP will be reused in a situation where the automatic polarity assignment fails. .SH EXAMPLES Here's a simple file transfer daemon: .nf server$ faucet 3001 \-\-once \-\-fd3 \\ sh \-c 'while ~/src/netpipes4.0/encapsulate \-\-fd 3 \-so5i4 \\ sh \-c "fname=`cat 0<&4`; echo \\$fname; cat < \\$fname 1>&5"; \\ do true; done' client$ hose server 3001 \-\-retry 10 \-\-delay 1 \-\-fd3 \\ sh \-c 'while read fname; do \\ ~/src/netpipes4.0/encapsulate \-\-fd 3 \-si4o5 \\ sh \-c "echo $fname 1>&5; exec 5>&\-; cat 0<&4" \\ || break; done' .fi Just type the name of the file you want to retrieve into the hose and press return. It will be dumped to stdout. Repeat until enlightened or bored. .SH TROUBLESHOOTING Did you specify \fB\-\-client\fP and \fB\-\-server\fP properly? One side should be server, the other side should be client. If you specify them both as server or both as client, you have made a mistake. Do not rely on the automatic polarity detection. While it is theoretically a very good algorithm, it is fooled very easily. Do all of your channel assignments (\fB\-\-infd\fP et al) match up? If you get these wrong, \fBencapsulate\fP will freak out and drip spooge all over your shoes. For deadlock avoidance, make sure you are closing channels when you don't need them anymore. Use the >&\- redirection operator in sh or bash. Make sure you close it in all of the background processes as well. Unable to read stdin from a process that has been backgrounded with &\ ? Bash closes file descriptor 0 for any subprocess that is backgrounded (e.g. (command&) ). You can get around this by copying 0 onto another descriptor, and then copying it back within the backgrounded process. .nf ( ( cat 0<&3 ) & ) 3<&0 .fi .SH SEE ALSO netpipes (1), http://sunsite.unc.edu/ses/scp.html The Session Control Protocol document on SunSite was a draft. There is a more recent one that doesn't specify header compression (which I don't use anyway). It may eventually become an RFC. Then again, encapsulate may be the only program which ever implements SCP. .SH BUGS \fBencapsulate\fP is not hard to deadlock. Until I add unbounded buffering inside encapsulate, avoid constructing deadlock\-vulnerable systems. The \fBencapsulate\fP included with netpipes 4.0 totally failed to handle the case where no subprocess was specified. No error message would be issued, and the program would do absolutely nothing. The 4.1 version should work. \fBencapsulate\fP has no other known bugs. I'm sure there are unknown ones because this software is not yet mature; in fact, it's totally wet behind the ears. Break it and send me the pieces. Well, the command\-line argument style is inconsistent with faucet & hose. I'll be updating faucet & hose. The Linux kernel from the beginning of time up through version 2.0.29 has a problem with sockets being shut down "too fast". This results in loss of data at the end of a stream and an "Error: connection reset by peer" during reads. 2.0.30 supposedly fixes this. This state machine flaw is very likely present in many other OSes, because the strange conditions that exercise it are almost nonexistent in normal applications, but happen all the time in some applications of the NetPipes package. \fBencapsulate\fP can be used to work around this bug in some cases because encapsulate does not perform a shutdown on the network socket ever (it doesn't even do a "close"). .SH CREDITS Hi Mom! Hi Dad! .SH COPYRIGHT Copyright (C) 1997\-98 Robert Forsman 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. .SH AUTHOR Robert Forsman thoth@purplefrog.com Purple Frog Software http://web.purplefrog.com/~thoth/ netpipes-4.2.orig/encapsulate.c0100644000175000017500000013341106615677313016601 0ustar knoppixknoppix/* encapsulate.c, part of netpipes: network pipe utilities Copyright (C) 1996 Robert Forsman 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. */ static char info[] = "encapsulate: a utility for sockets\nWritten 1996 by Robert Forsman \n"; /* Encapsulate encapsulate is designed to be used in a script spawned as the child of a faucet or hose. ============================================================ NEW version of encapsulate now. It uses the Session Control Protocol described in http://sunsite.unc.edu/ses/scp.html . ARGS: If they don't specify --client or --server, compare your socket ID (IP first, then port if IPs match) to the other end. The numerically lower one is the server. The MSB is the first octet of the IP. If they're identical, you have bigger problems >:) For each --outfd on the subprocess, send a SYN packet with a new session ID. For each --infd on the subprocess, set aside a structure to wait for a SYN packet from the other end. Each SYN packet will be associated with a file descriptor in the order they were specified on the command line. The --duplex descriptors are trickier. They need one session ID, but who gets to allocate it? With --Duplex the "client" (which could be local or remote) allocates the session ID and sends the SYN packet. The "server" then sends a SYN packet for the same session ID causing the connection to become two-way. With --duplex, the local program waits for a SYN from the other side and responds with a SYN of its own to duplex the session. With --DUPLEX the local program sends the SYN packet and the remote side is expected to duplex the session. The short flags correspond to the long like so: --Duplex n -dn --duplex n -ion --DUPLEX n -oin Notice how the order of the i and o correspond to the order in which the SYN packets are sent. INTEROPERABILITY This program is immensely complicated by the fact that I want it to interoperate with a server that could also be speaking SCP (with some theoretical restrictions to prevent the following problems). 1) SYN packets to associate with input descriptors could come arbitrarily late in the conversaion. 2) The remote program might not be obeying our rules for the --Duplex family of directives (this particular problem, and others, could also be caused by command line mismatches on either side of the link). 3) In my reading I haven't found any restrictions on bouncing the connection between RO, RW and WO, which would wreak havoc on the file-descriptor model `encapsulate' is based on. For #1, I plan to just cope. As long as the SYNs eventually arrive, things should work. #2 is stickier, and I want to figure out an appropriate way to give a warning that a deadlock might be occurring. #3 I will handle by ruthless application of RESET packets and messages to stderr. INCOMING BUFFER: store data from socket before it is sent to the subprocess. HEADER BUFFER: store headers from new SCP packets. OUTGOING BUFFER 1: store data from subprocess before it is encapsulated in an SCP packet. NOTE: once data from a subprocess descriptor is stored in here, no other outgoing (subprocess- writeable) descriptors should be polled. There is only one of these buffers. This might result in a kind of starvation, so consider doing a round-robin thing with the outgoing subprocess descriptors that have data available. OUTGOING BUFFER 2: store the SCP packet while it's being written to the socket. While this buffer is in use, no packets can be encapsulated, so data can accumulate in outgoing buffer 1. This is good because then we have a bigger packet for next time. Note: we'll be able to read arbitrarily-sized SCP packets due to the design of the state machine. We'll be limited in the size of packets we send by the size of outgoing buffer 1. I can hear you saying "so what". */ #include #include extern int errno; /* I hate the errno header file */ #include #include #include #include #include #include #include #include #include #include "common.h" #include "memmove.h" #define EXITCODE_ARGS 127 #define EXITCODE_SYSCALLFAILED 126 #define EXITCODE_EXECFAILED 125 #define EXITCODE_SIGNAL 124 #define EXITCODE_PROTOCOL 123 #define EXITCODE_GOT_RESET 122 #define PACKETCODE_EOF 0 #define PACKETCODE_EOF_WAITING 1 #define PACKETCODE_EXITSTATUS 2 /*typedef short Nshort;*/ #define SCP_SYN 0x80 #define SCP_FIN 0x40 #define SCP_PUSH 0x20 #define SCP_RESET 0x10 #define SESSION_ENCAP 70 /* encapsulate Control Protocol */ #define ECP_EOF 0 #define ECP_EXITCODE 1 /********************************************************************/ static int subproc=0; static int verbose=0; /********************************************************************/ static void usage() { fprintf(stderr,"Usage : %s --fd n [ --verbose ] [ --subproc [ --infd n ] [ --outfd n ] [ --Duplex n ] [ --duplex n ] [ --DUPLEX n ] [ --prefer-local ] [ --prefer-remote ] [ --local-only ] [ --remote-only ] [ --client ] [ --server ] -[#n][v][s[in][on][dn][ion][oin][l][r][L][R]] ]\n", progname); } /********************************************************************/ static int remote_return_code = 0; static int local_return_code = 0; static int exitcode_warnings = 0; static int child_unreaped = 0; static int child_running = 0; static void probe_child(); static int Im_server_p(sock_fd) int sock_fd; { struct sockaddr_in me, him; int len, i; len = sizeof(me); getsockname(sock_fd, (struct sockaddr*)&me, &len); len = sizeof(him); getpeername(sock_fd, (struct sockaddr*)&him, &len); i = memcmp(&me.sin_addr, &him.sin_addr, 4); if (i<0) return 1; else if (i>0) return 0; if (me.sin_portchild_fd = fd; temp->code = code; temp->session_id = sid; temp->syn_received = 0; temp->bytes_left = 0; temp->specact = NOTHING; temp->next = 0; /* add to tail */ { struct pipeline **curr; for (curr = &pipe_head; *curr; curr = &( (*curr)->next ) ) ; *curr = temp; } } void add_control_channel() { struct pipeline *temp; temp = malloc(sizeof(*temp)); temp->child_fd = -1; temp->pipe[0] = -10; temp->code = DUPLEX_OI; temp->session_id = SESSION_ENCAP; temp->syn_received = 0; temp->bytes_left = 0; temp->specact = NOTHING; temp->next = 0; /* add to tail */ { struct pipeline **curr; for (curr = &pipe_head; *curr; curr = &( (*curr)->next ) ) ; *curr = temp; } pl_encapsulate_control = temp; } void remove_pipeline_(pl) struct pipeline ** pl; { struct pipeline *tmp; tmp = *pl; *pl = tmp->next; free(tmp); } void remove_pipeline(pl) struct pipeline * pl; { struct pipeline **curr; for (curr = &pipe_head; *curr && *curr != pl; curr = &( (*curr)->next ) ) ; if (0==*curr) { fprintf(stderr, "%s: greivous internal error. attempt to delete unlisted pipeline from queue\n", progname); exit(1); } remove_pipeline_(curr); } /* build a buffer full of SYN packets. The beginning of the buffer is the return value, and the length is stored into len_ret. */ static char * prepare_SYNs(len_ret) int *len_ret; { struct pipeline *curr; int size = 64; char *rval = (char*)malloc(size); *len_ret = 0; for (curr = pipe_head; curr; curr = curr->next) { switch (curr->code) { case WRITEABLE: case DUPLEX_IO: /* we need to wait for the other side to send a SYN for these two */ /* curr->session_id = -1; it's already -1 */ break; case READABLE: case DUPLEX_OI: if (*len_ret + 8 > size) { rval = (char*)realloc(rval, size *=2); } { char *p = rval + *len_ret; if (curr->session_id<0) { curr->session_id = session_id_; /* XXX - gotta prevent stompage in later rev */ session_id_ += 2; /* odd for servers, even for clients */ } p[0] = SCP_SYN; p[1] = (curr->session_id >>16 ) &0xff; p[2] = (curr->session_id >> 8 ) &0xff; p[3] = (curr->session_id >> 0 ) &0xff; p[4] = p[5] = p[6] = p[7] = 0; *len_ret += 8; #ifdef DEBUG fprintf(stderr, "%s: prepared SYN for session 0x%06x\n", progname, curr->session_id); #endif } break; case DUPLEX: /* can't happen */ abort(); exit(1); } } return rval; } struct special_packet { char *buf; int len; struct special_packet *next; }; struct special_packet *special_packet_queue = 0; /* stuffs a special packet into the special-packet-queue for sending at the next possible moment. sp and sp->buf must be heap-allocated. */ void prime_packet_queue_(sp) struct special_packet *sp; { struct special_packet **curr; /* add to tail */ for (curr = &special_packet_queue; *curr; curr = &(*curr)->next) ; *curr = sp; sp->next = 0; } void prime_packet_queue(buf, len) char *buf; int len; { struct special_packet *tmp; tmp = malloc(sizeof(*tmp)); tmp->buf = buf; tmp->len = len; prime_packet_queue_(tmp); } /********************************************************************/ void maybe_inject_special_packets(buf, len, size) char *buf; int *len; int size; { struct special_packet *sp; if (*len>0) return; /* can't fit one in */ sp = special_packet_queue; if (sp ==0) return; /* no special packets */ if (sp->len > size) { memcpy(buf, sp->buf, size); memmove(sp->buf, sp->buf + size, sp->len -size); sp->len -= size; *len = size; } else { memcpy(buf, sp->buf, sp->len); *len = sp->len; special_packet_queue = sp->next; free(sp->buf); free(sp); } } void build_fd_lists(readfds, writefds, curr_readable, curr_writeable, sock_fd, maxfd, ibuf_len, ibuf_size, obuf_len, obuf_size, obuf2_len, obuf2_off) fd_set *readfds, *writefds; struct pipeline *curr_readable, *curr_writeable; int sock_fd, *maxfd; int ibuf_len, ibuf_size; int obuf_len, obuf_size; int obuf2_len, obuf2_off; { FD_ZERO(readfds); FD_ZERO(writefds); *maxfd = -1; #define MAX_FD(i) if (*maxfd < (i)) *maxfd = (i) /* when can we write to a child? */ if (ibuf_len>0 && curr_writeable->pipe[0]>=0 ) { /* curr_writeable != 0 */ FD_SET(curr_writeable->pipe[0], writefds); MAX_FD( curr_writeable->pipe[0] ); } /* when can we read from the socket? */ if ( curr_writeable == 0 || (ibuf_lenbytes_left > 0 ) ) { #if 1 FD_SET(sock_fd, readfds); MAX_FD(sock_fd); #else struct pipeline *curr; for (curr = pipe_head; curr; curr = curr ? curr->next : 0) { switch(curr->code) { case DUPLEX_IO: case DUPLEX_OI: case DUPLEX: /* DUPLEX is not really possible */ case WRITEABLE: FD_SET(sock_fd, readfds); MAX_FD(sock_fd); curr = 0; /* bail from for loop */ break; case READABLE: /* we don't write to this one */ break; } } #endif } /* when can we read from a child? */ if ( curr_readable == 0 ) { /* select from ANY incoming child descriptor */ struct pipeline *curr; for (curr = pipe_head; curr; curr = curr->next) { if (curr->pipe[0]<0) continue; if ( curr->code == DUPLEX_IO && ! curr->syn_received) continue; if ( curr->specact == CLOSE_TO_WRITE ) continue; switch(curr->code) { case READABLE: case DUPLEX_IO: case DUPLEX_OI: case DUPLEX: /* DUPLEX is not really possible */ FD_SET(curr->pipe[0], readfds); MAX_FD(curr->pipe[0]); break; case WRITEABLE: /* we don't read from this one */ break; } } } else if (obuf_len < obuf_size && /* yes, the curr_readable could be WRITEABLE-only when the child closes its descriptor, but we haven't copied the bytes into the outgoing socket buffer. In that case we don't want to read from the descriptor. curr_readable will be zeroed when the bytes get copied into the outgoing socket buffer */ curr_readable->code != WRITEABLE && !( curr_readable->specact == CLOSE_TO_WRITE || curr_readable->specact == CLOSE_TO_RW) ) { FD_SET(curr_readable->pipe[0], readfds); MAX_FD(curr_readable->pipe[0]); } /* when can we write to the socket? */ if (obuf2_len>obuf2_off) { FD_SET(sock_fd, writefds); MAX_FD(sock_fd); } } void build_packet_header (buf, flags, session, length) char *buf; /* length 8 */ int flags, session; unsigned length; { buf[0] = flags; buf[1] = session>>16; buf[2] = session>>8; buf[3] = session; buf[4] = length>>24; buf[5] = length>>16; buf[6] = length>>8; buf[7] = length; } void send_reset(struct pipeline *pl) { char *buf = malloc(8); build_packet_header(buf, SCP_RESET, pl->session_id, 0); prime_packet_queue(buf, 8); } /* returns number of bytes read into buf at offset *buf_len, limited by buf_size. An uncrecoverable error aborts the program */ int read_from_child(pl, buf, buf_len, buf_size) struct pipeline *pl; char *buf; int *buf_len; int buf_size; { int rval; #if DEBUG>1 fprintf(stderr, "%s: read(in[c%d], buf+%d, %d-%d)", progname, pl->child_fd, *buf_len, buf_size, *buf_len); #endif rval = read(pl->pipe[0], buf+*buf_len, buf_size - *buf_len); #if DEBUG>1 fprintf(stderr, "=%d;\n", rval); #endif if (rval == 0) { #ifdef DEBUG fprintf(stderr, "%s: closing in[%d=c%d]\n", progname, pl->pipe[0], pl->child_fd); #endif pl->specact = CLOSE_TO_WRITE; } else if (rval<0) { if (errno == EINTR) { return 0; /* no biggie, retry later */ } else { fprintf(stderr, "%s: error during read(in[%d],,). Aborting. ", progname, pl->pipe[0]); perror(""); exit(EXITCODE_SYSCALLFAILED); } } else { *buf_len += rval; } return rval; } /* returns number of bytes written from buf, limited by (*buf_len). It takes care of moving the bytes in the buffer for the case of an incomplete write. An uncrecoverable error aborts the program */ int write_to_child(pl, buf, buf_len) struct pipeline *pl; char *buf; int *buf_len; { int rval; #if DEBUG>1 fprintf(stderr, "%s: write(out[%d/c%d], buf, %d)", progname, pl->pipe[0], pl->child_fd, *buf_len); #endif rval = write(pl->pipe[0], buf, *buf_len); #if DEBUG>1 fprintf(stderr, "=%d;\n", rval); #endif if (rval == 0) { #ifdef DEBUG fprintf(stderr, "%s: Inexplicable! write(out[%d],,%d) returns 0", progname, pl->pipe[0], *buf_len); #endif } else if (rval<0) { if (errno == EINTR) { return 0; /* no biggie, retry later */ } else if (errno == EPIPE) { /* DOH! fake it */ fprintf(stderr, "%s: EPIPE while writing to child fd %d\n", progname, pl->child_fd); exitcode_warnings = EXITCODE_GOT_RESET; pl->specact = CLOSE_TO_READ; *buf_len = 0; send_reset(pl); return 0; /* this is NOT a normal thing */ } else { fprintf(stderr, "%s: error during write(out[%d],,). Aborting. ", progname, pl->pipe[0]); perror(""); exit(EXITCODE_SYSCALLFAILED); } } else { memmove(buf, buf+rval, *buf_len - rval); *buf_len -= rval; } return rval; } /* updates obuf_off to reflect how many bytes it copied from obuf to fd */ void write_to_socket(fd, obuf, obuf_off, obuf_len) int fd; char *obuf; int *obuf_off; int obuf_len; { int rval; #if DEBUG>1 fprintf(stderr, "%s: write(sock_fd, buf+%d, %d-%d)", progname, *obuf_off, obuf_len, *obuf_off); #endif rval = write(fd, obuf+ *obuf_off, obuf_len-*obuf_off); #if DEBUG>1 fprintf(stderr, "=%d;\n", rval); #endif if (rval==0) { fprintf(stderr, "%s: Inexplicable! write(sock_fd,,%d) returns 0\n", progname, obuf_len-*obuf_off); exit(EXITCODE_SYSCALLFAILED); } else if (rval<0) { if (errno!=EINTR) { fprintf(stderr, "%s: error during write(sock_fd,,%d). Aborting. ", progname, obuf_len-*obuf_off); perror(""); exit(EXITCODE_SYSCALLFAILED); } /* never mind. try again later */ } else { *obuf_off += rval; } } /* read bytes from the socket */ void read_from_socket(fd, pl, buf, buf_len, buf_size) int fd; struct pipeline *pl; char *buf; int *buf_len, buf_size; { int desired_read = buf_size - *buf_len; int rval; if (pl && desired_read > pl->bytes_left) { desired_read = pl->bytes_left; } #if DEBUG>1 fprintf(stderr, "%s: read(sock_fd, buf+%d, %d)", progname, *buf_len, desired_read); #endif rval = read(fd, buf+*buf_len, desired_read); #if DEBUG>1 fprintf(stderr, "=%d;\n", rval); #endif if (rval==0) { fprintf(stderr, "%s: encapsulation protocol error reading socket. Socket closed prematurely by remote end.\n", progname); /*sock_closed = 1;*/ exit(EXITCODE_PROTOCOL); } else if (rval<0) { if (errno!=EINTR) { fprintf(stderr, "%s: error during read(sock_fd,,%d). Aborting. ", progname, desired_read); perror(""); exit(EXITCODE_SYSCALLFAILED); } /* never mind. try again later */ } else { *buf_len += rval; if (pl) pl->bytes_left -= rval; } if (pl == &pl_bit_bucket) { /* throw away the bytes */ #ifdef DEBUG fprintf(stderr, "%s: %d bytes into the bit bucket\n", progname, *buf_len); #endif *buf_len = 0; } } void interpret_scp_header(header, pl) unsigned char *header; /* size 8 */ struct pipeline **pl; { int flags, session_id; unsigned int length; struct pipeline *found = 0; flags = header[0]; session_id = ( header[1] << 16 ) | ( header[2] << 8 ) | header[3]; length = ( header[4] << 24 ) | ( header[5] << 16 ) | ( header[6] << 8 ) | header[7]; #ifdef DEBUG fprintf(stderr, "%s: packet. flags=0x%02x, session=0x%06x, length=%d\n", progname, flags, session_id, length); #endif if ( (flags & (SCP_SYN|0xf)) == SCP_SYN) { struct pipeline *curr; found = 0; /* see if there's one descriptor that's waiting for this particular session_id */ for (curr = pipe_head; curr && !found; curr = curr->next ) { if (curr->syn_received) continue; switch(curr->code) { case WRITEABLE: case DUPLEX_IO: case DUPLEX_OI: case DUPLEX: /* DUPLEX not actually possible */ if (curr->session_id == session_id) { found = curr; found->syn_received = 1; } break; case READABLE: break; /* like, whatever */ } } if (!found) for (curr = pipe_head; curr && !found; curr = curr->next ) { if (curr->syn_received) continue; switch(curr->code) { case WRITEABLE: case DUPLEX_IO: case DUPLEX_OI: case DUPLEX: /* DUPLEX not actually possible */ if (curr->session_id<0) { found = curr; found->session_id = session_id; found->syn_received = 1; } break; case READABLE: break; /* like, whatever */ } } if (!found) { fprintf(stderr, "%s: Warning! discarding SYN for session_id=0x%06x, to the bit bucket!\n", progname, session_id); found = &pl_bit_bucket; } else { #ifdef DEBUG fprintf(stderr, "%s: received SYN for session 0x%06x", progname, session_id); #endif if (found->code == DUPLEX_IO) { char *buf = malloc(8); build_packet_header(buf, SCP_SYN, session_id, 0); prime_packet_queue(buf, 8); #ifdef DEBUG fprintf(stderr, "; sending one back"); #endif } #ifdef DEBUG putc('\n', stderr); #endif } /* fall through and accept any data that might be in the packet */ } else if ( (flags & (SCP_FIN|0xf)) == SCP_FIN) { struct pipeline *curr; for (curr = pipe_head; curr && !found; curr = curr->next ) { if (! curr->syn_received) continue; if (curr->session_id != session_id) continue; switch(curr->code) { case WRITEABLE: case DUPLEX_IO: case DUPLEX_OI: case DUPLEX: /* DUPLEX not actually possible */ found = curr; found->specact = CLOSE_TO_READ; break; case READABLE: break; /* like, whatever */ } } if (!found) { fprintf(stderr, "%s: Warning! discarding FIN for session_id=0x%06x, to the bit bucket!\n", progname, session_id); found = &pl_bit_bucket; } else { #ifdef DEBUG fprintf(stderr, "%s: received FIN for session 0x%06x\n", progname, session_id); #endif } } else if ( (flags & (SCP_PUSH|0xf)) == SCP_PUSH) { /* like, whatever */ } else if ( (flags & (SCP_RESET|0xf)) == SCP_RESET) { struct pipeline *curr; /* why are they doing this to me? */ fprintf(stderr, "%s: RESET received for session_id=%d. closing descriptor bidirectionally\n", progname, session_id); for (curr = pipe_head; curr && !found; curr = curr->next ) { if (! curr->syn_received) continue; if (curr->session_id != session_id) continue; switch(curr->code) { case READABLE: case DUPLEX_IO: case DUPLEX_OI: case DUPLEX: /* DUPLEX not actually possible */ case WRITEABLE: found = curr; found->specact = CLOSE_TO_RW; exitcode_warnings = EXITCODE_GOT_RESET; break; } } if (!found) { fprintf(stderr, "%s: Warning! discarding RESET for session_id=0x%06x, to the bit bucket!\n", progname, session_id); found = &pl_bit_bucket; } } else if (flags != 0) { fprintf(stderr, "%s: Warning! funky flags 0x%02x on packet, to the bit bucket!\n", progname, flags); found = &pl_bit_bucket; } else { struct pipeline *curr; for (curr = pipe_head; curr && !found; curr = curr->next ) { if (curr->session_id == session_id) { found = curr; break; } } if (!found) { fprintf(stderr, "%s: Warning! discarding data packet for session_id=0x%06x, to the bit bucket!\n", progname, session_id); found = &pl_bit_bucket; } } if (length) { if (found->code == READABLE) { fprintf(stderr, "%s: Got data for session 0x%06x I can't write to. RESETting\n", progname, session_id); send_reset(found); found = &pl_bit_bucket; } *pl = found; (*pl)->bytes_left = length; } } void handle_control_message(buf, len) char *buf; int len; { if (len<1) { fprintf(stderr, "%s: Internal Error: control message length <1. \n", progname); exit(1); } switch(buf[0]) { case ECP_EOF: if (len!=1) { fprintf(stderr, "%s: Protocol Error: control message[0] length(%d) !=1. \n", progname, len); exit(EXITCODE_PROTOCOL); } #ifdef DEBUG fprintf(stderr, "%s: Got EOF from remote.\n", progname); #endif if (pl_encapsulate_control->code == WRITEABLE) { remove_pipeline(pl_encapsulate_control); pl_encapsulate_control = 0; } else { pl_encapsulate_control->code = READABLE; } break; case ECP_EXITCODE: if (len!=2) { fprintf(stderr, "%s: Protocol Error: control message[1] length(%d) !=2. \n", progname, len); exit(EXITCODE_PROTOCOL); } remote_return_code = (unsigned char )buf[1]; #ifdef DEBUG fprintf(stderr, "%s: remote exit status: %d\n", progname, remote_return_code); #endif if (pl_encapsulate_control->code == WRITEABLE) { remove_pipeline(pl_encapsulate_control); pl_encapsulate_control = 0; } else { pl_encapsulate_control->code = READABLE; } break; default: fprintf(stderr, "%s: Protocol Error: unknown control message [%d]. \n", progname, (unsigned char)buf[0]); exit(EXITCODE_PROTOCOL); break; } } void perform_special_actions(ibuf_len, obuf_len, curr_readable, curr_writeable) int *ibuf_len; int *obuf_len; struct pipeline **curr_readable, **curr_writeable; { struct pipeline **curr; for (curr = &pipe_head; *curr; curr = curr ? (&(*curr)->next) : &pipe_head ) { switch ((*curr)->specact) { case NOTHING: break; case CLOSE_TO_READ: /* got a FIN packet */ if (*ibuf_len>0) break; /* can't drop it yet */ if (*curr_writeable == *curr || *curr_readable == *curr) { /* fprintf(stderr, "%s: weird, special action CLOSE_TO_READ applied to a curr_ pipeline %lx\n", progname, (long)*curr); */ break; } switch((*curr)->code) { case WRITEABLE: #ifdef DEBUG fprintf(stderr, "%s: closing W child fd %d\n", progname, (*curr)->child_fd); #endif close((*curr)->pipe[0]); remove_pipeline_(curr); curr = 0; /* start scanning from the beginning */ break; case DUPLEX: /* DUPLEX not actually possible */ case DUPLEX_IO: case DUPLEX_OI: #ifdef DEBUG fprintf(stderr, "%s: converting child fd %d to child-write-only\n", progname, (*curr)->child_fd); #endif (*curr)->specact = NOTHING; (*curr)->code = READABLE; shutdown((*curr)->pipe[0], 1); break; case READABLE: fprintf(stderr, "%s: internal error, attempt to CLOSE_TO_READ on a READABLE descriptor\n", progname); exit(1); } break; case CLOSE_TO_RW: /* got a RESET packet. get drastic */ if ( (*curr)->bytes_left >0) { fprintf(stderr, "%s: Freaky, %d bytes_left in CLOSE_TO_RW channel\n", progname, (*curr)->bytes_left); break; /* can't dump it without corrupting the stream */ } if (*curr_readable == *curr) { *obuf_len = 0; *curr_readable = 0; } if (*curr_writeable == *curr) { *ibuf_len = 0; *curr_writeable = 0; } #ifdef DEBUG fprintf(stderr, "%s: RESETting child fd %d\n", progname, (*curr)->child_fd); #endif { struct pipeline *temp = *curr; close(temp->pipe[0]); *curr = temp->next; free(temp); } curr = 0; /* start scanning from the beginning */ break; case CLOSE_TO_WRITE: /* child closed the descriptor */ if (*curr_writeable == *curr || *curr_readable == *curr) { /*fprintf(stderr, "%s: weird, special action CLOSE_TO_WRITE applied to a curr_ pipeline %lx\n", progname, (long)*curr);*/ break; } { char *buf; int len; len = 8; buf = malloc(len); build_packet_header(buf, SCP_FIN, (*curr)->session_id, 0); prime_packet_queue(buf, len); #ifdef DEBUG fprintf(stderr, "%s: sending FIN for session 0x%06x\n", progname, (*curr)->session_id); #endif } switch((*curr)->code) { case READABLE: #ifdef DEBUG fprintf(stderr, "%s: closing R child fd %d\n", progname, (*curr)->child_fd); #endif { struct pipeline *temp = *curr; temp = *curr; close(temp->pipe[0]); *curr = temp->next; free(temp); } curr = 0; /* start scanning from the beginning */ break; case DUPLEX: /* DUPLEX not actually possible */ case DUPLEX_IO: case DUPLEX_OI: #ifdef DEBUG fprintf(stderr, "%s: converting child fd %d to child-read-only\n", progname, (*curr)->child_fd); #endif (*curr)->specact = NOTHING; (*curr)->code = WRITEABLE; shutdown((*curr)->pipe[0], 0); break; case WRITEABLE: fprintf(stderr, "%s: internal error, attempt to CLOSE_TO_WRITE on a WRITEABLE descriptor\n", progname); exit(1); } break; } } } #define BUF_SIZE 4096 static void main_io_loop(sock_fd) int sock_fd; { char incoming_buf[BUF_SIZE]; /* read from socket, will write to child */ char outgoing_buf[BUF_SIZE]; /* read from child, will packetize into : */ char outgoing2_buf[BUF_SIZE+8]; /* packet buf, will write to socket */ /* bytes in the buffer to child */ /* this is nonzero only if curr_writeable is nonNULL */ int incoming_len=0; /* this is nonzero only if curr_readable is nonNULL */ /* bytes in the buffer from child */ int outgoing_len=0; /* bytes in the buffer to socket */ /* this is independent of the curr_ variables */ int outgoing2_len=0; int outgoing2_off=0; /* for reading SCP headers */ char header_buf[8]; int header_len; fd_set readfds, writefds; int maxfd; struct pipeline *curr_readable=0; /* child descriptor we're reading */ struct pipeline *curr_writeable=0; /* child descriptor we're writing */ while (1) { int rval; build_fd_lists ( &readfds, &writefds, curr_readable, curr_writeable, sock_fd, &maxfd, incoming_len, sizeof(incoming_len), outgoing_len, sizeof(outgoing_buf), outgoing2_len, outgoing2_off); if ( #if 0 maxfd<0 || #else (!subproc || !child_unreaped) && #endif (0==pipe_head && 0 == outgoing2_len && special_packet_queue == 0) ) { if (incoming_len != 0 || outgoing_len != 0 || outgoing2_len != 0) { fprintf(stderr, "%s: leftover bytes in buffers at end of encapsulation. That is bad because it means Bob made a logic error in his code.\n", progname); } break; /* run out of things to do */ } if (maxfd>0) { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 500000; rval = select(maxfd+1, &readfds, &writefds, (fd_set*)0, &tv); if (rval<0) { if (errno == EINTR) { continue; } else { fprintf(stderr, "%s: error during select: ", progname); perror(""); exit(EXITCODE_SYSCALLFAILED); } /* NOTREACHED */ } else if (rval==0) { /* got a timeout */ } /* read bytes from the child */ { struct pipeline *curr; for (curr = pipe_head; curr; curr = curr->next) { switch (curr->code) { case READABLE: case DUPLEX_IO: case DUPLEX_OI: case DUPLEX: if (curr->pipe[0]>=0 && FD_ISSET(curr->pipe[0], &readfds) && (curr==curr_readable || 0==curr_readable)) { if (read_from_child(curr, outgoing_buf, &outgoing_len, sizeof(outgoing_buf)) ) curr_readable = curr; } break; case WRITEABLE: break; } } } /* write bytes to the child */ if (curr_writeable && incoming_len>0 && curr_writeable->pipe[0] >=0 && FD_ISSET(curr_writeable->pipe[0], &writefds) ) { write_to_child(curr_writeable, incoming_buf, &incoming_len); if (incoming_len<1 && curr_writeable->bytes_left <1) { curr_writeable = 0; } } /* write bytes to the socket */ if (FD_ISSET(sock_fd, &writefds)) { write_to_socket(sock_fd, outgoing2_buf, &outgoing2_off, outgoing2_len); if (outgoing2_off >= outgoing2_len) { outgoing2_len = 0; outgoing2_off = 0; } } /* read bytes from the socket */ if (FD_ISSET(sock_fd, &readfds)) { if (curr_writeable) { read_from_socket(sock_fd, curr_writeable, incoming_buf, &incoming_len, sizeof(incoming_buf) ); } else { read_from_socket(sock_fd, (struct pipeline *)0, header_buf, &header_len, sizeof(header_buf)); if (header_len==sizeof(header_buf)) { interpret_scp_header(header_buf, &curr_writeable); header_len = 0; } } } } maybe_inject_special_packets(outgoing2_buf, &outgoing2_len, sizeof(outgoing2_buf)); if (outgoing2_len==0 && outgoing_len>0) { build_packet_header(outgoing2_buf, 0, curr_readable->session_id, outgoing_len); memcpy(outgoing2_buf + 8, outgoing_buf, outgoing_len); outgoing2_len = outgoing_len + 8; outgoing_len = 0; } if (curr_readable && outgoing_len==0) { curr_readable = 0; } if (curr_writeable && curr_writeable->bytes_left == 0 && curr_writeable == pl_encapsulate_control && incoming_len>0) { handle_control_message(incoming_buf, incoming_len); incoming_len = 0; curr_writeable = 0; } if (subproc) { if (!child_running && child_unreaped) { probe_child(); } } else { if (pipe_head != 0 && pipe_head == pl_encapsulate_control && pipe_head->next == 0 && pipe_head->code != WRITEABLE) { /* all channels are closed */ char *buf; int len = 1; #ifdef DEBUG fprintf(stderr, "%s: sending EOF\n", progname); #endif buf = malloc(8+len); build_packet_header(buf, 0, SESSION_ENCAP, len); buf[8] = ECP_EOF; prime_packet_queue(buf, 8+len); if (pl_encapsulate_control->code == READABLE) { remove_pipeline(pl_encapsulate_control); pl_encapsulate_control = 0; } else { pl_encapsulate_control->code = WRITEABLE; } } } perform_special_actions(&incoming_len, &outgoing_len, &curr_readable, &curr_writeable); } } /********************************************************************/ static int childpid = -1; static void waitonchild() { /* got a SIGCHILD. It must be that: */ child_running = 0; } static void probe_child() { if (child_running || !child_unreaped) return; if ( 0>=wait(&local_return_code)) { fprintf(stderr, "%s: wait returned error or zero: ", progname); perror(""); exit(EXITCODE_SYSCALLFAILED); } if (!WIFEXITED(local_return_code)) local_return_code = EXITCODE_SIGNAL; else local_return_code = WEXITSTATUS(local_return_code); { char *buf; int len = 2; #ifdef DEBUG fprintf(stderr, "%s: sending exit status %d\n", progname, local_return_code); #endif buf = malloc(8+len); build_packet_header(buf, 0, SESSION_ENCAP, len); buf[8] = ECP_EXITCODE; buf[8+1] = local_return_code; prime_packet_queue(buf, len+8); if (pl_encapsulate_control->code == READABLE) { remove_pipeline(pl_encapsulate_control); pl_encapsulate_control = 0; } else { pl_encapsulate_control->code = WRITEABLE; } } child_unreaped = 0; } static void spawn_child(cmd, sockfd) char **cmd; int sockfd; { struct pipeline *curr; signal(SIGCHLD,waitonchild); child_running = 1; /* well, not yet. */ child_unreaped = 1; /* We're about to allocate a big stack of descriptors. Let's make sure we don't step on on our own toes. Dup descriptor 0 onto each of the descriptors so that our allocations won't get one of them. If you don't have a descriptor 0, then you're a FREAK! */ /* Uhoh. Some of them may already be connected to the parent. Bob attaches some funky things in funky places. */ /* The way I tell if a descriptor has been allocated or not is I select() on it. If I get EBADF, the descriptor has not been allocated and I can stomp on it before the fork. If I don't, then I won't stomp on it till after the fork. */ { for (curr = pipe_head; curr; curr = curr->next) { if (curr->child_fd<0) continue; if (!valid_descriptor(curr->child_fd)) dup2(0, curr->child_fd); /* "reserve" it */ } } for (curr = pipe_head; curr; curr = curr->next) { if (curr->child_fd<0) continue; /* skip this special channel */ switch (curr->code) { case READABLE: case WRITEABLE: if (pipe(curr->pipe) !=0) { fprintf(stderr, "%s: totally failed to pipe(2): ", progname); perror(""); exit (EXITCODE_SYSCALLFAILED); } break; case DUPLEX: case DUPLEX_IO: case DUPLEX_OI: if (0!=socketpair(AF_UNIX, SOCK_STREAM, 0/*let it choose*/, curr->pipe)) { fprintf(stderr, "%s: totally failed to socketpair(2): ", progname); perror(""); exit (EXITCODE_SYSCALLFAILED); } } if (curr->code == WRITEABLE) { /* we need to invert the polarity for this case, eh, Geordi? */ int t; t = curr->pipe[0]; curr->pipe[0] = curr->pipe[1]; curr->pipe[1] = t; } } childpid = fork(); if (childpid<0) { fprintf(stderr, "%s: unable to fork: ", progname); perror(""); /* I would clear child_running, but, look at the next line */ exit(EXITCODE_SYSCALLFAILED); } /* now there's a child running (assuming no race conditions, which is why I set it up above and not here. I'm stupid, but paranoid). */ if (childpid==0) { /* child */ close(sockfd); /* can't have the child accidentally stomping on our conversation. */ for (curr = pipe_head; curr; curr = curr->next) { if (curr->child_fd<0) continue; /* skip this special channel */ close(curr->pipe[0]); dup2(curr->pipe[1], curr->child_fd); close(curr->pipe[1]); } execvp(*cmd, cmd); fprintf(stderr, "%s: Unable to exec %s: ", progname, *cmd); perror(""); exit(EXITCODE_EXECFAILED); } else { /* parent */ for (curr = pipe_head; curr; curr = curr->next) { if (curr->child_fd<0) continue; /* skip this special channel */ close(curr->pipe[1]); } } } static void rig_single() { struct pipeline *curr; /* Dear mother of god. I have to invert the polarity of all the pipes. How the hell am I going to explain this in the manual page? */ for (curr = pipe_head; curr; curr = curr->next) { switch (curr->code) { case READABLE: curr->code = WRITEABLE; break; case WRITEABLE: curr->code = READABLE; break; default: /* I don't need to diddle the duplex cases really */ break; } /* so that select and I/O will work */ curr->pipe[0] = curr->child_fd; curr->pipe[1] = -1; } } /********************************************************************/ static int scan_flag_numeric_fd(s, fdp) char *s; int *fdp; { int n; if (1 != sscanf(s, "%i%n", fdp, &n)) { fprintf(stderr, "%s: parse error in file descriptor list at '%s'\n", progname, s); exit(EXITCODE_ARGS); } return n; } /********************************************************************/ enum mergereturns_ { UNINITIALIZED, PREFER_LOCAL, /* if both local and remote processes error, return the local code */ PREFER_REMOTE, /* if both local and remote processes error, return the remote code. */ LOCAL_ONLY, /* return the exit code of the local process, ignoring the return code of the remote process. */ REMOTE_ONLY, /* return the exit code of the remote process, ignoring the return code of the local process. */ } merge_returns = UNINITIALIZED; static int sockfd = -1; static int im_server = -1; int main (argc,argv) int argc; char ** argv; { set_progname(argv[0]); #if 0 if (sizeof(Nshort) != 2) { fprintf(stderr, "%s: greivous porting error. sizeof(Nshort) == %d, not 2.\n", progname, sizeof(Nshort)); exit(EXITCODE_ARGS); } #endif while (argc>1) { char *arg = argv[1]; if (arg[0] != '-') { break; } arg++; if (arg[0] == '-') { arg++; if (0==strcmp(arg, "verbose")) { verbose = 1; argv++; argc--; } else if (0==strcmp(arg, "fd")) { argv++; argc--; if (argc<2) { fprintf(stderr, "%s: --fd requires file number for socket.\n", progname); usage(); exit(EXITCODE_ARGS); } else if (sockfd>=0) { fprintf(stderr, "%s: --fd can only be specified once\n", progname); usage(); exit(EXITCODE_ARGS); } else { sockfd = atoi(argv[1]); argv++; argc--; } } else if (0==strcmp(arg, "subproc")) { subproc = 1; argv++; argc--; } else if (0==strcmp(arg, "infd") || 0==strcmp(arg, "outfd") || 0==strcmp(arg, "duplex") || 0==strcmp(arg, "Duplex") || 0==strcmp(arg, "DUPLEX")) { long fd, sid; char *p; int err = 0; enum pipe_polarity pol = -1; argv++; argc--; if (argc<2 || argv[1][0] == 0) { err = 1; } else { fd = strtol(argv[1], &p, 0); if (*p==0) { sid = -1; } else if (p[0] == '=' && p[1] != 0) { sid = strtol(p+1, &p, 0); if (*p != 0) { err = 1; } } else { err = 1; } } if (err) { fprintf(stderr, "%s: %s requires descriptor number as argument\n", progname, arg-2); usage(); exit(EXITCODE_ARGS); } { if (0==strcmp(arg, "infd")) pol = WRITEABLE; else if (0==strcmp(arg, "outfd")) pol = READABLE; else if (0==strcmp(arg, "duplex")) pol = DUPLEX_IO; else if (0==strcmp(arg, "Duplex")) pol = DUPLEX; else if (0==strcmp(arg, "DUPLEX")) pol = DUPLEX_OI; } if (pol == -1) { fprintf(stderr, "%s: code error, polarity uninitialized %s:%d\n", progname, __FILE__, __LINE__); abort(); } add_subproc_fd(fd, pol, -1); argv++; argc--; } else if (0==strcmp(arg, "prefer-local")|| 0==strcmp(arg, "preferlocal")) { merge_returns = PREFER_LOCAL; argv++; argc--; } else if (0==strcmp(arg, "prefer-remote")|| 0==strcmp(arg, "preferremote")) { merge_returns = PREFER_REMOTE; argv++; argc--; } else if (0==strcmp(arg, "local-only")|| 0==strcmp(arg, "localonly")) { merge_returns = LOCAL_ONLY; argv++; argc--; } else if (0==strcmp(arg, "remote-only")|| 0==strcmp(arg, "remoteonly")) { merge_returns = REMOTE_ONLY; argv++; argc--; } else if (0==strcmp(arg, "client")) { im_server = 0; argv++; argc--; } else if (0==strcmp(arg, "server")) { im_server = 1; argv++; argc--; } else { /* unknown -- flag. Assume it's a command :) */ break; } } else { /* it's a set of single dash flags. */ do { switch (arg[0]) { case '#': arg += scan_flag_numeric_fd(arg+1, &sockfd); break; case 'v': verbose = 1; break; case 's': subproc=1; break; case 'i': if (arg[1] == 'o') { int fd; arg += scan_flag_numeric_fd(arg+2, &fd); add_subproc_fd(fd, DUPLEX_IO, -1); } else { int fd; arg += scan_flag_numeric_fd(arg+1, &fd); add_subproc_fd(fd, WRITEABLE, -1); } break; case 'o': if (arg[1] == 'i') { int fd; arg += scan_flag_numeric_fd(arg+2, &fd); add_subproc_fd(fd, DUPLEX_OI, -1); } else { int fd; arg += scan_flag_numeric_fd(arg+1, &fd); add_subproc_fd(fd, READABLE, -1); } break; case 'd': { int fd; arg += scan_flag_numeric_fd(arg+1, &fd); add_subproc_fd(fd, DUPLEX, -1); } break; case 'l': merge_returns = PREFER_LOCAL; break; case 'r': merge_returns = PREFER_REMOTE; break; case 'L': merge_returns = LOCAL_ONLY; break; case 'R': merge_returns = REMOTE_ONLY; break; case 0: fprintf(stderr, "%s: blank compact flag.\n", progname); /* fall through */ default: fprintf(stderr, "%s: Unknown compact flag beginning %s\n", progname, arg); usage(); exit (EXITCODE_ARGS); } arg++; } while (arg[0]); argv++; argc--; } } /* argv+1 points to an unrecognized flag that must be the subprocess cmd and arguments. */ if (argc>1 && !subproc) { fprintf(stderr, "%s: Unknown flag %s\n", progname, argv[1]); usage(); exit (EXITCODE_ARGS); } if (sockfd<0) { fprintf(stderr, "%s: I must know the file number for the socket.\n", progname); usage(); exit(EXITCODE_ARGS); } if (subproc) { if (merge_returns == UNINITIALIZED) merge_returns = PREFER_LOCAL; /* check to make sure at least one descriptor is rerouted */ if (pipe_head == 0) { fprintf(stderr, "%s: must redirect at least one descriptor of subprocess.\n", progname); usage(); exit(EXITCODE_ARGS); } } else { if (pipe_head == 0) { /* rig the degenerate case */ add_subproc_fd(0, WRITEABLE, -1); add_subproc_fd(1, READABLE, -1); } if (merge_returns == PREFER_LOCAL || merge_returns == PREFER_REMOTE || merge_returns == LOCAL_ONLY || merge_returns == REMOTE_ONLY) { fprintf(stderr, "%s: no local process to get a return code from\n", progname); usage(); exit (EXITCODE_ARGS); } merge_returns = LOCAL_ONLY; } add_control_channel(); /* for passing exit status. Is DUPLEX_OI. */ if (verbose) emit_version("encapsulate", 1996); if (im_server<0) { im_server = Im_server_p(sockfd); } { struct pipeline *curr; for (curr = pipe_head; curr; curr = curr->next) { if (curr->code == DUPLEX) curr->code = im_server ? DUPLEX_IO : DUPLEX_OI; } /* might as well initialize our session_id counter */ session_id_ = im_server ? 1025 : 1024; /* below 1024 is reserved */ } if (subproc) spawn_child(argv+1, sockfd); else { /* I have to invert the polarity of writable and readable channels, but not duplex. Also have to copy the child_fd to pipe[0]. What a hellish mess. */ rig_single(); } signal(SIGPIPE, SIG_IGN); /* handle the error returns */ { char *buf; int len; buf = prepare_SYNs( &len); prime_packet_queue(buf, len); } main_io_loop(sockfd); #ifdef DEBUG fprintf(stderr, "%s: end of IO loop\n", progname); #endif #if 0 while (child_running) { pause(); } probe_child(); #endif if (local_return_code ==0) local_return_code = exitcode_warnings; switch (merge_returns) { case PREFER_LOCAL: if (local_return_code!=0) exit (local_return_code); else exit (remote_return_code); /* NOTREACHED */ case PREFER_REMOTE: if (remote_return_code!=0) exit (remote_return_code); else exit (local_return_code); /* NOTREACHED */ case LOCAL_ONLY: exit(local_return_code); case REMOTE_ONLY: exit(remote_return_code); default: fprintf(stderr, "%s: logic error. merge_returns has bogus value.\n", progname); exit(EXITCODE_ARGS); } } netpipes-4.2.orig/encapsulate.html0100644000175000017500000003123606615677313017325 0ustar knoppixknoppix ENCAPSULATE 1 "June 19, 1997"

NAME

encapsulate - multiplex several channels over a single socket with sampling of remote process exit status, and provide conversation termination without closing the socket.

netpipes 4.2

SYNOPSIS

encapsulate --fd n [ --verbose ] [ --subproc [ --infd n[=sid] ] [ --outfd n[=sid] ] [ --duplex n[=sid] ] [ --Duplex n[=sid] ] [ --DUPLEX n[=sid] ] [ --prefer-local ] [ --prefer-remote ] [ --local-only ] [ --remote-only ] ] [ --client ] [ --server ] -[#n][v][s[in][on][dn][ion][oin][l][r][L][R]] command args ...

DESCRIPTION

encapsulate implements the Session Control Protocol (SCP) in a limited manner. encapsulate multiplexes several virtual channels over a single socket using SCP. encapsulate transmits the exit status of the local program to the remote end over a reserved SCP channel and receives the remote exit status back. encapsulate provides conversation boundaries without closing the socket.

Flags may appear in any order. The first argument that isn't a flag is the command to spawn (assuming --subproc is specified, an error otherwise).

OPTIONS

--fd n, -#n : specify the file descriptor of the socket we will be multiplexing subprocess channels over. This argument is required

--verbose, -v : Print extra information (including a copyright notice) to stderr.

--subproc, -s : spawn a subprocess. You must supply a command and args. If you omit this flag, then you must not supply a command and args. If you omit this flag, encapsulate will copy input from stdin to an outgoing channel in the SCP–muxed socket and copy to stdout from an incoming channel in the SCP–muxed socket. If you omit this flag, all of the input and output channel flags are illegal.

--infd n, -in : specify an input channel. If there is a subprocess, it will be able to read from descriptor n. If there is no subprocess encapsulate will read from its descriptor n (these are opposite polarities for the SCP channel).

--outfd n, -on : specify an output channel. If there is a subprocess, it will be able to write to descriptor n. If there is no subprocess encapsulate will write to its descriptor n (these are opposite polarities for the SCP channel).

--duplex n, -ion : specify a bidirectional channel. The remote encapsulate will send the SCP SYN packet, and the local will respond with a SYN for the same session. The subprocess will be able to read and write to file descriptor n. The subprocess should use the sockdown(1) program if it must close one direction while leaving the other direction open.

--Duplex n, -dn : specify a bidirectional channel. The --client end of the encapsulate connection sends the SCP SYN packet and --server responds with a SYN for the same session. The subprocess will be able to read and write to file descriptor n. The subprocess should use the sockdown(1) program if it must close one direction while leaving the other direction open.

--DUPLEX n, -oin : specify a bidirectional channel. The local encapsulate will send the SCP SYN packet, and the remote will respond with a SYN for the same session. The subprocess will be able to read and write to file descriptor n. The subprocess should use the sockdown(1) program if it must close one direction while leaving the other direction open.

All of the long forms of the bidirectional channel have an optional =sid component that can be used to specify the SCP Session ID. This is not very useful when connecting encapsulate to another instance of itself, but could be handy when connecting to another piece of software that implements SCP.

--prefer-local, -l : if both the remote and local subprocesses exit with non–zero (erroneous) codes, encapsulate will exit with the same code as the local subprocess. This is the default.

--prefer-remote, -r : if both the remote and local subprocesses exit with non–zero (erroneous) codes, encapsulate will exit with the same code as the remote subprocess.

--local-only, -L : encapsulate exits with the local status and ignores the remote status.

--remote-only, -R : encapsulate exits with the remote status and ignores the local status.

SESSION IDs AND SUBPROCESS CHANNELS

When specifying channels for the subprocess, the order of the flags is very important. Every flag to the local encapsulate must have a corresponding flag on the remote encapsulate that is in the exact same position (in the list of channels). The descriptor numbers need not correspond, but the position and type of each channel must.

A lamentably complicating factor is that the data flow implied by --infd and --outfd are different when you specify a subprocess.
Local Remote
--infd w/subproc --outfd w/subproc
--infd w/subproc --infd
--infd --infd w/subproc
--infd --outfd
--outfd w/subproc --infd w/subproc
--outfd w/subproc --outfd
--outfd --outfd w/subproc
--outfd --infd
--duplex --DUPLEX
--Duplex --Duplex
--DUPLEX --duplex

RIGHT:

l$ encapsulate --infd 0 --duplex 5
r$ encapsulate --outfd 1 --DUPLEX 5
WRONG:
l$ encapsulate --infd 0 --duplex 5
r$ encapsulate --outfd 1 --duplex 5

--duplex must have a corresponding --DUPLEX on the remote end.

l$ encapsulate --infd 0 --duplex 5
r$ encapsulate --DUPLEX 5 --outfd 1

--infd must have a corresponding --outfd on the remote end. It's out of order and the channels will be allocated incorrectly leading to protocol errors.

If you understand the source code for encapsulate, you can violate these guidelines, but it is unnecessary, error–prone, and ill–advised; besides, you don't really understand the source code. Don't do it.

CLIENT -VS- SERVER

The SCP has an implicit polarity. One end is the server and the other end is the client. You can specify which end is which using --client and --server. If you do not specify one, then encapsulate will compare the addresses of both ends of the socket (specified with --fd) and use a deterministic algorithm to pick one to be the server and one to be the client. If the remote address of the socket does not correspond to the remote encapsulate (e.g. the packets are being forwarded through a plugged gateway, the addresses are being masqueraded, or are otherwise percieved inconsistently by the two ends) then this algorithm has a good chance of "failing" and assigning both to be server or both to be client.

The only time you should ever let encapsulate choose between client and server is in interactive situations. It is very likely that a software system built around encapsulate will be reused in a situation where the automatic polarity assignment fails.

EXAMPLES

Here's a simple file transfer daemon:

server$ faucet 3001 --once --fd3 \
     sh -c 'while ~/src/netpipes4.0/encapsulate --fd 3 -so5i4 \
                sh -c "fname=`cat 0<&4`; echo \$fname; cat < \$fname 1>&5"; \
                do true; done'
client$ hose server 3001 --retry 10 --delay 1 --fd3 \
        sh -c 'while read fname; do \
                ~/src/netpipes4.0/encapsulate --fd 3 -si4o5 \
                        sh -c "echo $fname 1>&5; exec 5>&-; cat 0<&4" \
                || break; done'

Just type the name of the file you want to retrieve into the hose and press return. It will be dumped to stdout. Repeat until enlightened or bored.

TROUBLESHOOTING

Did you specify --client and --server properly? One side should be server, the other side should be client. If you specify them both as server or both as client, you have made a mistake. Do not rely on the automatic polarity detection. While it is theoretically a very good algorithm, it is fooled very easily.

Do all of your channel assignments (--infd et al) match up? If you get these wrong, encapsulate will freak out and drip spooge all over your shoes.

For deadlock avoidance, make sure you are closing channels when you don't need them anymore. Use the >&- redirection operator in sh or bash. Make sure you close it in all of the background processes as well.

Unable to read stdin from a process that has been backgrounded with & ? Bash closes file descriptor 0 for any subprocess that is backgrounded (e.g. (command&) ). You can get around this by copying 0 onto another descriptor, and then copying it back within the backgrounded process.

( ( cat 0<&3 ) & ) 3<&0

SEE ALSO

netpipes (1), http://sunsite.unc.edu/ses/scp.html

The Session Control Protocol document on SunSite was a draft. There is a more recent one that doesn't specify header compression (which I don't use anyway). It may eventually become an RFC. Then again, encapsulate may be the only program which ever implements SCP.

BUGS

encapsulate is not hard to deadlock. Until I add unbounded buffering inside encapsulate, avoid constructing deadlock-vulnerable systems.

The encapsulate included with netpipes 4.0 totally failed to handle the case where no subprocess was specified. No error message would be issued, and the program would do absolutely nothing. The 4.1 version should work.

encapsulate has no other known bugs. I'm sure there are unknown ones because this software is not yet mature; in fact, it's totally wet behind the ears. Break it and send me the pieces.

Well, the command-line argument style is inconsistent with faucet & hose. I'll be updating faucet & hose.

The Linux kernel from the beginning of time up through version 2.0.29 has a problem with sockets being shut down "too fast". This results in loss of data at the end of a stream and an "Error: connection reset by peer" during reads. 2.0.30 supposedly fixes this. This state machine flaw is very likely present in many other OSes, because the strange conditions that exercise it are almost nonexistent in normal applications, but happen all the time in some applications of the NetPipes package. encapsulate can be used to work around this bug in some cases because encapsulate does not perform a shutdown on the network socket ever (it doesn't even do a "close").

CREDITS

Hi Mom! Hi Dad!

COPYRIGHT

Copyright (C) 1997-98 Robert Forsman

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.

AUTHOR

Robert Forsman
thoth@purplefrog.com
Purple Frog Software
http://web.purplefrog.com/~thoth/
netpipes-4.2.orig/faucet.10100644000175000017500000003106006615677334015462 0ustar knoppixknoppix.\" t .\" $Id: faucet.html,v 1.5 1998/10/28 16:07:57 thoth Exp $ .\" Copyright 1992-98 by Robert Forsman .TH FAUCET 1 "October 28, 1998" .SH NAME faucet \- a fixture for a BSD network pipe netpipes 4.2 .SH SYNOPSIS \fBfaucet\fP \fIport\fP (\fB\-\-in\fP|\fB\-\-out\fP|\fB\-\-err\fP|\fB\-\-fd\fP \fIn\fP)+ [\fB\-\-once\fP] [\fB\-\-verbose\fP] [\fB\-\-quiet\fP] [\fB\-\-unix\fP] [\fB\-\-foreignhost\fP \fIaddr\fP] [\fB\-\-foreignport\fP \fIport\fP] [\fB\-\-localhost\fP \fIaddr\fP] [\fB\-\-serial\fP] [\fB\-\-daemon\fP] [\fB\-\-shutdown\fP (r|w) ] [\fB\-\-pidfile\fP \fIfilename\fP] [\fB\-\-noreuseaddr\fP] [\fB\-\-backlog\fP \fIn\fP] [\fB\-\fP[\fBi\fP][\fBo\fP][\fBe\fP][\fB#\fP\fI3\fP[,\fI4\fP[,\fI5\fP...]]][\fBv\fP][\fB1\fP][\fBq\fP][\fBu\fP][\fBd\fP][\fBs\fP]] [\fB\-p\fP \fIforeign\-port\fP] [\fB\-h\fP \fIforeign\-host\fP] [\fB\-H\fP \fIlocal\-host\fP] \fIcommand\fP \fIargs\fP .SH DESCRIPTION \fBfaucet\fP attempts to provide the functionality of pipes over the network. It behaves as the server end of a server\-client connection. When used with \fBhose(1)\fP it can function as a replacement for .nf tar \-cf \- . | rsh other "cd destdir; tar \-xf \-" .fi \fBfaucet\fP and \fBhose\fP are especially useful when you don't have easy non\-interactive access to the destination account (such as a root account where .rhosts are a bad idea). \fBfaucet\fP creates a BSD socket, binds it to the \fIport\fP specified on the command line, and listens for connections. Every time \fBfaucet\fP gets a connection it exec(2)s \fIcommand\fP and its \fIargs\fP with stdin, stdout, stderr, and/or arbitrary file descriptors redirected according to the \fB\-\-in \-\-out \-\-err \-\-fd\fP \fIn\fP flags. \fBfaucet\fP also automagically shuts down the unused half of the connection if only \fB\-\-in\fP is specified or if only \fB\-\-out\fP and/or \fB\-\-err\fP are specified. See the \fB\-\-shutdown\fP option for more information. .SH OPTIONS If the \fB\-\-once\fP flag is specified, \fBfaucet\fP will exec(2) the \fIcommand\fP instead of fork(2)ing and exec(2)ing. \fB\-\-once\fP means that the network pipe is only good for one shot. The \fB\-\-verbose\fP flag specifies that \fBfaucet\fP should print information about connecting hosts. This information includes the numeric host address, host names, and foreign port numbers. The \fB\-\-quiet\fP flag specifies that \fBfaucet\fP should NOT print such info. \fB\-\-quiet\fP is the default. The \fB\-\-unix\fP flag specifies that the \fIport\fP is not an internet port number or service name, but instead it is a file name for a UNIX domain socket. The \fB\-\-foreignhost\fP option specifies that faucet should reject all connections that do not come from the \fIhost\fP machine. Similarly \fB\-\-foreignport\fP specifies that faucet should reject all connections that are not bound on their local machine to the \fIport\fP argument. The above two options allow a crude form of authentication. Note that on UNIX systems only root can bind a socket to a port number below 1024. \fBPlease\fP do not be fooled into thinking this makes faucet secure. There are ways to spoof IP numbers that have been known for years (but only publicized recently). I do think that this method is safe from DNS spoofs, but you probably should have \fBnospoof on\fP in /etc/host.conf anyway. \fB\-\-localhost\fP specifies that the listening socket should be bound to a specific internet address on this host. This is only useful on hosts with several internet numbers. \fB\-\-daemon\fP specifies that the faucet should disassociate from the controlling terminal once it has started listening on the socket. This is done using the setsid() system call. If you don't have setsid on your system, it uses the standard ``close all file descriptors, ioctl TIOCNOTTY, fork() and parent exit'' sequence. \fB\-\-shutdown\fP is used to turn the (normally) bi\-directional socket into a uni\-directional one If the `r' is present, then \fBfaucet\fP will close half the connection to make it a read\-only socket. If we try to write, it will fail. If the remote connection tries to read, it will percieve the socket as closed. If instead the `w' is present, then \fBfaucet\fP will close the other half of the connection to make it a write\-only socket. If we try to read, we will percieve the socket as closed. If the remote connection tries to write, it will fail. The default behavior is to leave both halves open, however the shutdown of half of the connection is automagically done by certain combinations of the \fB\-\-in\fP, \fB\-\-out\fP, and \fB\-\-err\fP flags. To suppress their automagic behavior you can use (respectively) \-\-fd 0, \-\-fd 1, and \-\-fd 2. \fB\-\-shutdown\fP may not be used with some internet servers (such as certain httpds) because they interpret the closing of one half of the connection as a close on the entire connection. This warning applies to \fB\-\-in\fP, \fB\-\-out\fP, and \fB\-\-err\fP. \fB\-\-serial\fP causes faucet to wait for one child to finish before accepting any more connections. Serialization is a very crude form of critical\-section management. \fB\-\-pidfile\fP \fIfilename\fP commands \fBfaucet\fP to write its process id into \fIfilename\fP. This is useful when faucet is part of a larger system and a controlling process might want to kill the faucet. \fB\-\-pidfile\fP functions properly when using the \fB\-\-daemon \fP option. By default, \fBfaucet\fP performs a .nf setsockopt(fd, SOL_SOCKET, SO_REUSEADDR...) .fi which prevents the ``Address in use'' problem that ``plagued'' netpipes versions 4.0 and earlier. \fB\-\-noreuseaddr\fP tells faucet to skip that system call, and revert to pre\-4.1 behavior. Without this call, the socket is not always available for immediate reuse after the faucet exits. \fB\-\-backlog\fP \fIn\fP allows you to specify the second parameter to the listen(2) system call. The default is 5. .SH SHORT FLAGS To reduce the typing requirements for arguments (and to pay homage to the age\-old tradition of UNIX cryptotaxonomy) I have added some short forms of the flags. Here is a correspondence chart: .TS H |lw(0.4i)|lw(1.2i)| |cBw(0.4i)|lBw(1.2i)|. .TB Short Long \fBi\fP \fBin\fP \fBo\fP \fBout\fP \fBe\fP \fBerr\fP \fB#\fP\fIn\fP \fBfd\fP\fIn\fP \fBv\fP \fBverbose\fP \fB1\fP \fBonce\fP \fBq\fP \fBquiet\fP \fBu\fP \fBunix\fP \fBd\fP \fBdaemon\fP \fBs\fP \fBserial\fP \fBp\fP \fBforeignport\fP \fBh\fP \fBforeignhost\fP \fBH\fP \fBlocalhost\fP .TE For example, the following command .nf example$ faucet 3000 \-\-out \-\-verbose \-\-once \-\-foreignhost client echo blah .fi could be written .nf example$ faucet 3000 \-ov1h client echo blah .fi The \fB\-p\fP, \fB\-h\fP, and \fB\-H\fP flags take an argument, but the flags may be grouped into one argument. They then grab the arguments they need from the command line in the order the flags appear. .nf example$ faucet 3000 \-hpHov1 client 2999 example\-le2 echo blah .fi Whereas each \fB\-\-fd\fP word flag required an individual descriptor, the \fB\-#\fP character flag can take multiple descriptors. The following are equivalent: .nf example$ faucet 3000 \-\-fd 0 \-\-fd 1 \-\-verbose \-\-once echo blah example$ faucet 3000 \-#0,1v \-\-once echo blah example$ faucet 3000 \-v1#0,1 echo blah example$ faucet 3000 \-#0,1v1 echo blah .fi Note that you have to pay attention when using the \fB\-#\fP character flag and the \fB\-1\fP character flag in the same argument. Also, remember the special shutdown(2) semantics of \fB\-in\fP and \fB\-out\fP. .SH EXAMPLES This creates a TCP\-IP socket on the local machine bound to port 3000. .nf example$ faucet 3000 \-\-out \-\-verbose tar \-cf \- . .fi Every time some process (from any machine) attempts to connect to port 3000 on this machine the \fBfaucet\fP program will fork(2) a process and the child will exec(2) a .nf tar \-cf \- . .fi The \fB\-\-out\fP option means that the output of the child process will have been redirected into the new socket retrieved by the accept(2) call. \fB\-\-verbose\fP means that faucet will print information about each new connection. This creates a UNIX domain socket in the current directory .nf example$ faucet u\-socket \-\-out \-\-err \-\-once \-\-unix csh \-c \\ "dd if=angio.pgm | funky.perl.script" .fi The \fB\-\-out \-\-err\fP option means that stdout and stderr will be redirected in the child process. The \fB\-\-once\fP option means that the faucet will not fork(2), but exec(2) the process so that only the first process can connect to the u\-socket before the faucet becomes unavailable. This example listens on a socket until the first connection comes through. It then spawns a bidirectional copy that is similar to hose \-slave. .nf faucet 3000 \-1v \-\-fd 3 sh \-c 'cat <&3 & cat >&3 ; sockdown 3' .fi .SH SEE ALSO netpipes (1), hose (1), sockdown (1), getpeername (1), socket (2), bind (2), listen (2), accept (2), shutdown (2), services (5), gethostbyaddr (3) .SH BUGS There is a problem with almost every OS I have used faucet on. Ports are sometimes not recycled swiftly enough. If you kill one faucet and try to start another that wants to listen on the same port you will often see pre\-4.1 faucets print the following warning over and over again: .nf faucet: Address 3000 in use, sleeping 10. faucet: Trying again . . . .fi but you won't actually be able to connect(2) to that port (with \fBhose\fP(1), for example) because you'll get a ``connection refused''. There was also an experimental Linux kernel that NEVER recycled ports (I quickly switched back to my old kernel). I have been informed that this is a side\-effect of the TCP specification and that I should use the SO_REUSEADDR option to work around it, so I do. .SH NOTES Doubtless there are bugs in this program, especially in the unix domain socket portions. I welcome problem reports and would like to make these programs as "clean" (no leftover files, sockets) as possible. 4.1 added \fB\-\-backlog\fP and \fB\-\-noreuseaddr\fP. \fB\-\-noreuseaddr\fP reflects the fact that 4.1 also added the SO_REUSEADDR socket option as the default. 4.0 made the full\-word arguments use \-\- like many GNU programs. They are still available with a single \- for backward\-compatibility. 3.1 added the single\-character flags and the \-pidfile option. It also switched to the setsid(2) system call to detach itself from the process group for the \-daemon flag. I've been hacking at UNIX for years, but there are still some things that I never really learned, and others that have been changing. I need to buy a book. Release 2.3 added support for multi\-homed hosts: hosts with multiple internet numbers (such as gateways). Before this faucet assumed that the first internet number that gethostbyname returned was the only one. \fB\-\-foreignhost\fP authentication was weakened by this inadequacy so I beefed up the algorithms. \fB\-\-foreignhost\fP will accept a connection from any of the internet numbers associated with the host name. .SH CREDITS Thanks to Steve Clift for SGI (SysV) patches. Many people complained about the old way of specifying the command. Thanks to whoever gave me the alternative which is now implemented. It is much better. Randy Fischer finally prodded me into fixing the old lame non\-handling of multi\-homed host. Thanks to all who suggested I use setsid() for \-daemon mode. Thanks to the Spring 1996 UF CIS consulting staff for pointing out the sys_errlist[] declaration conflict on FreeBSD. Sometimes I hate Sun Microsystems. Thanks to Daniel O'Connor for suggesting the \-pidfile flag. Big thanks to Joe Traister for his signal handling patches, strerror surrogate, and other assorted hacks. Thanks to Thomas A. Endo for dropping an SO_REUSEADDR patch in my lap. Otherwise I wouldn't have gotten to it till 2001. .SH COPYRIGHT Copyright (C) 1992\-98 Robert Forsman 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. .SH AUTHOR Robert Forsman thoth@purplefrog.com Purple Frog Software http://web.purplefrog.com/~thoth/ netpipes-4.2.orig/faucet.c0100644000175000017500000004207406615677314015551 0ustar knoppixknoppix/* faucet.c, part of faucet and hose: network pipe utilities Copyright (C) 1992-98 Robert Forsman 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. */ static char info[] = "faucet: a network utility for sockets\nWritten 1992-98 by Robert Forsman \n$Id: faucet.c,v 1.22 1998/08/13 15:01:06 thoth Exp $\n"; #include #include extern int errno; /* I hate the errno header file */ #include #include #include #include #ifdef hpux #include #endif /* defined(hpux) */ #include #include #include #ifdef USE_IOCTL #include /* find the FIOCLEX ioctl */ #ifdef linux #include #else /* defined(linux) */ #ifdef sco #include #else /* defined(sco) */ #include #endif /* defined(sco) */ #endif /* defined(linux) */ #else /* defined(USE_IOCTL) */ #include #include #include #endif /* defined(USE_IOCTL) */ #include #ifndef NOUNIXSOCKETS #include #endif #include #include /* for getrlimit with -daemon option */ #include #include #include "common.h" int mastersocket; #define DOONCE (1<<0) #define DOVERBOSE (1<<1) #ifndef NOUNIXSOCKETS #define DOUNIX (1<<2) #endif #define DODAEMON (1<<3) #define EXITCODE_CONNECTION 127 #define EXITCODE_ARGS 126 #define EXITCODE_FAILED_SYSCALL 125 #define EXITCODE_PIPE 124 int doflags=0; int running=1; struct in_addr ** /* addr_array */ convert_hostname(); char *localhost=NULL; char *foreignhost=NULL,*foreignport=NULL; int foreignPORT; int foreignCOUNT=0; struct in_addr **foreignHOST; int name_to_inet_port(); void usage () { fprintf(stderr,"Usage : %s (--in|--out|--err|--fd N)+ [--once] [--verb(|ose)] [--quiet] [--unix] [--foreignport ] [--foreignhost ] [--localhost ] [--daemon] [--serial] [--shutdown (r|w)] [--pidfile fname] [--noreuseaddr] [--backlog n] -[i][o][e][#3[,4[,5...]]][v][1][q][u][d][s] [-p ] [-h ] [-H ] command args\n", progname); } void nice_shutdown() /* This procedure gets called when we are killed with one of the reasonable signals (TERM, HUP, that kind of thing). The main while loop then terminates and we get a chance to clean up. */ { running = 0; } int setup_socket(name, backlog, reuseaddr) char *name; int backlog; int reuseaddr; /* This procedure creates a socket and handles retries on the inet domain. Sockets seem to "stick" on my system (SunOS [43].x) */ { int sock; int family; #ifdef DOUNIX if (doflags&DOUNIX) family = AF_UNIX; else #endif family = AF_INET; sock = socket(family, SOCK_STREAM, #ifdef DOUNIX (doflags&DOUNIX)?0: #endif IPPROTO_TCP); /* I need a real value for the protocol eventually. IPPROTO_TCP sounds like a good value, but what about AF_UNIX sockets? It seems to have worked so far... */ if (sock <0) { perror("opening stream socket"); exit(EXITCODE_CONNECTION); } if (!bindlocal(sock, name, localhost, family, reuseaddr)) { fprintf(stderr,"%s: error binding stream socket %s (%s)\n", progname,name,strerror(errno)); exit(EXITCODE_CONNECTION); } /* We used to ask for NOFILE (max number of open files) for the size of the connect queue. Linux didn't like it (NOFILE=256) so we hardcoded a smaller value. */ listen(sock, (backlog>0 ? backlog : 5) ); return(sock); } void waitonchild() { int status; int childpid; childpid = wait(&status); } int authorize_address(sin) struct sockaddr *sin; { #ifdef DOUNIX if (doflags&DOUNIX) { struct sockaddr_un *srv = (struct sockaddr_un*)sin; if (foreignport != NULL && 0!=strcmp(foreignport, srv->sun_path)) { if (doflags&DOVERBOSE) { fprintf(stderr, "%s: refusing connection from port %s\n", progname, srv->sun_path); } return 0; } } else #endif { struct sockaddr_in *srv = (struct sockaddr_in*)sin; int i; if (foreignhost) { for (i=0; isin_addr, foreignHOST[i], sizeof(struct in_addr))) break; } if (i>=foreignCOUNT) { if (doflags&DOVERBOSE) { fprintf(stderr, "refusing connection from host "); printhost(stderr, &srv->sin_addr); fprintf(stderr, ".\n"); } return 0; } } if (foreignport!=NULL && foreignPORT != srv->sin_port) { if (doflags&DOVERBOSE) { fprintf(stderr, "refusing connection from port %d.\n", ntohs(srv->sin_port)); } return 0; } } return 1; } /**********************************************************************/ /* since we have flag processing for long and short, we do the same thing in two separate pieces of code. The non-trivial ones we encapsulate in a small function */ void flag_in() { add_fd(0); if (how_shutdown == 0) /* make sure we can read from the socket */ how_shutdown = -1; else if (how_shutdown==-2) how_shutdown = 1; } void flag_out() { add_fd(1); if (how_shutdown == 1) /* make sure we can write to the socket */ how_shutdown = -1; else if (how_shutdown==-2) how_shutdown = 0; } void flag_err() { add_fd(2); if (how_shutdown == 1) /* make sure we can write to the socket */ how_shutdown = -1; else if (how_shutdown==-2) how_shutdown = 0; } int flag_scan_comma_fds(s) char *s; { int rval=0; while (1) { int fd; int n; if (1 != sscanf(s, "%i%n", &fd, &n)) { fprintf(stderr, "%s: parse error in file descriptor list at '%s'\n", progname, s); usage(); exit(EXITCODE_ARGS); } add_fd(fd); rval +=n; s += n; if (*s == ',') { rval++; s++; } else { break; } } return rval; } /**********************************************************************/ int main (argc,argv) int argc; char ** argv; { int rval, i; union { struct sockaddr_in in; #ifdef DOUNIX struct sockaddr_un un; #endif } saddr; struct sockaddr_in *sinp = &saddr.in; #ifdef DOUNIX struct sockaddr_un *sunp = &saddr.un; #endif char **cmd; char *pidfilename=0; /* we'll write our PID in decimal into this file */ FILE *pidfp=0; int serialize=0; int backlog=0; /* parameter to pass to listen(2) */ int reuseaddr=1; /* Shall we set SO_REUSEADDR? */ /* * */ set_progname(argv[0]); if (argc<3) { usage(); exit(EXITCODE_ARGS); } /* parse trailing args */ for (i=2; i0) argument.\n", progname, arg); usage(); exit(EXITCODE_ARGS); } } else { int j; for (j=0; arg[j]; j++) { switch (arg[j]) { case 'i': flag_in(); break; case 'o': flag_out(); break; case 'e': flag_err(); break; case '#': j += flag_scan_comma_fds(arg+j+1); break; case '1': doflags |= DOONCE; break; case 'v': doflags |= DOVERBOSE; break; case 'q': doflags &= ~DOVERBOSE; break; case 'u': #ifdef DOUNIX doflags |= DOUNIX; #else fprintf(stderr, "%s: unix-domain sockets are not supported in this binary.\n", progname); exit(EXITCODE_ARGS); #endif break; case 'p': if (i+1=0) { ioctl(rval, TIOCNOTTY, &rval); close(rval); } } /* it seems printing to a closed FP will kill a process in some OSs. */ freopen("/dev/null", "w", stderr); freopen("/dev/null", "w", stdout); freopen("/dev/null", "r", stdin); #endif { int childpid = fork(); if (childpid<0) { fprintf(stderr, "%s: WAUGH! fork failed while trying to enter -daemon mode. This bodes ill.\n", progname); } else if (childpid>0) exit(0); } #ifndef NO_SETSID setsid(); #endif } if (pidfp) { fprintf(pidfp, "%ld\n", (long) getpid()); fclose(pidfp); } while (running) { { int length; length = sizeof(saddr); rval = accept(mastersocket,(struct sockaddr*)&saddr,&length); } if (rval<0) { if (errno==EWOULDBLOCK) { /* this can't happen, but why take chances? */ fprintf(stderr, "%s: No more connections to talk to.\n",progname); } else if (errno!=EINTR) { fprintf(stderr,"%s: error in accept (%s).", progname,strerror(errno)); exit(EXITCODE_FAILED_SYSCALL); } continue; } if (!authorize_address(&saddr)) { close(rval); continue; } if ( doflags&DOVERBOSE ) { fprintf(stderr, "%s: Got connection from ",progname); #ifdef DOUNIX if ( doflags&DOUNIX ) { puts(sunp->sun_path); } else #endif { printhost(stderr, &sinp->sin_addr); fprintf(stderr, " port %d\n",ntohs(sinp->sin_port)); } } fflush(stdout); if ( doflags&DOONCE || fork()==0 ) { /* XXX should check error return */ /* child process: frob descriptors and exec */ char *s; int duped_stderr; #ifdef DOUNIX if ( (doflags&(DOONCE|DOUNIX)) == (DOONCE|DOUNIX) ) unlink(argv[1]); /* We don't want the unix domain socket anymore */ #endif /* the child doesn't need the master socket fd */ close(mastersocket); /* put stderr somewhere safe temporarily */ duped_stderr = dup(fileno(stderr)); /* but we don't want it to hang around after we exec... */ #ifdef USE_IOCTL ioctl(duped_stderr,FIOCLEX,NULL); #else fcntl(duped_stderr,F_SETFD,FD_CLOEXEC); #endif /* We don't need old stderr hanging around after an exec. The mastersocket has been closed by the dup2 */ dup_n(rval); /* dup the socket onto all the chosen file descriptors */ close(rval); /* rval has been properly duplicated */ execvp(cmd[0], cmd); s ="exec failed\n"; write(duped_stderr,s,strlen(s)); exit(0); } else { /* parent: close socket. Signal will arrive upon death of child. */ close(rval); if (serialize) { int status; pid_t pid; pid = wait(&status); /* child has exited */ if (pid == -1) { fprintf(stderr, "%s: error serializing (waiting on child) ", progname); perror(""); } } } } if (pidfilename != 0) { if (doflags&DOVERBOSE) fprintf(stderr, "%s: removing pid file %s\n", progname, pidfilename); unlink(pidfilename); /* if it fails, we just don't care */ } #ifdef DOUNIX /* clean up the socket when we're done */ if (doflags&DOUNIX) unlink(argv[1]); #endif close(mastersocket); return 0; } netpipes-4.2.orig/faucet.html0100644000175000017500000003304006615677314016264 0ustar knoppixknoppix FAUCET 1 "October 28, 1998"

NAME

faucet - a fixture for a BSD network pipe

netpipes 4.2

SYNOPSIS

faucet port (--in|--out|--err|--fd n)+ [--once] [--verbose] [--quiet] [--unix] [--foreignhost addr] [--foreignport port] [--localhost addr] [--serial] [--daemon] [--shutdown (r|w) ] [--pidfile filename] [--noreuseaddr] [--backlog n] [-[i][o][e][#3[,4[,5...]]][v][1][q][u][d][s]] [-p foreign-port] [-h foreign-host] [-H local-host] command args

DESCRIPTION

faucet attempts to provide the functionality of pipes over the network. It behaves as the server end of a server-client connection. When used with hose(1) it can function as a replacement for

tar -cf - . | rsh other "cd destdir; tar -xf -"
faucet and hose are especially useful when you don't have easy non-interactive access to the destination account (such as a root account where .rhosts are a bad idea).

faucet creates a BSD socket, binds it to the port specified on the command line, and listens for connections.

Every time faucet gets a connection it exec(2)s command and its args with stdin, stdout, stderr, and/or arbitrary file descriptors redirected according to the --in --out --err --fd n flags. faucet also automagically shuts down the unused half of the connection if only --in is specified or if only --out and/or --err are specified. See the --shutdown option for more information.

OPTIONS

If the --once flag is specified, faucet will exec(2) the command instead of fork(2)ing and exec(2)ing. --once means that the network pipe is only good for one shot.

The --verbose flag specifies that faucet should print information about connecting hosts. This information includes the numeric host address, host names, and foreign port numbers. The --quiet flag specifies that faucet should NOT print such info. --quiet is the default.

The --unix flag specifies that the port is not an internet port number or service name, but instead it is a file name for a UNIX domain socket.

The --foreignhost option specifies that faucet should reject all connections that do not come from the host machine. Similarly --foreignport specifies that faucet should reject all connections that are not bound on their local machine to the port argument. The above two options allow a crude form of authentication. Note that on UNIX systems only root can bind a socket to a port number below 1024.

Please do not be fooled into thinking this makes faucet secure. There are ways to spoof IP numbers that have been known for years (but only publicized recently). I do think that this method is safe from DNS spoofs, but you probably should have nospoof on in /etc/host.conf anyway.

--localhost specifies that the listening socket should be bound to a specific internet address on this host. This is only useful on hosts with several internet numbers.

--daemon specifies that the faucet should disassociate from the controlling terminal once it has started listening on the socket. This is done using the setsid() system call. If you don't have setsid on your system, it uses the standard ``close all file descriptors, ioctl TIOCNOTTY, fork() and parent exit'' sequence.

--shutdown is used to turn the (normally) bi-directional socket into a uni-directional one If the `r' is present, then faucet will close half the connection to make it a read-only socket. If we try to write, it will fail. If the remote connection tries to read, it will percieve the socket as closed. If instead the `w' is present, then faucet will close the other half of the connection to make it a write-only socket. If we try to read, we will percieve the socket as closed. If the remote connection tries to write, it will fail. The default behavior is to leave both halves open, however the shutdown of half of the connection is automagically done by certain combinations of the --in, --out, and --err flags. To suppress their automagic behavior you can use (respectively) --fd 0, --fd 1, and --fd 2.

--shutdown may not be used with some internet servers (such as certain httpds) because they interpret the closing of one half of the connection as a close on the entire connection. This warning applies to --in, --out, and --err.

--serial causes faucet to wait for one child to finish before accepting any more connections. Serialization is a very crude form of critical-section management.

--pidfile filename commands faucet to write its process id into filename. This is useful when faucet is part of a larger system and a controlling process might want to kill the faucet. --pidfile functions properly when using the --daemon option.

By default, faucet performs a

setsockopt(fd, SOL_SOCKET, SO_REUSEADDR...)
which prevents the ``Address in use'' problem that ``plagued'' netpipes versions 4.0 and earlier. --noreuseaddr tells faucet to skip that system call, and revert to pre-4.1 behavior. Without this call, the socket is not always available for immediate reuse after the faucet exits.

--backlog n allows you to specify the second parameter to the listen(2) system call. The default is 5.

SHORT FLAGS

To reduce the typing requirements for arguments (and to pay homage to the age-old tradition of UNIX cryptotaxonomy) I have added some short forms of the flags. Here is a correspondence chart:
Short Long
i in
o out
e err
#n fdn
v verbose
1 once
q quiet
u unix
d daemon
s serial
p foreignport
h foreignhost
H localhost

For example, the following command

example$ faucet 3000 --out --verbose --once --foreignhost client echo blah

could be written

example$ faucet 3000 -ov1h client echo blah

The -p, -h, and -H flags take an argument, but the flags may be grouped into one argument. They then grab the arguments they need from the command line in the order the flags appear.

example$ faucet 3000 -hpHov1 client 2999 example-le2 echo blah

Whereas each --fd word flag required an individual descriptor, the -# character flag can take multiple descriptors. The following are equivalent:

example$ faucet 3000 --fd 0 --fd 1 --verbose --once echo blah
example$ faucet 3000 -#0,1v --once echo blah
example$ faucet 3000 -v1#0,1 echo blah
example$ faucet 3000 -#0,1v1 echo blah

Note that you have to pay attention when using the -# character flag and the -1 character flag in the same argument. Also, remember the special shutdown(2) semantics of -in and -out.

EXAMPLES

This creates a TCP-IP socket on the local machine bound to port 3000.

example$ faucet 3000 --out --verbose tar -cf - .
Every time some process (from any machine) attempts to connect to port 3000 on this machine the faucet program will fork(2) a process and the child will exec(2) a
tar -cf - .
The --out option means that the output of the child process will have been redirected into the new socket retrieved by the accept(2) call. --verbose means that faucet will print information about each new connection.

This creates a UNIX domain socket in the current directory

example$ faucet u-socket --out --err --once --unix csh -c \
	"dd if=angio.pgm | funky.perl.script" 
The --out --err option means that stdout and stderr will be redirected in the child process. The --once option means that the faucet will not fork(2), but exec(2) the process so that only the first process can connect to the u-socket before the faucet becomes unavailable.

This example listens on a socket until the first connection comes through. It then spawns a bidirectional copy that is similar to hose -slave.

faucet 3000 -1v --fd 3 sh -c 'cat <&3 & cat >&3 ; sockdown 3'

SEE ALSO

netpipes (1), hose (1), sockdown (1), getpeername (1), socket (2), bind (2), listen (2), accept (2), shutdown (2), services (5), gethostbyaddr (3)

BUGS

There is a problem with almost every OS I have used faucet on. Ports are sometimes not recycled swiftly enough. If you kill one faucet and try to start another that wants to listen on the same port you will often see pre-4.1 faucets print the following warning over and over again:

faucet: Address 3000 in use, sleeping 10.
faucet: Trying again . . .

but you won't actually be able to connect(2) to that port (with hose(1), for example) because you'll get a ``connection refused''.

There was also an experimental Linux kernel that NEVER recycled ports (I quickly switched back to my old kernel).

I have been informed that this is a side-effect of the TCP specification and that I should use the SO_REUSEADDR option to work around it, so I do.

NOTES

Doubtless there are bugs in this program, especially in the unix domain socket portions. I welcome problem reports and would like to make these programs as "clean" (no leftover files, sockets) as possible.

4.1 added --backlog and --noreuseaddr. --noreuseaddr reflects the fact that 4.1 also added the SO_REUSEADDR socket option as the default.

4.0 made the full-word arguments use -- like many GNU programs. They are still available with a single - for backward-compatibility.

3.1 added the single-character flags and the -pidfile option. It also switched to the setsid(2) system call to detach itself from the process group for the -daemon flag. I've been hacking at UNIX for years, but there are still some things that I never really learned, and others that have been changing. I need to buy a book.

Release 2.3 added support for multi-homed hosts: hosts with multiple internet numbers (such as gateways). Before this faucet assumed that the first internet number that gethostbyname returned was the only one. --foreignhost authentication was weakened by this inadequacy so I beefed up the algorithms. --foreignhost will accept a connection from any of the internet numbers associated with the host name.

CREDITS

Thanks to Steve Clift <clift@ml.csiro.au> for SGI (SysV) patches.

Many people complained about the old way of specifying the command. Thanks to whoever gave me the alternative which is now implemented. It is much better.

Randy Fischer <fischer@ucet.ufl.edu> finally prodded me into fixing the old lame non-handling of multi-homed host.

Thanks to all who suggested I use setsid() for -daemon mode.

Thanks to the Spring 1996 UF CIS consulting staff <consult@cis.ufl.edu> for pointing out the sys_errlist[] declaration conflict on FreeBSD. Sometimes I hate Sun Microsystems.

Thanks to Daniel O'Connor <doconnor@adam.ist.flinders.edu.au> for suggesting the -pidfile flag.

Big thanks to Joe Traister <traister@gate.net> for his signal handling patches, strerror surrogate, and other assorted hacks.

Thanks to Thomas A. Endo <tendo@netcom.com> for dropping an SO_REUSEADDR patch in my lap. Otherwise I wouldn't have gotten to it till 2001.

COPYRIGHT

Copyright (C) 1992-98 Robert Forsman

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.

AUTHOR

Robert Forsman
thoth@purplefrog.com
Purple Frog Software
http://web.purplefrog.com/~thoth/ netpipes-4.2.orig/getpeername.10100644000175000017500000001553706615677335016523 0ustar knoppixknoppix.\" $Id: getpeername.html,v 1.3 1998/10/28 16:07:57 thoth Exp $ Copyright 1995-98 by Robert Forsman .TH GETPEERNAME 1 "March 18, 1998" .SH NAME getpeername \- get information about this or that end of the socket's connection netpipes 4.2 .SH SYNOPSIS \fBgetpeername\fP [ \fB\-verbose\fP ] [ \fB\-sock\fP ] [ \fIfd\fP ] \fBgetsockname\fP [ \fB\-verbose\fP ] [ \fB\-peer\fP ] [ \fIfd\fP ] .SH DESCRIPTION This is \fBnot\fP the manual page for the getpeername system call. That manual page is in section 2. You can access it using a command like "man 2 getpeername" or "man \-s 2 getpeername". I apologize for the confusion. \fBgetpeername\fP performs a getpeername(2) system call on one of its file descriptors specified by \fIfd\fP and prints out the results. The default \fIfd\fP is 0 (stdin). You may cause \fBgetpeername\fP to behave like \fBgetsockname\fP by providing the \-sock argument. \fBgetsockname\fP performs a getsockname(2) system call on one of its file descriptors specified by \fIfd\fP and prints out the results. The default \fIfd\fP is 0 (stdin). You may cause \fBgetsockname\fP to behave like \fBgetpeername\fP by providing the \-peer argument. There is a severe limitation of \fBgetpeername\fP. If the remote process has closed the connection, \fBgetpeername\fP will fail with a `Socket is not connected' error. This will happen with dismaying frequency when the remote process is not dependent upon the local process for input and it is only sending small amounts of output before closing the connection. Hopefully the practical uses of \fBgetpeername\fP (if there are any) will not exercise this problem. You can use \fBgetpeername\fP to find out the address of the opposite end of a socket. You can use \fBgetsockname\fP to find out the address of the local end of a socket. They are in fact the same program with different names. We will refer to both of them by the name \fBgetpeername\fP in the following description. \fBgetpeername\fP knows how to display peer information about UNIX and Internet sockets. If you try to use it on another type of socket, it will fail with an "unknown address family" error. If you regularly deal with strange sockets and wish \fBgetpeername\fP to work with them, send me email. If the socket is a UNIX domain socket, then \fBgetpeername\fP prints the name of the file (which is the port) on a single line. If \fB\-verbose\fP was specified, \fBgetpeername\fP prints a more detailed report consisting of the word `Unix' on the first line, the word `Port' on the second line, and the name of the file on the third line. If the socket is an Internet socket, then \fBgetpeername\fP prints the port number on the first line and the numeric address on the second line. If \fB\-verbose\fP was specified, \fBgetpeername\fP prints a more detailed report consisting of the word `Internet' on the first line, the word `Port' on the second line, the port numer on the third line, the word `Host' on the fourth line. Starting on the fifth line it prints all the numeric internet addresses returned by the gethostbyaddr(3) library routine. On the rest of the lines it prints all the host names. .SH EASTER EGG If you specify \fB\-verbose\fP twice, the program will print a copyright notice. .SH EXAMPLES I originally designed \fBgetpeername\fP so that a faucet\-spawned shell script could find out who was talking to it (and maybe perform access control). I added getsockname for completeness. Now I realize that getsockname is useful for multi\-homing services. However, most software that you want to understand multi\-homing (httpd, ftpd) is already capable of doing it, and much more efficiently than a script wrapper. Still, it might come in handy some day. .nf client$ hose mail.cise.ufl.edu smtp \-\-in ./getpeername 25 128.227.205.210 .fi You connected to mail.cis.ufl.edu on the SMTP port (port 25). For a verbose report: .nf client$ hose mail.cise.ufl.edu smtp \-\-in ./getpeername \-v Internet Port 25 Host 128.227.205.210 fireant.cise.ufl.edu .fi Now let's give an example of a race condition which will cause \fBgetpeername\fP to fail: .nf client$ hose web.cise.ufl.edu 80 \-in ./getpeername ./getpeername: getpeername failed on descriptor 0: Socket is not connected .fi The HTTP daemon tries to read a request, finds that half of the full duplex connection closed (by the special behavior of the \-in option on hose(1)) and drops the connection before \fBgetpeername\fP can query the file descriptor. We can cause the HTTP daemon to wait for us by leaving both halves of the duplex connection open. .nf client$ hose web.cise.ufl.edu 80 \-fd0 ./getpeername \-v Internet Port 80 Host 128.227.205.206 flood.cise.ufl.edu .fi And, finally, let's extract some useful information from our socket. .nf client$ hose web.cise.ufl.edu 80 \-fd0 sh \-c " ./getpeername \-v | \\ tail +5 | egrep \-v '^[0\-9.]*$' | head \-1" flood.cise.ufl.edu .fi .SH ERRORS \fBSocket operation on non\-socket\fP The \fIfd\fP you specified does not refer to a socket, or refers to a socket that has been closed. This happens when you run \fBgetpeername\fP by itself (it is unlikely that any of the file descriptors attached to an interactive shell are actually sockets), or if you goof up your faucet/hose command and forgot to dup(2) one of your descriptors, or if the remote machine manages to close the connection before \fBgetpeername\fP could run. \fBBad file number\fP You gave it a bad file number for \fIfd\fP. If you have enough skill to actually generate this error, you probably know what is wrong. If you encounter any other errors, clue me in. .SH SEE ALSO netpipes (1), faucet (1), hose (1), sockdown (1), socket (2), shutdown (2), .SH BUGS These programs are vulnerable to reverse DNS lookup spoofing. You probably want to add ``nospoof on'' to your /etc/host.conf. .SH NOTES Just avoid doing anything funky like passing \fBgetpeername\fP strings and it should serve you well. DOH! 3.0 didn't use the ntohs macro on the port numbers so the output was bogus on machines with non\-network\-order port numbers (like Linux\-i386). 3.1 fixed this. .SH CREDITS "Hi Mom! Hi Dad!" .SH COPYRIGHT Copyright (C) 1995\-98 Robert Forsman 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. .SH AUTHOR Robert Forsman thoth@purplefrog.com Purple Frog Software http://web.purplefrog.com/~thoth/ netpipes-4.2.orig/getpeername.c0100644000175000017500000001023306615677314016566 0ustar knoppixknoppix/* getpeername.c, part of faucet and hose: network pipe utilities Copyright (C) 1995-98 Robert Forsman 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. */ static char info[] = "getpeername: a network utility for sockets\nWritten 1995-98 by Robert Forsman \n"; #include #include #include extern int errno; /* I hate the errno header file */ #include #include #include #ifndef NOUNIXSOCKETS #include #endif #include #include #include "common.h" void usage() { fprintf(stderr, "Usage: %s [ -verbose ] [ fd# ]\n", progname); } int getpeername(); int getsockname(); int main(argc, argv) int argc; char **argv; { int i; int peer_not_sock = 1; int fd = 0; /* assume socket is attached to stdin. (if it's attached to stdout, our output will go over the socket) */ int verbose=0; set_progname(argv[0]); if (0==strcmp(progname + strlen(progname) - 11, "getsockname") && (strlen(progname)<12 || progname[strlen(progname)-12] == '/')) peer_not_sock = 0; for (i=1; i1) { emit_version("getpeername", 1995); } { union { struct sockaddr base; struct sockaddr_in in; #ifndef NOUNIXSOCKETS struct sockaddr_un un; #endif } saddr; struct sockaddr_in *sinp = &saddr.in; #ifndef NOUNIXSOCKETS struct sockaddr_un *sunp = &saddr.un; #endif int saddrlen = sizeof(saddr); int (*f)(); char *name; if (peer_not_sock) { f = getpeername; name = "peer"; } else { f = getsockname; name = "sock"; } if (0!= f(fd, &saddr, &saddrlen)) { fprintf(stderr, "%s: get%sname failed on descriptor %d: ", progname, name, fd); perror(""); exit(1); } #ifndef NOUNIXSOCKETS if (saddr.base.sa_family == AF_UNIX) { if (verbose) puts("Unix\nPort"); puts(sunp->sun_path); /* with newline */ } else #endif if (saddr.base.sa_family == AF_INET) { if (verbose) puts("Internet\nPort"); printf("%d\n", ntohs(sinp->sin_port)); if (verbose) puts("Host"); { struct in_addr* addr = &sinp->sin_addr; int i; printf("%d", ((u_char*)addr)[0]); for (i=1; isin_addr, sizeof(sinp->sin_addr), AF_INET); if (host) { int j,k; for (j=0; host->h_addr_list[j]; j++) { struct in_addr *ia = (struct in_addr *)host->h_addr_list[j]; if (0==memcmp(host->h_addr_list[j], &sinp->sin_addr, host->h_length)) { continue; /* skip this one */ } printf("%d", ((u_char*)ia)[0]); for (k=1; kh_name); for (j=0; host->h_aliases[j]; j++) { puts(host->h_aliases[j]); } } else { puts(" (no name for host)"); } } } else { fprintf(stderr, "%s: unknown address family (%d) returned by get%sname\n", progname, saddr.base.sa_family, name); } } return 0; } netpipes-4.2.orig/getpeername.html0100644000175000017500000001646706615677314017327 0ustar knoppixknoppix GETPEERNAME 1 "March 18, 1998"

NAME

getpeername - get information about this or that end of the socket's connection

netpipes 4.2

SYNOPSIS

getpeername [ -verbose ] [ -sock ] [ fd ]

getsockname [ -verbose ] [ -peer ] [ fd ]

DESCRIPTION

This is not the manual page for the getpeername system call. That manual page is in section 2. You can access it using a command like "man 2 getpeername" or "man -s 2 getpeername". I apologize for the confusion.

getpeername performs a getpeername(2) system call on one of its file descriptors specified by fd and prints out the results. The default fd is 0 (stdin). You may cause getpeername to behave like getsockname by providing the -sock argument.

getsockname performs a getsockname(2) system call on one of its file descriptors specified by fd and prints out the results. The default fd is 0 (stdin). You may cause getsockname to behave like getpeername by providing the -peer argument.

There is a severe limitation of getpeername. If the remote process has closed the connection, getpeername will fail with a `Socket is not connected' error. This will happen with dismaying frequency when the remote process is not dependent upon the local process for input and it is only sending small amounts of output before closing the connection. Hopefully the practical uses of getpeername (if there are any) will not exercise this problem.

You can use getpeername to find out the address of the opposite end of a socket. You can use getsockname to find out the address of the local end of a socket. They are in fact the same program with different names. We will refer to both of them by the name getpeername in the following description.

getpeername knows how to display peer information about UNIX and Internet sockets. If you try to use it on another type of socket, it will fail with an "unknown address family" error. If you regularly deal with strange sockets and wish getpeername to work with them, send me email.

If the socket is a UNIX domain socket, then getpeername prints the name of the file (which is the port) on a single line. If -verbose was specified, getpeername prints a more detailed report consisting of the word `Unix' on the first line, the word `Port' on the second line, and the name of the file on the third line.

If the socket is an Internet socket, then getpeername prints the port number on the first line and the numeric address on the second line. If -verbose was specified, getpeername prints a more detailed report consisting of the word `Internet' on the first line, the word `Port' on the second line, the port numer on the third line, the word `Host' on the fourth line. Starting on the fifth line it prints all the numeric internet addresses returned by the gethostbyaddr(3) library routine. On the rest of the lines it prints all the host names.

EASTER EGG

If you specify -verbose twice, the program will print a copyright notice.

EXAMPLES

I originally designed getpeername so that a faucet-spawned shell script could find out who was talking to it (and maybe perform access control). I added getsockname for completeness. Now I realize that getsockname is useful for multi-homing services. However, most software that you want to understand multi-homing (httpd, ftpd) is already capable of doing it, and much more efficiently than a script wrapper. Still, it might come in handy some day.

client$ hose mail.cise.ufl.edu smtp --in ./getpeername
25
128.227.205.210

You connected to mail.cis.ufl.edu on the SMTP port (port 25). For a verbose report:

client$ hose mail.cise.ufl.edu smtp --in ./getpeername -v
Internet
Port
25
Host
128.227.205.210
fireant.cise.ufl.edu

Now let's give an example of a race condition which will cause getpeername to fail:

client$ hose web.cise.ufl.edu 80 -in ./getpeername
./getpeername: getpeername failed on descriptor 0: Socket is not connected

The HTTP daemon tries to read a request, finds that half of the full duplex connection closed (by the special behavior of the -in option on hose(1)) and drops the connection before getpeername can query the file descriptor. We can cause the HTTP daemon to wait for us by leaving both halves of the duplex connection open.

client$ hose web.cise.ufl.edu 80 -fd0 ./getpeername -v
Internet
Port
80
Host
128.227.205.206
flood.cise.ufl.edu

And, finally, let's extract some useful information from our socket.

client$ hose web.cise.ufl.edu 80 -fd0 sh -c " ./getpeername -v | \
	tail +5 | egrep -v '^[0-9.]*$' | head -1"
flood.cise.ufl.edu

ERRORS

Socket operation on non-socket The fd you specified does not refer to a socket, or refers to a socket that has been closed. This happens when you run getpeername by itself (it is unlikely that any of the file descriptors attached to an interactive shell are actually sockets), or if you goof up your faucet/hose command and forgot to dup(2) one of your descriptors, or if the remote machine manages to close the connection before getpeername could run.

Bad file number You gave it a bad file number for fd. If you have enough skill to actually generate this error, you probably know what is wrong.

If you encounter any other errors, clue me in.

SEE ALSO

netpipes (1), faucet (1), hose (1), sockdown (1), socket (2), shutdown (2),

BUGS

These programs are vulnerable to reverse DNS lookup spoofing. You probably want to add ``nospoof on'' to your /etc/host.conf.

NOTES

Just avoid doing anything funky like passing getpeername strings and it should serve you well.

DOH! 3.0 didn't use the ntohs macro on the port numbers so the output was bogus on machines with non-network-order port numbers (like Linux-i386). 3.1 fixed this.

CREDITS

"Hi Mom! Hi Dad!"

COPYRIGHT

Copyright (C) 1995-98 Robert Forsman

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.

AUTHOR

Robert Forsman
thoth@purplefrog.com
Purple Frog Software
http://web.purplefrog.com/~thoth/ netpipes-4.2.orig/hose.10100644000175000017500000002332106615677342015151 0ustar knoppixknoppix.\" t .\" $Id: hose.html,v 1.4 1998/10/28 16:07:57 thoth Exp $ .\" Copyright 1992-98 by Robert Forsman .TH HOSE 1 "October 28, 1998" .SH NAME hose \- the client end of a BSD network pipe netpipes 4.2 .SH SYNOPSIS \fBhose\fP \fIhostname\fP \fIport\fP (\fB\-\-in\fP|\fB\-\-out\fP|\fB\-\-err\fP|\fB\-\-fd\fP \fIn\fP|\fB\-\-slave\fP|\fB\-\-netslave\fP|\fB\-\-netslave1\fP|\fB\-\-netslave2\fP) [\fB\-\-verbose\fP] [\fB\-\-unix\fP] [\fB\-\-localport\fP \fIport\fP] [\fB\-\-localhost\fP \fIaddr\fP] [\fB\-\-retry\fP \fIn\fP] [\fB\-\-delay\fP \fIn\fP] [\fB\-\-shutdown\fP [r|w][a] ] [\fB\-\-noreuseaddr\fP] [\fB\-\fP[\fBi\fP][\fBo\fP][\fBe\fP][\fB#\fP\fI3\fP[,\fI4\fP[,\fI5\fP...]]][\fBs\fP][\fBv\fP][\fBu\fP]] [\fB\-p\fP \fIlocal\-port\fP] [\fB\-h\fP \fIlocal\-host\fP] \fIcommand\fP \fIargs\fP .SH DESCRIPTION \fBhose\fP attempts to provide the functionality of pipes over the network. It behaves as the client end of a server\-client connection. When used with \fBfaucet(1)\fP it can function as a replacement for .nf tar \-cf \- . | rsh other "cd destdir; tar \-xf \-" .fi \fBfaucet\fP and \fBhose\fP are especially useful when you don't have easy non\-interactive access to the destination machine. .SH OPTIONS \fBhose\fP creates a BSD socket and, if the \fB\-\-localport\fP option is used, binds it to the port number (or service name) specified immediately afterwards. If \fB\-\-localhost\fP is also specified then its argument is a local address to bind to. ( \fB\-\-localhost\fP is only useful on machines with multiple IP addresses.) \fBhose\fP then tries to connect to the foreign machine \fIhostname\fP with foreign port \fIport.\fP If successful \fBhose\fP redirects the socket to stdin, stdout, stderr, and/or arbitrary file descriptors according to the \fB\-\-in \-\-out \-\-err \-\-fd \fIn\fP\fP flags. \fBhose\fP also automagically shuts down the unused half of the connection if only \fB\-\-in\fP is specified or if only \fB\-\-out\fP and/or \fB\-\-err\fP are specified. See the \fB\-\-shutdown\fP option for more information. \fBhose\fP then exec(2)s a \fIcommand\fP with \fIargs\fP. However, the \fB\-\-slave\fP flag turns \fBhose\fP into a primitive sort of telnet. The \fIcommand\fP is ignored. Instead, \fBhose\fP goes into a loop where it copies bytes from stdin to the socket, and bytes from the socket to stdout. This is actually more useful than telnet because telnet tries to perform interpretation on the byte stream and generally gets in your way. \fBhose\fP just passes bytes without mucking with them. The \fB\-\-netslave*\fP options are variants on the \fB\-\-slave\fP theme. Whereas \fB\-\-slave\fP will continue to forward data in one direction even after the other has encountered EOF, \fB\-\-netslave\fP variants are more aggressive in closing the entire socket. Before closing the socket, it attempts to flush any data already in its own buffer. \fB\-\-slave\fP performs the shutdown(2) system call when it encounters EOF on one direction, but the \fB\-\-netslave\fP variants don't because some network daemons are confused by it. \fB\-\-netslave\fP closes down the connection when it encounters EOF in either direction. \fB\-\-netslave1\fP closes down the connection when it encounters EOF while reading stdin. Any data unread on the socket will be ignored. If it merely encounters EOF on the socket, it will continue to read from stdin. \fB\-\-netslave2\fP closes down the connection when it encounters EOF while reading from the socket. Any data unread on stdin will be ignored. If it merely encounters EOF on stdin, it will continue to read from the socket. This mode can be useful with some web servers. The \fB\-\-verbose\fP flag specifies that \fBhose\fP should print information about the host it connects to. This information includes the numeric host address, host names, and foreign port numbers. The \fB\-\-unix\fP flag specifies that the \fIport\fP is not an internet port number or service name, but instead it is a filename for a UNIX domain socket. This option may be simulated by using \fB\-unix\-\fP as the host name to connect to, or by renaming the \fBhose\fP program to \fBuhose\fP. \fB\-\-retry\fP \fIn\fP allows the user to specify that \fBhose\fP should retry the connect(2) call for \fIn\fP times (or forever if \fIn\fP is negative). \fB\-\-delay\fP \fIn\fP specifies how many seconds to delay between tries. \fB\-\-shutdown\fP is used to control two behaviors. The first set is controlled by the `r' and `w' flags. If the `r' is present, then \fBhose\fP will close half the connection to make it a read\-only socket. If the child tries to write, it will fail. If the remote connection tries to read, it will percieve the socket as closed. If instead the `w' is present, then \fBhose\fP will close the other half of the connection to make it a write\-only socket. If the child tries to read, it will percieve the socket as closed. If the remote connection tries to write, it will fail. The default behavior is to leave both halves open, however the shutdown of half of the connection is automagically done by certain combinations of the \fB\-\-in\fP, \fB\-\-out\fP, and \fB\-\-err\fP flags. To suppress their automagic behavior you can use (respectively) \-\-fd 0, \-\-fd 1, and \-\-fd 2. The other behavior is controlled by the `a' flag. If the `a' flag is present then \fBhose\fP will fork(2) before execcing the \fIcommand\fP and when the child exits it will perform a shutdown(2) with how=2. This closes both halves of the connection. This option is not necessary for most applications since the closing of the file descriptors is detected by the remote process, but some less sophisticated network devices (such as printers) require a shutdown(2) for proper operation. To make things perfectly clear, the list of acceptable arguments to the \fB\-\-shutdown\fP option are `r', `w', `ra', `wa', `a'. By default, \fBhose\fP performs a .nf setsockopt(fd, SOL_SOCKET, SO_REUSEADDR...) .fi which prevents the ``Address in use'' problem that ``plagued'' netpipes versions 4.0 and earlier. \fB\-\-noreuseaddr\fP tells \fBhose\fP to skip that system call, and revert to pre\-4.1 behavior. Without this call, the port is not always available for immediate reuse after the \fBhose\fP exits. .SH SHORT FLAGS To reduce the typing requirements for arguments (and to pay homage to the age\-old tradition of UNIX cryptotaxonomy) I have added some short forms of the flags. Here is a correspondence chart: .TS H |lw(0.4i)|lw(1.2i)| |cw(0.4i)|lw(1.2i)|. .TB Short Long \fBi\fP \fBin\fP \fBo\fP \fBout\fP \fBe\fP \fBerr\fP \fB#\fP\fIn\fP \fBfd\fP\fIn\fP \fBs\fP \fBslave\fP \fBv\fP \fBverbose\fP \fBq\fP \fBquiet\fP \fBu\fP \fBunix\fP \fBp\fP \fBlocalport\fP \fBh\fP \fBlocalhost\fP .TE See faucet(1) for a more detailed discussion of short flags. Their behavior should be unsurprising. The flags that require separate arguments follow in the tradition of tar(1). .SH EXAMPLES This will connect to port 3000 on the machine reef and connect the socket to the stdin of a tar command. .nf example$ hose reef 3000 \-\-in tar \-xf \- . .fi The command actually exec(2)ed by the \fBhose\fP program is .nf tar \-xf \- . .fi The \fB\-\-in\fP option means that the input of the child process will have been redirected into the socket connected to reef. This connects to a UNIX domain socket in the current directory .nf example$ hose \-\-unix\- u\-socket \-\-in sh \-c \\ "unfunky.perl.script | dd of=sample.pgm" .fi The socket provides input to the sh command. .SH SEE ALSO netpipes (1), faucet (1), sockdown (1), getpeername (1), socket (2), bind (2), connect (2), shutdown (2), services (5), gethostbyaddr (3) .SH NOTES Doubtless there are bugs in this program, especially in the unix domain socket portions. I welcome problem reports and would like to make these programs as "clean" (no leftover files, sockets) as possible. 4.0 made the full\-word arguments use \-\- like many GNU programs. They are still available with a single \- for backward\-compatibility. 3.1 added the single\-character flags. Release 2.3 added support for multi\-homed hosts: hosts with multiple internet numbers (such as gateways). Before this faucet assumed that the first internet number that gethostbyname returned was the only one. \fB\-\-foreignport\fP authentication was weakened by this inadequacy so I beefed up the algorithms. \fB\-\-foreignport\fP will accept a connection from any of the internet numbers associated with the host name. .SH CREDITS Thanks to Steve Clift for SGI (SysV) patches. Many people complained about the old way of specifying the command. Thanks to whoever gave me the alternative which is now implemented. It is much better. Thanks to Sten Drescher for the \-\-retry and \-\-delay patches and giving me the idea for the \-\-shutdown option. Evidently some printer doesn't appreciate the socket being close(2)d. Randy Fischer finally prodded me into fixing the old lame non\-handling of multi\-homed host. .SH COPYRIGHT Copyright (C) 1992\-98 Robert Forsman 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. .SH AUTHOR Robert Forsman thoth@purplefrog.com Purple Frog Software http://web.purplefrog.com/~thoth/ netpipes-4.2.orig/hose.c0100644000175000017500000004312006615677314015231 0ustar knoppixknoppix/* $Id: hose.c,v 1.25 1998/10/28 15:52:23 thoth Exp $, part of faucet and hose: network pipe utilities Copyright (C) 1992-98 Robert Forsman 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. */ static char info[] = "hose: a network utility for sockets\nWritten 1992-98 by Robert Forsman \n$Id: hose.c,v 1.25 1998/10/28 15:52:23 thoth Exp $\n"; #include #include #include #ifdef hpux #include #endif #include #include #include #include #ifdef USE_IOCTL #include /* find the FIOCLEX ioctl */ #ifdef linux #include #else /* defined(linux) */ #ifdef sco #include #else /* defined(sco) */ #include #endif /* defined(sco) */ #endif /* defined(linux) */ #else /* defined(USE_IOCTL) */ #include #endif /* defined(USE_IOCTL) */ #include #include #include #ifndef NOUNIXSOCKETS #include #endif #include #include #include #include #ifdef AIX #include #endif #include "memmove.h" #include "common.h" #ifndef NOUNIXSOCKETS #define DOUNIX (1<<0) #endif #define DOVERBOSE (1<<1) #define DOJAM (1<<2) #define DOSLAVE (1<<3) #define DONETSLAVE_CT (1<<4) #define DONETSLAVE_CF (1<<5) #define DONETSLAVE (DONETSLAVE_CT | DONETSLAVE_CF) #define EXITCODE_CONNECTION 127 #define EXITCODE_ARGS 126 #define EXITCODE_FAILED_SYSCALL 125 #define EXITCODE_PIPE 124 struct in_addr ** /* addr_array */ convert_hostname(); long doflags=0; int retry=0; /* how many times to retry after ECONNREFUSED */ unsigned delay=5; /* how long to wait between each retry */ int shutdn=0; /* should we fork, wait and shutdown? */ char *localport=NULL; /* local port name */ char *localaddr=NULL; /* local internet address */ extern int errno; int name_to_inet_port(); void usage () { fprintf(stderr,"Usage : %s (--in|--out|--err|--fd N|--slave|--netslave|--netslave1|--netslave2)+ [--verb(|ose)] [--unix] [--localport ] [--localhost ] [--retry n] [--delay n] [--shutdown [r|w][a]] [--noreuseaddr] -[i][o][e][#3[,4[,5...]]][s][v][q][u] [-p ] [-h ] [ args ... ]\n",progname); } int setup_socket(hostname,portname, reuseaddr) char *hostname; char *portname; int reuseaddr; { int sock = -1; struct in_addr ** addresses=0; #ifdef DOUNIX struct sockaddr_un unix_addr; #endif struct sockaddr_in inet_addr; int num_addresses; int length; int tries; int cstat; #ifdef DOUNIX if (doflags&DOUNIX) { unix_addr.sun_family = AF_UNIX; strncpy( unix_addr.sun_path, portname, sizeof(unix_addr.sun_path)); unix_addr.sun_path[sizeof(unix_addr.sun_path) - 1] = 0; length = sizeof(struct sockaddr_un); num_addresses = 1; } else #endif { inet_addr.sin_family = AF_INET; if (0==(addresses = convert_hostname(hostname, &num_addresses))) { fprintf(stderr, "%s: could not translate %s to a host address\n", progname, hostname); exit(EXITCODE_CONNECTION); } inet_addr.sin_port = name_to_inet_port(portname); if (inet_addr.sin_port==0) { fprintf(stderr,"%s: bogus port number %s\n",progname,portname); exit(EXITCODE_CONNECTION); } length = sizeof(struct sockaddr_in); } for (tries = 0; retry<0 || tries <= retry; tries++) { int j; int family; #ifdef DOUNIX if (doflags&DOUNIX) family = AF_UNIX; else #endif family = AF_INET; /* multi-homed hosts are a little tricky */ for ( j=0; j=0 || fromsocklen>=0) { /********************/ FD_ZERO(&readfds); FD_ZERO(&writefds); if (tosocklen>=0) { if (tosocklen==0) { FD_SET(0, &readfds); } else { FD_SET(sock, &writefds); } } if (fromsocklen>=0) { if (fromsocklen==0) { FD_SET(sock, &readfds); } else { FD_SET(1, &writefds); } } if ( ( (aggressive_close&DONETSLAVE_CF) && fromsocklen < 0 && tosocklen<1 ) || ( (aggressive_close&DONETSLAVE_CT) && tosocklen < 0 && fromsocklen<1 ) ) { /* One direction is closed and the other's buffer is empty. Exit. */ close(sock); break; } if ( ( (aggressive_close&DONETSLAVE_CF) && fromsocklen < 0 ) || ( (aggressive_close&DONETSLAVE_CT) && tosocklen < 0 ) ) { /* One direction is closed but the other's buffer is not empty. Don't accept any more input while we flush the buffer. */ FD_ZERO(&readfds); } /********************/ rval=select(sock+1, &readfds, &writefds, (fd_set*)0, (struct timeval*)0); /********************/ if (rval<0) { if (errno != EINTR) { perror("during copyio() select(2)"); exit(EXITCODE_PIPE); } } else if (rval==0) { break; } /********************/ if (FD_ISSET(1, &writefds)) { rval = write(1, fromsockbuf, fromsocklen); if (rval<0) { perror("during copyio() write(2)(1)"); exitval = EXITCODE_PIPE; fromsocklen = -1; shutdown(sock, 0); } else { memmove(fromsockbuf, fromsockbuf+rval, fromsocklen-rval); fromsocklen -= rval; } } if (FD_ISSET(sock, &writefds)) { rval = write(sock, tosockbuf, tosocklen); if (rval<0) { perror("during copyio() write(2)(sock)"); exitval = EXITCODE_PIPE; tosocklen = -1; shutdown(sock, 1); } else { memmove(tosockbuf, tosockbuf+rval, tosocklen-rval); tosocklen -= rval; } } if (FD_ISSET(0, &readfds)) { tosocklen = read(0, tosockbuf, BSIZE); if (tosocklen<0) { perror("during copyio() read(2)(0)"); exitval = EXITCODE_PIPE; tosocklen = -1; } else if (tosocklen==0) { tosocklen = -1; if (aggressive_close == 0) shutdown(sock, 1); } } if (FD_ISSET(sock, &readfds)) { fromsocklen = read(sock, fromsockbuf, BSIZE); if (fromsocklen<0) { perror("during copyio() read(2)(0)"); exitval = EXITCODE_PIPE; fromsocklen = -1; } else if (fromsocklen==0) { fromsocklen = -1; if (aggressive_close == 0) shutdown(sock, 0); } } } exit(exitval); } void endjam() { doflags &= ~DOJAM; } /**********************************************************************/ /* since we have flag processing for long and short, we do the same thing in two separate pieces of code. The non-trivial ones we encapsulate in a small function */ void flag_in() { add_fd(0); if (how_shutdown == 0) /* make sure we can read from the socket */ how_shutdown = -1; else if (how_shutdown==-2) how_shutdown = 1; } void flag_out() { add_fd(1); if (how_shutdown == 1) /* make sure we can write to the socket */ how_shutdown = -1; else if (how_shutdown==-2) how_shutdown = 0; } void flag_err() { add_fd(2); if (how_shutdown == 1) /* make sure we can write to the socket */ how_shutdown = -1; else if (how_shutdown==-2) how_shutdown = 0; } int flag_scan_comma_fds(s) char *s; { int rval=0; while (1) { int fd; int n; if (1 != sscanf(s, "%i%n", &fd, &n)) { fprintf(stderr, "%s: parse error in file descriptor list at 's'\n", progname); usage(); exit(EXITCODE_ARGS); } add_fd(fd); rval +=n; s += n; if (*s == ',') { rval++; s++; } else { break; } } return rval; } /**********************************************************************/ int main (argc,argv) int argc; char ** argv; { int sock,i; int jampipe[2]; char **cmd; int reuseaddr =1; set_progname(argv[0]); if (argc<4) { usage(); exit(EXITCODE_ARGS); } if (strcmp(argv[1],"-unix-")==0 || strcmp(progname,"uhose")==0 ){ #ifdef DOUNIX doflags |= DOUNIX; #else fprintf(stderr, "%s: unix-domain sockets are not supported in this binary.\n", progname); exit(EXITCODE_ARGS); #endif } for (i=3; i0) { fprintf(stderr, "%s: --in, --out, --err, and --fd are mutually exclusive \nwith --slave and --netslave.\n", progname); } } else { if (!*cmd) { fprintf(stderr, "%s: No subcommand specified.\n", progname); usage(); exit (EXITCODE_ARGS); } } /* this wierd setup is to flood a socket with connections */ if (doflags&DOJAM) { signal(SIGCHLD, endjam); if (0>pipe(jampipe)) { perror("opening jampipe"); exit(EXITCODE_ARGS); } } fflush(stdout); fflush(stderr); while ( (doflags & DOJAM) && fork() ) { char ch; close (jampipe[1]); while (1==read(jampipe[0], &ch, 1)) ; close (jampipe[0]); jampipe[0] = -1; if (0>pipe(jampipe)) { perror("opening jampipe"); exit(EXITCODE_FAILED_SYSCALL); } } if (doflags&DOJAM) close (jampipe[0]); reserve_fds(0); sock = setup_socket(argv[1],argv[2], reuseaddr); #ifdef DOUNIX if (doflags&DOUNIX && localport!=NULL) unlink(localport); #endif if (doflags &DOSLAVE) { copyio(sock, doflags & DONETSLAVE ); } fflush(stdout); fflush(stderr); /* if we're to shutdown(2) the socket when the subprocess exits we need to fork */ i = shutdn ? fork() : 0; if (i) { /* we are supposed to shutdown(2) the socket and we are the parent */ int status; int pid; pid = wait(&status); if (pid != -1 && i!=pid) fprintf(stderr, "Strange, wait returned a child I don't know about. I'm an unwed father!\n"); shutdown(sock, 2); /* shut the socket down nicely? */ close(sock); exit( (status&0xff) ? EXITCODE_FAILED_SYSCALL : ((status>>8)&0xff)); } else { int sparefd; char *s; sparefd = dup(fileno(stderr)); #ifdef USE_IOCTL ioctl(sparefd,FIOCLEX,NULL); #else fcntl(sparefd,F_SETFD,FD_CLOEXEC); #endif dup_n(sock); /* dup the socket onto all the chosen file descriptors */ close(sock); if (doflags&DOJAM) close (jampipe[1]); execvp(cmd[0], cmd); s ="exec failed for "; write(sparefd,s,strlen(s)); write(sparefd,cmd[0],strlen(cmd[0])); write(sparefd,"\n",1); exit(EXITCODE_FAILED_SYSCALL); } /* NOTREACHED */ } netpipes-4.2.orig/hose.html0100644000175000017500000002466506615677314015770 0ustar knoppixknoppix HOSE 1 "October 28, 1998"

NAME

hose - the client end of a BSD network pipe

netpipes 4.2

SYNOPSIS

hose hostname port (--in|--out|--err|--fd n|--slave|--netslave|--netslave1|--netslave2) [--verbose] [--unix] [--localport port] [--localhost addr] [--retry n] [--delay n] [--shutdown [r|w][a] ] [--noreuseaddr] [-[i][o][e][#3[,4[,5...]]][s][v][u]] [-p local-port] [-h local-host] command args

DESCRIPTION

hose attempts to provide the functionality of pipes over the network. It behaves as the client end of a server-client connection. When used with faucet(1) it can function as a replacement for

tar -cf - . | rsh other "cd destdir; tar -xf -"
faucet and hose are especially useful when you don't have easy non-interactive access to the destination machine.

OPTIONS

hose creates a BSD socket and, if the --localport option is used, binds it to the port number (or service name) specified immediately afterwards. If --localhost is also specified then its argument is a local address to bind to. ( --localhost is only useful on machines with multiple IP addresses.)

hose then tries to connect to the foreign machine hostname with foreign port port.

If successful hose redirects the socket to stdin, stdout, stderr, and/or arbitrary file descriptors according to the --in --out --err --fd n flags. hose also automagically shuts down the unused half of the connection if only --in is specified or if only --out and/or --err are specified. See the --shutdown option for more information.

hose then exec(2)s a command with args.

However, the --slave flag turns hose into a primitive sort of telnet. The command is ignored. Instead, hose goes into a loop where it copies bytes from stdin to the socket, and bytes from the socket to stdout. This is actually more useful than telnet because telnet tries to perform interpretation on the byte stream and generally gets in your way. hose just passes bytes without mucking with them.

The --netslave* options are variants on the --slave theme. Whereas --slave will continue to forward data in one direction even after the other has encountered EOF, --netslave variants are more aggressive in closing the entire socket. Before closing the socket, it attempts to flush any data already in its own buffer. --slave performs the shutdown(2) system call when it encounters EOF on one direction, but the --netslave variants don't because some network daemons are confused by it.

--netslave closes down the connection when it encounters EOF in either direction.

--netslave1 closes down the connection when it encounters EOF while reading stdin. Any data unread on the socket will be ignored. If it merely encounters EOF on the socket, it will continue to read from stdin.

--netslave2 closes down the connection when it encounters EOF while reading from the socket. Any data unread on stdin will be ignored. If it merely encounters EOF on stdin, it will continue to read from the socket. This mode can be useful with some web servers.

The --verbose flag specifies that hose should print information about the host it connects to. This information includes the numeric host address, host names, and foreign port numbers.

The --unix flag specifies that the port is not an internet port number or service name, but instead it is a filename for a UNIX domain socket. This option may be simulated by using -unix- as the host name to connect to, or by renaming the hose program to uhose.

--retry n allows the user to specify that hose should retry the connect(2) call for n times (or forever if n is negative). --delay n specifies how many seconds to delay between tries.

--shutdown is used to control two behaviors. The first set is controlled by the `r' and `w' flags. If the `r' is present, then hose will close half the connection to make it a read-only socket. If the child tries to write, it will fail. If the remote connection tries to read, it will percieve the socket as closed. If instead the `w' is present, then hose will close the other half of the connection to make it a write-only socket. If the child tries to read, it will percieve the socket as closed. If the remote connection tries to write, it will fail. The default behavior is to leave both halves open, however the shutdown of half of the connection is automagically done by certain combinations of the --in, --out, and --err flags. To suppress their automagic behavior you can use (respectively) --fd 0, --fd 1, and --fd 2.

The other behavior is controlled by the `a' flag. If the `a' flag is present then hose will fork(2) before execcing the command and when the child exits it will perform a shutdown(2) with how=2. This closes both halves of the connection. This option is not necessary for most applications since the closing of the file descriptors is detected by the remote process, but some less sophisticated network devices (such as printers) require a shutdown(2) for proper operation. To make things perfectly clear, the list of acceptable arguments to the --shutdown option are `r', `w', `ra', `wa', `a'.

By default, hose performs a

 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR...)
which prevents the ``Address in use'' problem that ``plagued'' netpipes versions 4.0 and earlier. --noreuseaddr tells hose to skip that system call, and revert to pre-4.1 behavior. Without this call, the port is not always available for immediate reuse after the hose exits.

SHORT FLAGS

To reduce the typing requirements for arguments (and to pay homage to the age-old tradition of UNIX cryptotaxonomy) I have added some short forms of the flags. Here is a correspondence chart:
Short Long
i in
o out
e err
#n fdn
s slave
v verbose
q quiet
u unix
p localport
h localhost

See faucet(1) for a more detailed discussion of short flags. Their behavior should be unsurprising. The flags that require separate arguments follow in the tradition of tar(1).

EXAMPLES

This will connect to port 3000 on the machine reef and connect the socket to the stdin of a tar command.

example$ hose reef 3000 --in tar -xf - .
The command actually exec(2)ed by the hose program is
tar -xf - .
The --in option means that the input of the child process will have been redirected into the socket connected to reef.

This connects to a UNIX domain socket in the current directory

example$ hose --unix- u-socket --in sh -c \
	"unfunky.perl.script | dd of=sample.pgm"
The socket provides input to the sh command.

SEE ALSO

netpipes (1), faucet (1), sockdown (1), getpeername (1), socket (2), bind (2), connect (2), shutdown (2), services (5), gethostbyaddr (3)

NOTES

Doubtless there are bugs in this program, especially in the unix domain socket portions. I welcome problem reports and would like to make these programs as "clean" (no leftover files, sockets) as possible.

4.0 made the full-word arguments use -- like many GNU programs. They are still available with a single - for backward-compatibility.

3.1 added the single-character flags.

Release 2.3 added support for multi-homed hosts: hosts with multiple internet numbers (such as gateways). Before this faucet assumed that the first internet number that gethostbyname returned was the only one. --foreignport authentication was weakened by this inadequacy so I beefed up the algorithms. --foreignport will accept a connection from any of the internet numbers associated with the host name.

CREDITS

Thanks to Steve Clift <clift@ml.csiro.au> for SGI (SysV) patches.

Many people complained about the old way of specifying the command. Thanks to whoever gave me the alternative which is now implemented. It is much better.

Thanks to Sten Drescher <smd@hrt213.brooks.af.mil> for the --retry and --delay patches and giving me the idea for the --shutdown option. Evidently some printer doesn't appreciate the socket being close(2)d.

Randy Fischer <fischer@ucet.ufl.edu> finally prodded me into fixing the old lame non-handling of multi-homed host.

COPYRIGHT

Copyright (C) 1992-98 Robert Forsman

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.

AUTHOR

Robert Forsman
thoth@purplefrog.com
Purple Frog Software
http://web.purplefrog.com/~thoth/ netpipes-4.2.orig/memmove.c0100644000175000017500000000055206615677314015742 0ustar knoppixknoppix #include #ifdef NO_MEMMOVE /* bloody SunOS, it's not ANSI */ void *memmove(dst, src, n) void *dst; void *src; size_t n; { int i; /* this memmove is not as functional as the ANSI one, it only works for what we do in copyio */ for (i=0; i result" .fi And of course, there is Nick Trown's metaserver for Netrek .nf cairo$ hose metaserver.ecst.csuchico.edu 3521 \-\-in cat .fi Allow me to apologize ahead of time for the convolutedness of the following example. It requires an understanding of Bourne shell file descriptor redirection syntax (and illustrates why csh and tcsh suck eggs). Do not try to type this from your tcsh command line. Get a bash (GNU's Bourne Again SHell). Suppose you want to distinguish between stdout and stderr of a remote process .nf remote$ faucet 3000 \-\-fd 3 \\ encapsulate \-\-fd 3 \-\-infd 0 \-\-outfd 1 \-\-outfd 2 \-\-subproc \\ remote\-app local$ hose remote 3000 \-\-fd 3 \\ encapsulate \-\-fd 3 \-\-outfd 3 \-\-infd 4 \-\-infd 5 \-\-subproc \\ sh \-c "cat 0<&4 3>&\- & cat 0<&5 1>&2 3>&\- & \\ cat 1>&3 ; exec 3>&\-" .fi Close all unneeded file descriptors when you spawn a background task. That's why the backgrounded cats have 3>&\-. .nf server$ faucet 3000 \-\-in \-\-out \-\-verbose enscript \-2rGhp \- client$ ps aux | hose server 3000 \-\-in \-\-out \\ sh \-c " (cat <&3; sockdown ) & cat >&4 " 3<&0 4>&1 | \\ lpr \-Pps422 #or perhaps this, but I haven't tested it client$ ps aux | hose server 3000 \-\-fd 3 \\ sh \-c " (cat >&3; sockdown 3 ) & cat <&3 " | \\ lpr \-Pps422 .fi This proves that hose \fIcan\fP be used as part of a pipeline to perform a sort of remote procedure call (RPC). After you have figured out that example, you will know how to use Bourne shell to shuffle file descriptors around. It is a handy skill. Now we go to the extreme, but simplify things by using the \fI\-\-slave\fP option of hose. The following is a socket relay .nf gateway$ faucet 3000 \-io hose server 4000 \-\-slave .fi It's a handy little bugger when you want to tunnel through a firewall on an occasional basis. If you experience ``hanging'' of the connection, try using the \fI\-\-netslave\fP option instead of \fI\-\-slave\fP. (telnet proxies would benefit from this) For those of you who use ssh, here's how to tunnel some information through an encrypted SSH port forward. .nf server$ faucet 3000 \-1v \-\-fd 1 \-\-foreignhost server echo blah client$ ssh \-n \-x \-L 3000:server:3000 server sleep 60 & client$ hose localhost 3000 \-\-fd 0 \-retry 10 cat .fi The trick with ssh's port forwarding, is that the shutdown(2) system call causes ssh to close both halves of the full-duplex connection instead of only one half. That's why you have to use \-\-fd 1 and \-\-fd 0. If you need to be able to close half of the connection while still using the other, use the encapsulate wrapper. .nf server$ faucet 3000 \-1v \-\-fd 3 \-\-foreignhost server \\ encapsulate \-\-fd 3 \-\-server \-si0o1 tr a\-z A\-Z client$ ssh \-n \-x \-L 3000:server:3000 server sleep 60 & client$ echo blah | hose localhost 3000 \-\-fd 3 \-retry 10 \\ encapsulate \-\-fd 3 \-\-client .fi .SH SEE ALSO faucet\ (1), hose\ (1), encapsulate\ (1), sockdown\ (1), getpeername\ (1), timelimit\ (1), ssl\-auth\ (1) .SH BUGS Report any bugs or feature requests to thoth@purplefrog.com .SH CREDITS Thanks to Harbor Development Inc. for funding some of the netpipes development. Thanks to Michal Jaegermann for some bug fixes and glibc portability suggestions against 4.1.1 . Big thanks to Joe Traister for his signal handling patches, strerror surrogate, and other assorted hacks. .SH COPYRIGHT Copyright (C) 1995-98 Robert Forsman 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. .SH DOWNLOAD Export Version: ftp://ftp.purplefrog.com/pub/netpipes/ U.S./Canada version with ssl\-auth: http://www.cryptography.org/ , then find it in the network/ subdirectory. .SH AUTHOR Robert Forsman thoth@purplefrog.com Purple Frog Software http://web.purplefrog.com/~thoth/ netpipes-4.2.orig/netpipes.html0100644000175000017500000002461206615677315016652 0ustar knoppixknoppix NETPIPES 1 "October 28, 1997"

NAME

netpipes – a package to manipulate BSD TCP/IP stream sockets

version 4.2

SYNOPSIS

faucet port (--in|--out|--err|--fd n)+ [--once] [--verbose] [--quiet] [--unix] [--foreignhost addr] [--foreignport port] [--localhost addr] [--serial] [--daemon] [--shutdown (r|w) ] [--pidfile filename] [--noreuseaddr] [--backlog n] [-[i][o][e][#3[,4[,5...]]][v][1][q][u][d][s]] [-p foreign-port] [-h foreign-host] [-H local-host] command args

hose hostname port (--in|--out|--err|--fd n|--slave) [--verbose] [--unix] [--localport port] [--localhost addr] [--retry n] [--delay n] [--shutdown [r|w][a] ] [--noreuseaddr] [-[i][o][e][#3[,4[,5...]]][s][v][u]] [-p local-port] [-h local-host] command args

encapsulate --fd n [ --verbose ] [ --subproc [ --infd n[=sid] ] [ --outfd n[=sid] ] [ --duplex n[=sid] ] [ --Duplex n[=sid] ] [ --DUPLEX n[=sid] ] [ --prefer-local ] [ --prefer-remote ] [ --local-only ] [ --remote-only ] ] [ --client ] [ --server ] -[#n][v][s[in][on][dn][ion][oin][l][r][L][R]] command args ...

ssl-auth --fd n ( --server | --client ) [ --cert file ] [ --key file ] [ --verbose ] [ --verify n ] [ --CApath path/ ] [ --CAfile file ] [ --cipher cipher-list ] [ --criteria criteria-expr ] [ --subproc [ --infd n ] [ --outfd n ] ] [ -[#n][v][s[in][on]] ]

sockdown [fd [how] ]

getpeername [ -verbose ] [ -sock ] [ fd ]

getsockname [ -verbose ] [ -peer ] [ fd ]

timelimit [ -v ] [ -nokill ] time command args

DESCRIPTION

The netpipes package makes TCP/IP streams usable in shell scripts. It can also simplify client/server code by allowing the programmer to skip all the tedious programming bits related to sockets and concentrate on writing a filter/service.

``Why would anyone want to do that?''
— Richard Stallman

faucet is the server end of a TCP/IP stream. It listens on a port of the local machine waiting for connections. Every time it gets a connection it forks a process to perform a service for the connecting client.

hose is the client end of a TCP/IP stream. It actively connects to a remote port and execs a process to request a service.

encapsulate is an implementation of the Session Control Protocol. It allows you to multiplex several streams across a single TCP session and also transmits remote exit status.

ssl-auth is an encryption filter that encapsulates stdin/stdout from a subprocess (or its own stdin/stdout) in the Secure Socket Layer protocol as implemented by the SSLeay library. It can be used to communicate with encrypted daemons (HTTPS daemons, or SSL IMAP daemons) and can sometimes be used to jury-rig secure versions of such services.

sockdown is a simple program designed to shut down part or all of the socket connection. It is primarily useful when the processes connected to the socket perform both input and output.

getpeername and getsockname are two names for a program designed to print out the addresses of the ends of a socket. getpeername prints the address of the remote end and getsockname prints the address of the local end.

timelimit limits the amount of foreground wallclock time a process can consume. After the time limit runs out it either kills the process or exits and leaves it in the background.

EXAMPLES

Here is a simple command I often perform to transfer directory trees between machines. (rsh does not work because one machine is connected using SLIP and .rhosts are out of the question).

server$ faucet 3000 --out tar cf - .
client$ hose server 3000 --in tar xvf -

Here is a minimal HTTP client. It is so minimal it speaks old HTTP.

cairo$ hose www.cis.ufl.edu 80 --in --out \
	sh -c "(echo 'GET /'; sockdown) & cat > result"

And of course, there is Nick Trown's metaserver for Netrek

cairo$ hose metaserver.ecst.csuchico.edu 3521 --in cat

Allow me to apologize ahead of time for the convolutedness of the following example. It requires an understanding of Bourne shell file descriptor redirection syntax (and illustrates why csh and tcsh suck eggs). Do not try to type this from your tcsh command line. Get a bash (GNU's Bourne Again SHell).

Suppose you want to distinguish between stdout and stderr of a remote process

remote$ faucet 3000 --fd 3 \
   encapsulate --fd 3 --infd 0 --outfd 1 --outfd 2 --subproc \
	remote-app
local$ hose remote 3000 --fd 3 \
   encapsulate --fd 3 --outfd 3 --infd 4 --infd 5 --subproc \
	sh -c "cat 0<&4 3>&- & cat 0<&5 1>&2 3>&- & \
	    cat 1>&3 ; exec 3>&-"
Close all unneeded file descriptors when you spawn a background task. That's why the backgrounded cats have 3>&-.
server$ faucet 3000 --in --out --verbose enscript -2rGhp -
client$ ps aux | hose server 3000 --in --out \
	sh -c " (cat <&3; sockdown ) & cat >&4 " 3<&0 4>&1 | \
	lpr -Pps422
#or perhaps this, but I haven't tested it
client$ ps aux | hose server 3000 --fd 3 \
	sh -c " (cat >&3; sockdown 3 ) & cat <&3 " | \
	lpr -Pps422
This proves that hose can be used as part of a pipeline to perform a sort of remote procedure call (RPC). After you have figured out that example, you will know how to use Bourne shell to shuffle file descriptors around. It is a handy skill.

Now we go to the extreme, but simplify things by using the --slave option of hose. The following is a socket relay

gateway$ faucet 3000 -io hose server 4000 --slave
It's a handy little bugger when you want to tunnel through a firewall on an occasional basis. If you experience ``hanging'' of the connection, try using the --netslave option instead of --slave. (telnet proxies would benefit from this)

For those of you who use ssh, here's how to tunnel some information through an encrypted SSH port forward.

server$ faucet 3000 -1v --fd 1 --foreignhost server echo blah 
client$ ssh -n -x -L 3000:server:3000 server sleep 60 &
client$ hose localhost 3000 --fd 0 -retry 10 cat

The trick with ssh's port forwarding, is that the shutdown(2) system call causes ssh to close both halves of the full–duplex connection instead of only one half. That's why you have to use --fd 1 and --fd 0. If you need to be able to close half of the connection while still using the other, use the encapsulate wrapper.

server$ faucet 3000 -1v --fd 3 --foreignhost server \
	encapsulate --fd 3 --server -si0o1 tr a-z A-Z
client$ ssh -n -x -L 3000:server:3000 server sleep 60 &
client$ echo blah | hose localhost 3000 --fd 3 -retry 10 \
	encapsulate --fd 3 --client

SEE ALSO

faucet (1), hose (1), encapsulate (1), sockdown (1), getpeername (1), timelimit (1), ssl-auth (1)

BUGS

Report any bugs or feature requests to thoth@purplefrog.com

CREDITS

Thanks to Harbor Development Inc. for funding some of the netpipes development.

Thanks to Michal Jaegermann <michal@ellpspace.math.ualberta.ca> for some bug fixes and glibc portability suggestions against 4.1.1 .

Big thanks to Joe Traister <traister@gate.net> for his signal handling patches, strerror surrogate, and other assorted hacks.

COPYRIGHT

Copyright (C) 1995–98 Robert Forsman

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.

DOWNLOAD

Export Version: ftp://ftp.purplefrog.com/pub/netpipes/

U.S./Canada version with ssl-auth: http://www.cryptography.org/ , then find it in the network/ subdirectory.

AUTHOR

Robert Forsman
thoth@purplefrog.com
Purple Frog Software
http://web.purplefrog.com/~thoth/ netpipes-4.2.orig/sockdown.10100644000175000017500000001167006615677350016045 0ustar knoppixknoppix.\" $Id: sockdown.html,v 1.4 1998/10/28 16:07:57 thoth Exp $ Copyright 1995 by Robert Forsman .TH SOCKDOWN 1 "July 7, 1998" .SH NAME sockdown \- shutdown(2) a socket netpipes 4.2 .SH SYNOPSIS \fBsockdown\fP [ \fIfd\fP [\fIhow\fP] ] .SH DESCRIPTION \fBsockdown\fP performs the shutdown(2) system call on one of its file descriptors specified by \fIfd\fP. The possible values for \fIhow\fP are .TS H |lw(0.4i)|lw(2i)|. .TB writeonly convert to write\-only file descriptor 0 convert to write\-only file descriptor writeonly symbolic for same as above 1 convert to read\-only file descriptor readonly symbolic for same as above 2 complete shutdown. no reads or writes allowed in the future totally symbolic for same as above .TE The default \fIfd\fP is 1 (stdout) and the default \fIhow\fP is 1. .SH EXAMPLES Imagine you have a machine that can perform a service (in this case conversion from ASCII to fancy postscript) : .nf server$ faucet 3000 \-\-in \-\-out enscript \-2rGhp \- .fi You may then connect to it with a hose. However, the first example enters deadlock : .nf client$ hose server 3000 \-in \-out \\ sh \-c " cat blah.txt & cat > blah.ps " .fi The enscript blocks waiting for input from the socket because not all of the client processes have exited. While the cat blah.txt is finished, the cat > blah.ps is not, and will not be finished until the remote enscript process finishes writing. The enscript process will not finish writing until it is finished reading, but that client\->server half of the socket is still open and will not be closed until all the client processes are done. The result is deadlock. So, we use sockdown to close half of the pipe .nf client$ hose server 3000 \-in \-out \\ sh \-c " ( cat blah.txt ; sockdown ) & cat > blah.ps " .fi This way when the cat blah.txt is done, half of the socket is shut down and the remote enscript process runs out of input, causing it to flush its output and exit, so eventually the whole mess finishes cleanly. Note: the & on the hose is necessary to prevent another deadlock. If we simply used the ; to serialize the two cat processes it is possible that the enscript would fill up its write buffer before the first cat was done causing both processes to block and preventing the second cat from draining the pipe. Of course, that idiomatic usage of hose is so useful that it is a special form: .nf client$ hose server 3000 \-slave < blah.txt > blah.ps .fi Ian Stirling informs me that \fBsockdown\fP can be used in Linux's /proc/\fIpid\fP/fd/ directories to tear down hung network connections. I have since used this myself on a wedged MOMspider. To try this, you have to know the PID of the program and the file descriptor of the wedged socket (can sometimes be found by running \fBstrace\fP and see if the program is stuck in a read(2) system call). If the PID is 991 and the socket's descriptor is 5, you do this as root: .nf bash# sockdown 1 2 > /proc/991/fd/5 .fi .SH ERRORS \fBSocket operation on non\-socket\fP \fBInvalid argument (seen on Solaris)\fP The \fIfd\fP you specified does not refer to a socket. This happens when you run sockdown by itself (it is unlikely that any of the file descriptors attached to an interactive shell are actually sockets) or if you goof up your faucet/hose command and forgot to dup(2) one of your descriptors. \fBBad file number\fP You gave it a bad file number for \fIfd\fP. If you have enough skill to actually generate this error, you probably know what is wrong. If you encounter any other errors, clue me in. .SH SEE ALSO netpipes (1) faucet (1), hose (1), getpeername (1), socket (2), shutdown (2), .SH NOTES Any normal human would assume a program this simple has to be bug free, but I am an experienced programmer. Just avoid doing anything funky like passing \fBsockdown\fP strings and it should serve you well. You should not have to pass it any arguments unless you are doing something fairly funky. Perhaps I should ditch the \fBshutdown \-a\fP semantics on hose since a \fBsockdown 1 2\fP would do the job. .SH CREDITS Ian Stirling , for the idea of using this program in /proc on a Linux machine. .SH COPYRIGHT Copyright (C) 1995\-1998 Robert Forsman 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. .SH AUTHOR Robert Forsman thoth@purplefrog.com Purple Frog Software http://web.purplefrog.com/~thoth/ netpipes-4.2.orig/sockdown.c0100644000175000017500000000426106615677315016126 0ustar knoppixknoppix/* $Id: sockdown.c,v 1.6 1998/06/12 19:59:18 thoth Exp $, part of faucet and hose: network pipe utilities Copyright (C) 1995-98 Robert Forsman 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. */ static char info[] = "sockdown: a network utility for sockets\nWritten 1995-98 by Robert Forsman \n"; #include #include #include #include #include #include #include "common.h" void /* this is in version.c */ emit_version(/* char*, int */); extern char *progname; int main(argc, argv) int argc; char **argv; { int fd; int how; int verbose=0; set_progname(argv[0]); if (argc>1&& 0==strncmp(argv[1], "-verbose", strlen(argv[1]))) { verbose=1; argc--; argv++; } if (argc<2) { fd = 1; how = 1; } else { fd = atoi(argv[1]); if (argc<3) { how = 1; } else { if (0==strncmp("readonly", argv[2], strlen(argv[2]))) { how = 1; } else if (0==strncmp("writeonly", argv[2], strlen(argv[2]))) { how = 0; } else if (0==strncmp("totally", argv[2], strlen(argv[2]))) { how = 2; } else { how = atoi(argv[2]); } } } if (verbose) { emit_version("sockdown", 1995); fprintf(stderr, "%s: Performing shutdown on descriptor %d with mode %d\n", progname, fd, how); } if ( 0==shutdown(fd, how) ) { exit(0); } else { fprintf(stderr, "%s: Error %d during shutdown(%d, %d) of socket. ", progname, errno, fd, how); perror(""); exit(1); } } netpipes-4.2.orig/sockdown.html0100644000175000017500000001316206615677315016650 0ustar knoppixknoppix SOCKDOWN 1 "July 7, 1998"

NAME

sockdown - shutdown(2) a socket

netpipes 4.2

SYNOPSIS

sockdown [ fd [how] ]

DESCRIPTION

sockdown performs the shutdown(2) system call on one of its file descriptors specified by fd. The possible values for how are

writeonly convert to write-only file descriptor
0 convert to write-only file descriptor
writeonly symbolic for same as above
1 convert to read-only file descriptor
readonly symbolic for same as above
2 complete shutdown. no reads or writes allowed in the future
totally symbolic for same as above

The default fd is 1 (stdout) and the default how is 1.

EXAMPLES

Imagine you have a machine that can perform a service (in this case conversion from ASCII to fancy postscript) :

server$ faucet 3000 --in --out enscript -2rGhp -
You may then connect to it with a hose. However, the first example enters deadlock :
client$ hose server 3000 -in -out \
	sh -c " cat blah.txt & cat > blah.ps "
The enscript blocks waiting for input from the socket because not all of the client processes have exited. While the cat blah.txt is finished, the cat > blah.ps is not, and will not be finished until the remote enscript process finishes writing. The enscript process will not finish writing until it is finished reading, but that client->server half of the socket is still open and will not be closed until all the client processes are done. The result is deadlock.

So, we use sockdown to close half of the pipe

client$ hose server 3000 -in -out \
	sh -c " ( cat blah.txt ; sockdown ) & cat > blah.ps "
This way when the cat blah.txt is done, half of the socket is shut down and the remote enscript process runs out of input, causing it to flush its output and exit, so eventually the whole mess finishes cleanly.

Note: the & on the hose is necessary to prevent another deadlock. If we simply used the ; to serialize the two cat processes it is possible that the enscript would fill up its write buffer before the first cat was done causing both processes to block and preventing the second cat from draining the pipe.

Of course, that idiomatic usage of hose is so useful that it is a special form:

client$ hose server 3000 -slave < blah.txt > blah.ps

Ian Stirling <root@mauve.demon.co.uk> informs me that sockdown can be used in Linux's /proc/pid/fd/ directories to tear down hung network connections. I have since used this myself on a wedged MOMspider. To try this, you have to know the PID of the program and the file descriptor of the wedged socket (can sometimes be found by running strace and see if the program is stuck in a read(2) system call). If the PID is 991 and the socket's descriptor is 5, you do this as root:

bash# sockdown 1 2 > /proc/991/fd/5

ERRORS

Socket operation on non-socket

Invalid argument (seen on Solaris) The fd you specified does not refer to a socket. This happens when you run sockdown by itself (it is unlikely that any of the file descriptors attached to an interactive shell are actually sockets) or if you goof up your faucet/hose command and forgot to dup(2) one of your descriptors.

Bad file number You gave it a bad file number for fd. If you have enough skill to actually generate this error, you probably know what is wrong.

If you encounter any other errors, clue me in.

SEE ALSO

netpipes (1) faucet (1), hose (1), getpeername (1), socket (2), shutdown (2),

NOTES

Any normal human would assume a program this simple has to be bug free, but I am an experienced programmer.

Just avoid doing anything funky like passing sockdown strings and it should serve you well. You should not have to pass it any arguments unless you are doing something fairly funky.

Perhaps I should ditch the shutdown -a semantics on hose since a sockdown 1 2 would do the job.

CREDITS

Ian Stirling <root@mauve.demon.co.uk>, for the idea of using this program in /proc on a Linux machine.

COPYRIGHT

Copyright (C) 1995-1998 Robert Forsman

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.

AUTHOR

Robert Forsman
thoth@purplefrog.com
Purple Frog Software
http://web.purplefrog.com/~thoth/ netpipes-4.2.orig/ssl-auth.10100644000175000017500000002474706615677357015776 0ustar knoppixknoppix.\" t .\"$Id: ssl-auth.html,v 1.7 1998/10/28 16:07:57 thoth Exp $ .\"Copyright 1992-98 by Robert Forsman .\" .TH SSL-AUTH 1 "October 28, 1998" .SH NAME ssl\-auth \- secure sockets for the peasants netpipes 4.2 .SH SYNOPSIS \fBssl\-auth\fP \fB\-\-fd\fP \fIn\fP ( \fB\-\-server\fP | \fB\-\-client\fP ) [ \fB\-\-cert\fP \fIfile\fP ] [ \fB\-\-key\fP \fIfile\fP ] [ \fB\-\-verbose\fP ] [ \fB\-\-verify\fP \fIn\fP ] [ \fB\-\-CApath\fP \fIpath/\fP ] [ \fB\-\-CAfile\fP \fIfile\fP ] [ \fB\-\-cipher\fP \fIcipher\-list\fP ] [ \fB\-\-criteria\fP \fIcriteria\-expr\fP ] [ \fB\-\-subproc\fP [ \fB\-\-infd\fP \fIn\fP ] [ \fB\-\-outfd\fP \fIn\fP ] ] [ \fB\-\fP[\fB#\fP\fIn\fP][\fBv\fP][\fBs\fP[\fBi\fP\fIn\fP][\fBo\fP\fIn\fP]] ] .SH DESCRIPTION \fBssl\-auth\fP provides SSL capability for simple programs and shell scripts. With \fBssl\-auth\fP you can secure and authenticate your netpipes scripts, provide secure proxies for mundane internet services such as IMAP, and communicate with such servers. .SH OPTIONS You must specify a file descriptor (using \fB\-\-fd\fP) over which to conduct the SSL conversation. This must be a socket (readable and writable), not just a pipe. Also, you must define the polarity of the conversation with \fB\-\-server\fP or \fB\-\-client\fP. Servers must specify a \fB\-\-key\fP and a \fB\-\-cert\fP. Failure to do so generally results in a ``no shared ciphers'' error on the server and a ``handshake failure'' on the client. \fB\-\-verbose\fP currently just prints a copyright notice. \fB\-\-verify\fP \fIn\fP specifies a verify depth. Errors deeper than \fIn\fP will be ignored. Issuer errors (UNABLE_TO_GET_ISSUER_CERT, and UNABLE_TO_GET_ISSUER_CERT_LOCALLY) are treated as a depth one greater than that reported by the SSL library because, while they are reported as a problem with the signed certificate, in a common case it is better to treat them as a problem with the signer (issuer) certificate. The typical value for \fIn\fP is 1. (behavior with the presence of \-\-criteria in the absence of \-\-verify is currently ill\-defined and uninvestigated). \fB\-\-CApath\fP allows you to specify the location of your Certificate Authority directory. This directory contains the (usually self-signed) certificates from certificate authorities and the hash links. Here's a BASH function to create a hash link for a certificate in the current directory: .nf function make\-ssl\-cert\-link { hash=`x509 \-noout \-hash < $1` ln \-s $1 $hash.0 } .fi \fB\-\-cipher\fP lets you specify a cipher list to be passed to SSL_CTX_set_cipher_list(). It is a colon\-separated list of names. Each name has an optional prefix of \fB\-\fP, \fB+\fP, or \fB!\fP. \fB\-\fP and \fB!\fP remove the cipher from the list supported by the library. \fB+\fP adds the cipher to the front, and no prefix adds it to the front unless it is already listed. \fB\-\-criteria\fP is the most powerful feature of \fBssl\-auth\fP. You can use it to specify a set of criteria to apply to the certificate chain presented by the SSL peer. The grammar of the \fIcriteria\-expression\fP is documented in the CRITERIA LANGUAGE section below. \fB\-\-subproc\fP allows you to specify a process that will supply the payload for the SSL conversation. Without \fB\-\-subproc\fP \fBssl\-auth\fP merely encrypts stdin to the socket and decrypts from the socket to stdout. When \fB\-\-subproc\fP is specified \fBssl\-auth\fP spawns a child, attaches pipes to the specified \fB\-\-infd\fP and/or \fB\-\-outfd\fP (if both descriptor numbers are the same, it attaches a socket instead of a pipe), and routes those data streams through the SSL socket. \fBssl\-auth\fP also accepts one-character compact flags. These flags may be compacted together in one argument, or spread throughout several. You may use any mixture of long and compact flags, as long as you don't mix them in the same argument. The compact flags that expect arguments expect them to immediately follow their activating character. \fB\-#\fP corresponds to \fB\-\-fd\fP. \fB\-v\fP corresponds to \fB\-\-verbose\fP. \fB\-s\fP corresponds to \fB\-\-subproc\fP. \fB\-i\fP corresponds to \fB\-\-infd\fP. \fB\-o\fP corresponds to \fB\-\-outfd\fP. .SH CRITERIA LANGUAGE \fIcriteria\-expr\fP : \fIprefix\-unary\-expr\fP \fIor\-list\fP : \fIand\-list\fP \fB\-\-or\fP \fIor\-list\fP \fIor\-list\fP : \fIand\-list\fP \fB\-o\fP \fIor\-list\fP \fIor\-list\fP : \fIand\-list\fP \fIand\-list\fP : \fIprefix\-unary\-expr\fP \fB\-\-and\fP \fIand\-list\fP \fIand\-list\fP : \fIprefix\-unary\-expr\fP \fB\-a\fP \fIand\-list\fP \fIand\-list\fP : \fIprefix\-unary\-expr\fP \fIprefix\-unary\-expr\fP : \fB\-\-not\fP \fIterm\fP \fIprefix\-unary\-expr\fP : \fB!\fP \fIterm\fP \fIprefix\-unary\-expr\fP : \fB\-\-depth\fP \fIinteger\fP \fIterm\fP \fIprefix\-unary\-expr\fP : \fB\-d\fP \fIinteger\fP \fIterm\fP \fIprefix\-unary\-expr\fP : \fIterm\fP \fIterm\fP : \fB(\fP \fIor\-list\fP \fB)\fP \fIterm\fP : \fB\-\-common\-name\fP \fIstring\fP \fIterm\fP : \fB\-\-country\-name\fP \fIstring\fP \fIterm\fP : \fB\-\-state\-name\fP \fIstring\fP \fIterm\fP : \fB\-\-province\-name\fP \fIstring\fP \fIterm\fP : \fB\-\-locality\-name\fP \fIstring\fP \fIterm\fP : \fB\-\-organization\-name\fP \fIstring\fP \fIterm\fP : \fB\-\-organizational\-unit\-name\fP \fIstring\fP \fIterm\fP : \fB\-\-department\-name\fP \fIstring\fP \fIterm\fP : \fB\-\-public\-key\-match\-cert\fP \fIfname\fP \fIterm\fP : \fB\-\-cert\-md5\-digest\fP \fI32hexdigits\fP \fIterm\fP : \fB\-\-write\-pem\-cert\fP \fIfname\fP The grammar parsed by the \fB\-\-criteria\fP flag will be unsurprising to the average computer-literate person. At the lowest precedence level is the or list whose members are separated by \fB\-o\fP or \fB\-\-or\fP. The next highest precedence level is the and list whose members are separated by \fB\-a\fP or \fB\-\-and\fP. The next level of precedence is the prefix unary operators which include \fB\-\-not\fP (can be shortened to \fB!\fP, but be sure to escape it if your shell treats it specially; most do) and \fB\-\-depth\fP \fIn\fP (which can be shortened to \fB\-d\fP \fIn\fP). The highest precedence are the primitives (listed below). Precedence may be overridden using parenthesis, but remember to escape them with a \\ because ()s are usually treated specially by the shell. The following lists the correspondence between the X509 field names and the primitives that are designed to compare them. .TS H lw(0.4i) lw(1.2i) lw(0.4i) lw(1.2i). .TB X509 criteria primitive CN \-\-common\-name C \-\-country\-name ST \-\-state\-name, \-\-province\-name L \-\-locality\-name O \-\-organization\-name OU \-\-organizational\-unit\-name, \-\-department\-name .TE \fB\-\-public\-key\-match\-cert\fP compares the public key (exponent and modulus) from the SSL peer with the public key in the PEM\-encoded certificate in \fIfname\fP. This can be used to verify the identity of the remote end in the absence of a certificate authority. \fB\-\-cert\-md5\-digest\fP compares the MD5 fingerprint of the SSL peer's certificate with the 32\-digit hex string argument. It incorporates much more than the public key such as the name, issuer, algorithm, and signature. You can compute the md5 fingerprint by running the following command upon the server's certificate. .nf server$ ssleay x509 \-md5 \-fingerprint \-in certificate.pem \-out /dev/null MD5 Fingerprint=F6:0A:A2:D1:A3:12:5A:41:49:C7:56:0B:4E:67:1D:3C .fi In this case you would use a criteria of \-\-cert\-md5\-digest F60AA2D1A3125A4149C7560B4E671D3C. \fB\-\-write\-pem\-cert\fP writes the certificate of the SSL peer to \fIfname\fP in PEM format. .SH EXAMPLES Here is an example ssl\-imapd spawnable from inetd: .nf #!/bin/sh exec > /dev/null exec 2>&1 exec /usr/local/bin/ssl\-auth \-\-fd 0 \-\-server \\ \-\-cert /usr/local/ssl/certs/imapd.cert \\ \-\-key /usr/local/ssl/private/imapd.key \\ \-\-CApath /usr/local/ssl/certs/ \\ \-si0o1 /usr/local/sbin/imapd .fi To use it, put this in your /etc/inetd.conf .nf 993 stream tcp nowait root /usr/local/sbin/ssl\-imapd .fi If you want to turn a non\-ssl IMAP client into an ssl\-capable IMAP client, try putting this in your local machine's inetd.conf: .nf imap stream tcp nowait root /usr/local/sbin/ssl\-proxy imap.remote.com .fi /usr/local/sbin/ssl\-proxy looks like this: .nf #!/bin/sh exec > /dev/null exec 2>&1 exec hose "$1" 993 \-\-fd 3 \\ ssl\-auth \-\-fd 3 \-\-client \\ \-\-CApath /usr/local/ssl/certs/ \-\-verify 1 >&0 .fi Now point your IMAP client at your local machine. The connection should be tunnelled through SSL to the remote machine. Tell me if it works... If you can type HTTP requests yourself, you can probe an SSL HTTPd with the following command: .nf $ hose web.purplefrog.com 443 \-\-fd 3 ssl\-auth \-\-fd 3 \-\-client .fi Then type your GET or POST request To get a copy of the remote server's certificate for local inspection you can do this: .nf $ hose web.purplefrog.com 443 \-\-fd 3 ssl\-auth \-\-fd 3 \-\-client \\ \-\-CApath /usr/local/ssl/certs/ \\ \-\-verify 1 \-\-criteria \-\-write\-pem\-cert tmp.cert \\ \-si0o1 /bin/true .fi .SH SEE ALSO netpipes (1), faucet (1), hose (1), encapsulate (1), SSLeay library .SH BUGS This program is raw. Even I don't know how to operate it fully. .SH EXPORT LAW As of December 1997 it is still illegal to export encryption from the United States to the rest of the world (with an exception or two). If you break the law, you will probably be repressed. .SH CREDITS Thanks, Eric Young, for writing SSLeay. Now tell me how to write more \fB\-\-criteria\fP primitives and improve the existing ones to work for strangely-encoded certificates. Thanks to Dr. Stephen Henson for numerous hints and answers. .SH COPYRIGHT Copyright (C) 1997\-98 Robert Forsman 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. .SH AUTHOR Robert Forsman thoth@purplefrog.com Purple Frog Software http://web.purplefrog.com/~thoth/ netpipes-4.2.orig/ssl-auth.html0100644000175000017500000002632706615677315016570 0ustar knoppixknoppix SSL-AUTH 1 "October 28, 1998"

NAME

ssl-auth - secure sockets for the peasants

netpipes 4.2

SYNOPSIS

ssl-auth --fd n ( --server | --client ) [ --cert file ] [ --key file ] [ --verbose ] [ --verify n ] [ --CApath path/ ] [ --CAfile file ] [ --cipher cipher-list ] [ --criteria criteria-expr ] [ --subproc [ --infd n ] [ --outfd n ] ] [ -[#n][v][s[in][on]] ]

DESCRIPTION

ssl-auth provides SSL capability for simple programs and shell scripts. With ssl-auth you can secure and authenticate your netpipes scripts, provide secure proxies for mundane internet services such as IMAP, and communicate with such servers.

OPTIONS

You must specify a file descriptor (using --fd) over which to conduct the SSL conversation. This must be a socket (readable and writable), not just a pipe. Also, you must define the polarity of the conversation with --server or --client.

Servers must specify a --key and a --cert. Failure to do so generally results in a ``no shared ciphers'' error on the server and a ``handshake failure'' on the client.

--verbose currently just prints a copyright notice.

--verify n specifies a verify depth. Errors deeper than n will be ignored. Issuer errors (UNABLE_TO_GET_ISSUER_CERT, and UNABLE_TO_GET_ISSUER_CERT_LOCALLY) are treated as a depth one greater than that reported by the SSL library because, while they are reported as a problem with the signed certificate, in a common case it is better to treat them as a problem with the signer (issuer) certificate. The typical value for n is 1. (behavior with the presence of --criteria in the absence of --verify is currently ill-defined and uninvestigated).

--CApath allows you to specify the location of your Certificate Authority directory. This directory contains the (usually self–signed) certificates from certificate authorities and the hash links. Here's a BASH function to create a hash link for a certificate in the current directory:

function make-ssl-cert-link {
    hash=`x509 -noout -hash < $1`
    ln -s $1 $hash.0
}

--cipher lets you specify a cipher list to be passed to SSL_CTX_set_cipher_list(). It is a colon-separated list of names. Each name has an optional prefix of -, +, or !. - and ! remove the cipher from the list supported by the library. + adds the cipher to the front, and no prefix adds it to the front unless it is already listed.

--criteria is the most powerful feature of ssl-auth. You can use it to specify a set of criteria to apply to the certificate chain presented by the SSL peer. The grammar of the criteria-expression is documented in the CRITERIA LANGUAGE section below.

--subproc allows you to specify a process that will supply the payload for the SSL conversation. Without --subproc ssl-auth merely encrypts stdin to the socket and decrypts from the socket to stdout. When --subproc is specified ssl-auth spawns a child, attaches pipes to the specified --infd and/or --outfd (if both descriptor numbers are the same, it attaches a socket instead of a pipe), and routes those data streams through the SSL socket.

ssl-auth also accepts one–character compact flags. These flags may be compacted together in one argument, or spread throughout several. You may use any mixture of long and compact flags, as long as you don't mix them in the same argument. The compact flags that expect arguments expect them to immediately follow their activating character.

-# corresponds to --fd. -v corresponds to --verbose. -s corresponds to --subproc. -i corresponds to --infd. -o corresponds to --outfd.

CRITERIA LANGUAGE

criteria-expr : prefix-unary-expr
or-list : and-list --or or-list
or-list : and-list -o or-list
or-list : and-list
and-list : prefix-unary-expr --and and-list
and-list : prefix-unary-expr -a and-list
and-list : prefix-unary-expr
prefix-unary-expr : --not term
prefix-unary-expr : ! term
prefix-unary-expr : --depth integer term
prefix-unary-expr : -d integer term
prefix-unary-expr : term
term : ( or-list )
term : --common-name string
term : --country-name string
term : --state-name string
term : --province-name string
term : --locality-name string
term : --organization-name string
term : --organizational-unit-name string
term : --department-name string
term : --public-key-match-cert fname
term : --cert-md5-digest 32hexdigits term : --write-pem-cert fname

The grammar parsed by the --criteria flag will be unsurprising to the average computer–literate person. At the lowest precedence level is the or list whose members are separated by -o or --or. The next highest precedence level is the and list whose members are separated by -a or --and. The next level of precedence is the prefix unary operators which include --not (can be shortened to !, but be sure to escape it if your shell treats it specially; most do) and --depth n (which can be shortened to -d n). The highest precedence are the primitives (listed below). Precedence may be overridden using parenthesis, but remember to escape them with a \ because ()s are usually treated specially by the shell.

The following lists the correspondence between the X509 field names and the primitives that are designed to compare them.

X509 criteria primitive
CN --common-name
C --country-name
ST --state-name, --province-name
L --locality-name
O --organization-name
OU --organizational-unit-name, --department-name

--public-key-match-cert compares the public key (exponent and modulus) from the SSL peer with the public key in the PEM-encoded certificate in fname. This can be used to verify the identity of the remote end in the absence of a certificate authority.

--cert-md5-digest compares the MD5 fingerprint of the SSL peer's certificate with the 32-digit hex string argument. It incorporates much more than the public key such as the name, issuer, algorithm, and signature. You can compute the md5 fingerprint by running the following command upon the server's certificate.

server$ ssleay x509 -md5 -fingerprint -in certificate.pem -out /dev/null
MD5 Fingerprint=F6:0A:A2:D1:A3:12:5A:41:49:C7:56:0B:4E:67:1D:3C
In this case you would use a criteria of --cert-md5-digest F60AA2D1A3125A4149C7560B4E671D3C.

--write-pem-cert writes the certificate of the SSL peer to fname in PEM format.

EXAMPLES

Here is an example ssl-imapd spawnable from inetd:

#!/bin/sh

exec > /dev/null
exec 2>&1

exec /usr/local/bin/ssl-auth --fd 0 --server \
        --cert /usr/local/ssl/certs/imapd.cert \
        --key  /usr/local/ssl/private/imapd.key \
        --CApath /usr/local/ssl/certs/ \
        -si0o1 /usr/local/sbin/imapd

To use it, put this in your /etc/inetd.conf

993     stream  tcp     nowait  root    /usr/local/sbin/ssl-imapd

If you want to turn a non-ssl IMAP client into an ssl-capable IMAP client, try putting this in your local machine's inetd.conf:

imap stream tcp nowait root /usr/local/sbin/ssl-proxy imap.remote.com

/usr/local/sbin/ssl-proxy looks like this:

#!/bin/sh

exec > /dev/null
exec 2>&1

exec hose "$1" 993 --fd 3 \
	ssl-auth --fd 3 --client \
        --CApath /usr/local/ssl/certs/ --verify 1 >&0

Now point your IMAP client at your local machine. The connection should be tunnelled through SSL to the remote machine. Tell me if it works...


If you can type HTTP requests yourself, you can probe an SSL HTTPd with the following command:

$ hose web.purplefrog.com 443 --fd 3 ssl-auth --fd 3 --client
Then type your GET or POST request

To get a copy of the remote server's certificate for local inspection you can do this:

$ hose web.purplefrog.com 443 --fd 3 ssl-auth --fd 3 --client \
        --CApath /usr/local/ssl/certs/ \
	--verify 1 --criteria --write-pem-cert tmp.cert \
	-si0o1 /bin/true

SEE ALSO

netpipes (1), faucet (1), hose (1), encapsulate (1), SSLeay library

BUGS

This program is raw. Even I don't know how to operate it fully.

EXPORT LAW

As of December 1997 it is still illegal to export encryption from the United States to the rest of the world (with an exception or two). If you break the law, you will probably be repressed.

CREDITS

Thanks, Eric Young, for writing SSLeay. Now tell me how to write more --criteria primitives and improve the existing ones to work for strangely–encoded certificates.

Thanks to Dr. Stephen Henson <shenson@drh-consultancy.demon.co.uk> for numerous hints and answers.

COPYRIGHT

Copyright (C) 1997-98 Robert Forsman

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.

AUTHOR

Robert Forsman
thoth@purplefrog.com
Purple Frog Software
http://web.purplefrog.com/~thoth/ netpipes-4.2.orig/timelimit.10100644000175000017500000000341606615677357016221 0ustar knoppixknoppix.\" $Id: timelimit.html,v 1.3 1998/10/28 16:07:57 thoth Exp $ .\" Copyright 1997-98 by Robert Forsman .TH TIMELIMIT 1 "February 12, 1998" .SH NAME timelimit \- spawn a subprocess and if the child does not finish within the time limit either kill it, or exit, leaving the child in the background. netpipes 4.2 .SH SYNOPSIS \fBtimelimit\fP [ \fB\-v\fP ] [ \fB\-nokill\fP ] \fItime\fP \fIcommand args\fP .SH DESCRIPTION \fBtimelimit\fP is used to limit the amount of foreground wallclock time a process consumes. Once the time limit expires \fBtimelimit\fP will kill the process unless \fB\-nokill\fP is specified. \fB\-v\fP adds some diagnostic messages. .SH EXAMPLES .nf timelimit 5m faucet 3000 \-\-out cat time\-sensitive\-info .fi .SH SEE ALSO netpipes (1) .SH BUGS Find 'em. Send 'em in. I'll teach them to gnaw on my code! .SH CREDITS Francis Liu suggested that I modify timelimit so that it doesn't SEGV when invoked with no arguments. .SH COPYRIGHT Copyright (C) 1997\-1998 Robert Forsman 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. .SH AUTHOR Robert Forsman thoth@purplefrog.com Purple Frog Software http://web.purplefrog.com/~thoth/ netpipes-4.2.orig/timelimit.c0100644000175000017500000001034706615677316016277 0ustar knoppixknoppix/* timelimit.c, part of netpipes: network pipe utilities Copyright (C) 1996-98 Robert Forsman 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. */ static char info[] = "timelimit: a utility for sockets\nWritten 1996 by Robert Forsman \n"; #include #include #include #include #include #include #include #include extern int errno; #include "common.h" int verbose = 0; int nokill = 0; char *childprogname=0; int deadchild = 0; void notice_child() { deadchild = 1; } void usage() { fprintf(stderr,"Usage : %s [ -v ] [ -nokill ]