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.
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
--fdn, -#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.
--infdn, -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).
--outfdn, -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).
--duplexn, -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.
--Duplexn, -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.
--DUPLEXn, -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.
--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.
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"
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 --fdn
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.
--pidfilefilename 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.
--backlogn 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:
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.
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
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.
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.
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.
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.
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.
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.
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"
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.
--retryn
allows the user to specify that
hose
should retry the connect(2) call for
n
times (or forever if
n
is negative).
--delayn
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
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.
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
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.
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
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.
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.
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.
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.
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.
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"
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.
--verifyn 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:
--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 --subprocssl-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--oror-list or-list : and-list-oor-list or-list : and-list and-list : prefix-unary-expr--andand-list and-list : prefix-unary-expr-aand-list and-list : prefix-unary-expr prefix-unary-expr : --notterm prefix-unary-expr : !term prefix-unary-expr : --depthintegerterm prefix-unary-expr : -dintegerterm prefix-unary-expr : term term : (or-list) term : --common-namestring term : --country-namestring term : --state-namestring term : --province-namestring term : --locality-namestring term : --organization-namestring term : --organizational-unit-namestring term : --department-namestring term : --public-key-match-certfname term : --cert-md5-digest32hexdigitsterm : --write-pem-certfname
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
--depthn (which can be shortened to -dn). 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.
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.
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 ]