This commit is contained in:
2024-03-12 16:01:41 +08:00
commit 201ffe6cab
185 changed files with 108495 additions and 0 deletions

18
BUGREPORTS Normal file
View File

@@ -0,0 +1,18 @@
* If you have found a bug, i.e. socat SIGSEGV'ed, terminated abnormally without
error message, did not comply to the documentation, or behaves different from
your expectations, please send the following infos to socat@dest-unreach.org,
as available:
. output of "make info" in socat.out (you may remove the hostname in the first
line to keep your privacy)
. config.log
. run your example with "socat -d -d -d -d -D ..." options, and include the log
output
. describe what you've done, and why you think socat did wrong
* If you fixed a bug:
Please do as described in the above paragraph, and include the modified files
(or a patch file)
* If you have contributions, problems etc: send available info and a
description to the above address.

2747
CHANGES Normal file

File diff suppressed because it is too large Load Diff

339
COPYING Normal file
View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) year 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.
<signature of Ty Coon>, 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 Lesser General
Public License instead of this License.

127
COPYING.OpenSSL Normal file
View File

@@ -0,0 +1,127 @@
LICENSE ISSUES
==============
The OpenSSL toolkit stays under a dual license, i.e. both the conditions of
the OpenSSL License and the original SSLeay license apply to the toolkit.
See below for the actual license texts. Actually both licenses are BSD-style
Open Source licenses. In case of any license issues related to OpenSSL
please contact openssl-core@openssl.org.
OpenSSL License
---------------
/* ====================================================================
* Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/
Original SSLeay License
-----------------------
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/

242
DEVELOPMENT Normal file
View File

@@ -0,0 +1,242 @@
This file should help you to add new address types and address options to
socat.
NOTE:
socat will in future releases be split into a library "libxio" containing all
the address stuff, useful also for many other purposes, and the socat main()
and data shuffler. If you intend to perform major changes to the xio part and
to publish them, please contact me before!
ADDING A NEW ADDRESS TYPE:
* Create new files xio-newaddr.c and xio-newaddr.h
* Create a new record of struct addrdesc in xio-newaddr.c, with declaration in xio-newaddr.h.
* Make a new entry to addressnames[] in xioopen.c with the addresses main name
and maybe with alias names. Keep this array ASCII sorted, without uppercase
chars.
* config.h.in: #undef WITH_NEWADDR
* configure.in: Copy the disable part of, e.g., WITH_SOCKS4 and adapt it to
NEWADDR
* In socat.c, add to socat_version
* Write a function xioopen_newaddr() in xio-newaddr.c, declaration in
xio-newaddr.h
Do not forget the following option processing calls:
All groups: _xio_openlate()
Group FD: applyopts_cloexec()
Group NAMED: applyopts_file() for phases PREOPEN, OPEN, and FD
* Describe a tested example in file EXAMPLES, and maybe in the socat manpage
source.
* Try to define a test for this address type in test.sh
* Update file CHANGES
ADDING A NEW ADDRESS OPTION:
xioopen.c:
* If this option depends on a #define that is probably not available on all
platforms, make all new code for this option dependent on the existence of this
C header define:
#ifdef PREFIX_NEWOPTION
...
#endif
* Add an OPT_NEWOPTION to enum e_optcode in xioopts.h, preferably keeping
alphabetic order
* Add a struct optdesc opt_newoption record in xio-newaddr.c and its
declaration in xio-newaddr.h. The complete structure definition must be in one
line without breaks for automatic docu extraction.
Build the record from the following components:
. A canonical default name (e.g. "newoption")
. A short, preferable name (e.g. "newopt") or NULL
. OPT_NEWOPTION (from enum e_optcode, see above)
. A group membership that restricts appliance of the new option to matching
address types (e.g., one of GROUP_ANY, GROUP_IP_TCP, GROUP_EXEC)
. A phase specification that positions this option within address processing.
Note that the function code can override this value.
. A representation type for option arguments (e.g., TYPE_INT, TYPE_STRING etc.;
use TYPE_BOOL if this option just triggers an action)
. A function or action definition for applying this option. If it does not use
one of the standard functions (open(), ioctl(), setsockopt()...), then use
OFUNC_SPEC (specific).
* For the canonical name and all its aliases and abbreviations, add entries to
the array optionnames in xioopts.c. KEEP STRICT ALPHABETIC (ASCII) ORDER!
The entries must be embedded in an IF_... macro of their group for conditional
compiling.
* For options using some predefined action (see OFUNC above), this might be
enough - test the option and document it in doc/socat.yo!
For OFUNC_SPEC, it might suffice to add another "case" to the OFUNC_SPEC branch
in applyopts() in xioopts.c. If you need more special handling, you should try
to understand the address specific functions and add your code there.
* If you use system or low level C library calls or library calls that might
hang or induce problems, please invoke them with capitalized name; if no such
name is defined, add an appropriate debug function to sycls.c, and a header
entry and a wrapper "define" to sycls.h
* Update file CHANGES
INFO ABOUT ADDRESS PHASES:
Each option entry has a field specifying a default phase for its application.
Of course, the code that analyses and applies an address may override this
default phase.
Depending on the type of address there are several major phase sequences:
OPEN addresses:
PH_INIT retrieving info from original state
PH_EARLY before any other processing
PH_PREOPEN before file creation/opening (not UNIX sockets)
PH_OPEN during file creation/opening (not UNIX sockets)
PH_PASTOPEN past file creation/opening (not UNIX sockets)
PH_FD soon after FD creation or identification
PH_LATE FD is ready, before start of data loop
PH_LATE2 FD is ready, dropping privileges
SOCKET addresses:
PH_INIT retrieving info from original state
PH_EARLY before any other processing
PH_PRESOCKET before socket call
PH_SOCKET for socket call
PH_PASTSOCKET after socket call
PH_FD soon after FD creation or identification
PH_PREBIND before socket bind()
PH_BIND during socket bind()
PH_PASTBIND past socket bind()
PH_PRECONNECT before connect()
PH_CONNECT during connect()
PH_PASTCONNECT after connect()
PH_CONNECTED phase common with listen
PH_LATE FD is ready, before start of data loop
PH_LATE2 FD is ready, dropping privileges
SOCKET with LISTEN and ACCEPT:
PH_INIT retrieving info from original state
PH_EARLY before any other processing
PH_PRESOCKET before socket call
PH_SOCKET for socket call
PH_PREBIND before socket bind()
PH_BIND during socket bind()
PH_PASTBIND past socket bind()
PH_PRELISTEN before listen()
PH_LISTEN during listen()
PH_PASTLISTEN after listen()
PH_PREACCEPT before accept()
PH_ACCEPT during accept()
PH_PASTACCEPT after accept()
# and the following on the new FD:
PH_FD soon after FD creation or identification
PH_PASTSOCKET after socket call
PH_CONNECTED phase common with connect
PH_PREFORK before forking
PH_FORK during fork()
PH_PASTFORK after fork()
PH_LATE FD is ready, before start of data loop
PH_LATE2 FD is ready, dropping privileges
Passive UNIX socket addresses; this is a mix of socket phases and file system phases:
PH_INIT retrieving info from original state
PH_EARLY before any other processing
PH_PRESOCKET before socket call
PH_SOCKET for socket call
PH_PASTSOCKET after socket call
PH_FD soon after FD creation or identification
PH_PREOPEN before file creation/opening
PH_PREBIND before socket bind()
PH_BIND during socket bind()
PH_PASTOPEN past file creation/opening
PH_PASTBIND past socket bind(), not used up to 1.7.3.4
PH_PRECONNECT before connect()
PH_CONNECT during connect()
PH_PASTCONNECT after connect()
PH_CONNECTED phase common with listen
PH_LATE FD is ready, before start of data loop
PH_LATE2 FD is ready, dropping privileges
FD addresses:
PH_INIT retrieving info from original state
PH_EARLY before any other processing
PH_FD soon after FD identification
PH_LATE FD is ready, before start of data loop
PH_LATE2 FD is ready, dropping privileges
EXEC addresses:
PH_INIT retrieving info from original state
PH_EARLY before any other processing
PH_PREBIGEN before socketpair() pipe() openpty()
PH_BIGEN during socketpair() pipe() openpty()
PH_PASTBIGEN past socketpair() pipe() openpty()
PH_PASTSOCKET for socketpair()
PH_FD soon after FD creation or identification
PH_PREFORK before forking
PH_FORK during fork()
PH_PASTFORK after fork()
PH_LATE FD is ready, before start of data loop
PH_LATE2 FD is ready, dropping privileges
PH_PREEXEC before exec() or system()
PH_EXEC during exec() or system()
There are lots of semantic relations between group, phase, and func fields of
an option.
There exists something like an overall phase sequence:
PH_INIT # su-d.1
PH_EARLY # chroot-early
PH_PREOPEN, PH_OPEN, PH_PASTOPEN # (chroot before/after?)
PH_PRESOCKET, PH_SOCKET, PH_PASTSOCKET # (su after (root for raw)?)
PH_PREBIGEN, PH_BIGEN, PH_PASTBIGEN # (chroot before/after (/dev..)?)
PH_FD
PH_PREBIND, PH_BIND, PH_PASTBIND # (su after(before?))
PH_PRELISTEN, PH_LISTEN, PH_PASTLISTEN
PH_PRECONNECT, PH_CONNECT, PH_PASTCONNECT # (chroot before/after (AF_UNIX)?)
PH_PREACCEPT, PH_ACCEPT, PH_PASTACCEPT
PH_CONNECTED
PH_PREFORK, PH_FORK, PH_PASTFORK # (all before/after?)
PH_LATE # chroot
PH_LATE2 # su, su-d.2
PH_PREEXEC, PH_EXEC # (all before)
===============================================================================
// Up to 1.7.2.4 socat used non async signal safe system and library calls in signal handlers, mostly for logging purposes. This problem was fixed in release 1.7.3.0 with the following concepts:
Signal handlers set on entry and unset on return the diag_in_handler global variable. The logging system, when this variable is set, queues the text message together with errno and exit info in a UNIX datagram socket. When invoked with unset diag_in_handler it first checks if there are messages in that queue and prints them first.
A async signal safe but minimal version of vsnprintf, named vsnprintf_r, was written so no value arguments need to be queued.
Because strerror is not async signal safe a new function snprinterr was written that replaces the (glibc compatible) %m format with strerror output. The original errno is passed in the message queue, snprinterr is called when dequeuing messages outside of signal handler.
// List of signal handlers in socat
socat.c:socat_signal (generic, just logs and maybe exits)
xioshutdown.c:signal_kill_pid (SIGALRM, kill child process)
xiosigchld.c:childdied (SIGCHLD: get info, log; possibly close channel)
xiosignal.c:socatsignalpass: cascades signal to channel child processes; w/ options sighup,sigint,sigquit
xio-socket.c:xiosigaction_hasread: SIGUSR1,SIGCHLD, tells parent that datagram has been consumed

456
EXAMPLES Normal file
View File

@@ -0,0 +1,456 @@
// Examples for using socat (and filan)
//"$" means normal user, "#" requires privileges, "//" starts a comment
///////////////////////////////////////////////////////////////////////////////
// Similar to netcat
// Connect to 10.1.1.1 on port 80 and relay to and from stdio
$ socat - TCP:10.1.1.1:80 # similar to "netcat 10.1.1.1 80"
// Listen on port 25, wait for an incoming connection, use CR+NL on this
// connection, relay data to and from stdio;
// then emulate a mailserver by hand :-)
# socat - TCP-LISTEN:25,crlf
// Listen on port 25, wait for an incoming connection, use CR+NL on this
// connection, relay data to and from stdio, but have line editing and history;
// then emulate a mailserver by hand :-)
# socat READLINE TCP-LISTEN:25,crlf
// Provide a transient history enabled front end to stupid line based
// interactive programs
$ socat \
READLINE \
EXEC:"nslookup",pty,ctty,setsid,echo=0
// Same works for ftp (but password is not hidden)
// You may also use a file based history list
$ socat \
READLINE,history=.nslookup_hist \
EXEC:"nslookup",pty,ctty,setsid,echo=0
// Using ~ as abbreviation for $HOME does not work!
// Poor mans 'telnetd' replacement
# socat \
TCP-L:2023,reuseaddr,fork \
EXEC:/bin/login,pty,setsid,setpgid,stderr,ctty
// and here an appropriate client:
$ socat \
-,raw,echo=0 \
TCP:172.16.181.130:2023
// Use ssl with client and server certificate for improved security;
// replace /bin/login by /bin/bash when using SSL client authentication, can be
// run without root then
// This is a cool trick, proposed by Christophe Lohr, to dump communications to
// two files; it would also work for other manipulations (recode, compress...)
// and it might also work with netcat ;-)
$ socat \
TCP-LISTEN:5555 \
SYSTEM:'tee l2r | socat - "TCP:remote:5555" | tee r2l'
///////////////////////////////////////////////////////////////////////////////
// Emergence solution because usleep(1) is not always available
// this will "sleep" for 0.1s
$ socat -T 0.1 PIPE PIPE
///////////////////////////////////////////////////////////////////////////////
// A very primitive HTTP/1.0 echo server (problems: sends reply headers before
// request; hangs if client does not shutdown - HTTP keep-alive)
// wait for a connection on port 8000; do not wait for request, but immediately
// start a shell that sends reply headers and an empty line; then echo all
// incoming data back to client
$ socat \
TCP-LISTEN:8000,crlf \
SYSTEM:"echo HTTP/1.0 200; echo Content-Type\: text/plain; echo; cat"
// A less primitive HTTP echo server that sends back not only the reqest but
// also server and client address and port. Might have portability issues with
// echo
$ socat -T 1 -d -d \
TCP-L:10081,reuseaddr,fork,crlf \
SYSTEM:"echo -e \"\\\"HTTP/1.0 200 OK\\\nDocumentType: text/html\\\n\\\n<html>date: \$\(date\)<br>server:\$SOCAT_SOCKADDR:\$SOCAT_SOCKPORT<br>client: \$SOCAT_PEERADDR:\$SOCAT_PEERPORT\\\n<pre>\\\"\"; cat; echo -e \"\\\"\\\n</pre></html>\\\"\""
///////////////////////////////////////////////////////////////////////////////
// For communicating with an attached modem, I had reasonable results with
// following command line. Required privileges depend on device mode.
// After leaving socat, type "sane".
// Replace /dev/ttyS0 by the correct serial line or with /dev/modem
$ socat \
READLINE \
/dev/ttyS0,raw,echo=0,crlf
// or
$ socat \
READLINE \
/dev/ttyS0,raw,echo=0,crlf,nonblock
// then enter "at$"
///////////////////////////////////////////////////////////////////////////////
// Relay TCP port 80 from everywhere (internet, intranet, dmz) through your
// firewall to your DMZ webserver (like plug-gw)
// Listen on port 80; whenever a connection is made, fork a new process (parent
// Process keeps accepting connections), su to nobody, and connect to
// www.dmz.mydomain.org on port 80.
// Attention: this is a substitute for a reverse proxy without providing
// application level security.
# socat \
TCP-LISTEN:80,reuseaddr,fork,su=nobody \
TCP:www.dmz.mydomain.org:80
// Note: parent process keeps running as root, su after forking
///////////////////////////////////////////////////////////////////////////////
// Relay mail from your DMZ server through your firewall.
// accept connections only on dmz interface and allow connections only from
// smtp.dmz.mydomain.org.
// the advantages over plug-gw and other relays are:
// * you can bind to an IP address (even an alias), therefore enhance security
// * in your OS you can create several IP aliases and bind another socat daemon
// to each, making several application servers addressable
// * lots of options, like switching user, chroot, IP performance tuning
// * no need for inetd
# socat -lm -d -d \
TCP-LISTEN:25,bind=fw.dmz.mydomain.org,fork,su=nobody,range=smtp.dmz.mydomain.org/32 \
TCP:smtp.intra.mydomain.org:25
///////////////////////////////////////////////////////////////////////////////
// Convert line terminator in ascii streams, stdin to stdout
// use unidirectional mode, convert nl to crnl
$ socat -u - -,crlf
// or cr to nl
$ socat -u -,cr -
// Save piped data similar to 'tee':
// copies stdin to stdout, but writes everything to the file too
$ socat \
-,echo=0 \
OPEN:/tmp/myfile,create,trunc,ignoreeof!!/tmp/myfile
///////////////////////////////////////////////////////////////////////////////
// Intrusion testing
// Found an XWindow Server behind IP filters with FTP data hole? (you are
// lucky!)
// prepare your host:
# rm -f /tmp/.X11-unix/X1
// relay a pseudo display :1 on your machine to victim:0
# socat \
UNIX-LISTEN:/tmp/.X11-unix/X1,fork \
TCP:host.victim.org:6000,sp=20 &
// and try to take a screendump (must be very lucky - when server has not even
// host based authentication!)
# xwd -root -display :1 -silent >victim.xwd
// You sit behind a socks firewall that has IP filters but lazily allows socks
// connections to loopback and has only host based X11 security.
// like above, but from your inside client:
# socat \
UNIX-LISTEN:/tmp/.X11-unix/X1,fork \
SOCKS4:firewall:loopback:6000
// or for the HTTP proxy:
# socat \
UNIX-LISTEN:/tmp/.X11-unix/X1,fork \
PROXY:firewall:loopback:6000
///////////////////////////////////////////////////////////////////////////////
// forms of stdin with stdout, all equivalent
$ socat PIPE -
$ socat PIPE STDIO
$ socat PIPE STDIN!!STDOUT
$ socat PIPE STDIO!!STDIO
$ socat PIPE -!!-
$ socat PIPE FD:0!!FD:1
$ socat PIPE 0!!1
$ socat PIPE /dev/stdin!!/dev/stdout // when your OS provides these
///////////////////////////////////////////////////////////////////////////////
// some echo address examples
$ socat - PIPE
$ socat - PIPE:/tmp/pipi // other version of echo
$ socat - PIPE:/tmp/pipi,nonblock!!/tmp/pipi // other version of echo
$ socat - EXEC:/bin/cat // another echo
$ socat - SYSTEM:/bin/cat // another echo
$ socat - TCP:loopback:7 // if inetd echo/TCP service activated
$ socat - UDP:loopback:7 // if inetd echo/UDP service activated
$ socat - /tmp/hugo,trunc,ignoreeof!!/tmp/hugo // with delay
$ socat - UDP:loopback:2000,bind=:2000 // self "connection"
$ socat - TCP:loopback:2000,bind=:2000 // Linux bug?
# socat - IP:loopback:222 // raw protocol, self "connected" (attention,
// Linux might drop packets with less than 8 bytes payload)
///////////////////////////////////////////////////////////////////////////////
// unidirectional data transfer
$ socat -u - -
// like "tail -f", but start with showing all file contents:
$ socat -u FILE:/var/log/syslog.debug,ignoreeof -
// like "tail -f", but do not show existing file contents:
$ socat -u FILE:/var/log/syslog.debug,ignoreeof,seek-end -
// write to new file, create with given permission and group (must be member) - race condition with group!!!
$ socat -u - CREATE:/tmp/outfile1,group=floppy,perm=0640
//
// for an existing file /tmp/outfile1
# socat -u - FILE:/tmp/outfile1,group=floppy,perm=0700,user=4321
///////////////////////////////////////////////////////////////////////////////
// File handling
$ socat - FILE:/tmp/outfile1,ignoreeof!!FILE:/tmp/outfile1,append // prints outfile1, then echoes input and protocols into file (appends to old data)
///////////////////////////////////////////////////////////////////////////////
// UNIX socket handling
// Create a listening unix socket
$ rm -f /tmp/mysocket; socat UNIX-LISTEN:/tmp/mysocket -
// From another terminal, connect to this socket
$ socat UNIX:/tmp/mysocket -
// then transfer data bidirectionally
///////////////////////////////////////////////////////////////////////////////
// Transport examples
// Socks relay (externally socksify applications);
// your ssh client and OS are not socksified, but you want to pass a socks
// server with ssh:
$ socat \
TCP-LISTEN:10022,fork \
SOCKS4:socks.mydomain.org:ssh-serv:22
$ ssh -p 10022 loopback
// or better define a ProxyCommand in ~/.ssh/config:
ProxyCommand socat - SOCKS:socks.mydomain.org:%h:%p
// and with proxy:
ProxyCommand socat - PROXY:proxy.mydomain.org:%h:%p,proxyport=8000
///////////////////////////////////////////////////////////////////////////////
// Application examples
// run sendmail daemon with your favorite network options
# socat \
TCP-LISTEN:25,fork,ip-ttl=4,ip-tos=7,tcp-maxseg=576 \
EXEC:"/usr/sbin/sendmail -bs",nofork
// Local mail delivery over UNIX socket - no SUID program required
# socat \
UNIX-LISTEN:/tmp/postoffice,fork,perm-early=0666 \
EXEC:"/usr/sbin/sendmail -bs"
$ socat - /tmp/postoffice
///////////////////////////////////////////////////////////////////////////////
// Uses of filan
// See what your operating system opens for you
$ filan
// or if that was too detailled
$ filan -s
// See what file descriptors are passed via exec function
$ socat - EXEC:"filan -s",nofork
$ socat - EXEC:"filan -s"
$ socat - EXEC:"filan -s",pipes,stderr
$ socat - EXEC:"filan -s",pipes
$ socat - EXEC:"filan -s",pty
// see what's done by your shell and with option "pipes"
$ socat - SYSTEM:"filan -s",pipes
// see if gdb gives you an equivalent environment or opens some files for your program
$ gdb ./filan
(gdb) r -s
(gdb) r
///////////////////////////////////////////////////////////////////////////////
// Want to use chat from the ppp package?
// Note: some OS's do not need "-e" for echo to print control characters
// Note: chat might send bytes one by one
// With AIX, a similar program is available under the name "pppdial"
$ socat -d -d \
TCP:localhost:25,crlf,nodelay \
EXEC:'/usr/sbin/chat -v -s "\"220 \"" "\"HELO loopback\"" "\"250 \"" "\"MAIL FROM: <hugo@localhost>\"" "\"250 \"" "\"RCPT TO: root\"" "\"250 \"" "\"DATA\"" "\"354 \"" "\"test1'$(echo -e "\r.")'\"" "\"250 \"" "\"QUIT\"" "\"221 \""',pty,echo=0,cr
//////////////////////////////////////////////////////////////////////////////
// IP6
# socat \
READLINE \
TCP6:[::1]:21 # if your inetd/ftp is listening on ip6
//////////////////////////////////////////////////////////////////////////////
// VSOCK
# Start a linux VM with cid=21
# qemu-system-x86_64 -m 1G -smp 2 -cpu host -M accel=kvm \
# -drive if=virtio,file=/path/to/fedora.img,format=qcow2 \
# -device vhost-vsock-pci,guest-cid=21
# guest listens on port 1234 and host connects to it
guest$ socat - VSOCK-LISTEN:1234
host$ socat - VSOCK-CONNECT:21:1234
# Host (well know CID_HOST = 2) listens on port 4321 and guest connects to it
host$ socat - VSOCK-LISTEN:4321
guest$ socat - VSOCK-CONNECT:2:4321
///////////////////////////////////////////////////////////////////////////////
// Application server solutions
// Run a program (here: /bin/sh) chrooted, unprivileged;
// parent process stays in real / running as root
# socat -d -d - EXEC:/bin/sh,chroot=/home/sandbox,su=sandbox,pty
// Make a program available on the network chrooted, unprivileged;
// parent process stays in / running as root
// script path is already chrooted
# ./socat -lm -d -d \
TCP-LISTEN:5555,fork \
EXEC:/bin/myscript,chroot=/home/sandbox,su=sandbox,pty,stderr
// To avoid terminal problems, you might - instead of telnet - connect using
$ socat \
-,icanon=0,echo=0 \
TCP:target:5555; reset
// Access local display from ssh server, when ssh port forwarding is disabled
// Socat must be installed on ssh server host
// Might have to use xauth...
// This example is one-shot because ssh can handle only one channel
xterm1$ socat -d -d \
EXEC:"ssh www.dest-unreach.org rm -f /tmp/.X11-unix/X9; ~/bin/socat -d -d unix-l\:/tmp/.X11-unix/X9\,fork -" \
UNIX:/tmp/.X11-unix/X0
xterm2$ ssh target
target$ DISPLAY=:9 myxapplication
// Touch with perms:
// no race condition for perms (applied with creat() call)
$ socat -u \
/dev/null \
CREAT:/tmp/tempfile,perm=0600
// Touch with owner and perms:
// race condition before changing owner, but who cares - only root may access
# socat -u \
/dev/null \
CREAT:/tmp/tempfile,user=user1,perm=0600
// Invoke an interactive ssh with EXEC
// First example passes control chars (^C etc.) to remote server as usual
socat \
-,echo=0,raw \
EXEC:'ssh server',pty,setsid,ctty
// Second example interprets control chars on local command line
socat \
-,echo=0,icanon=0 \
EXEC:'ssh server',pty,setsid,ctty
// afterwards, type "reset"!
// Convince ssh to provide an "interactive" shell to your script
// three main versions for entering password:
// 1) from your TTY; have 10 seconds to enter password:
(sleep 10; echo "ls"; sleep 1) |socat - EXEC:'ssh server',pty
// 2) from XWindows (DISPLAY !); again 10 seconds
(sleep 10; echo "ls"; sleep 1) |socat - EXEC:'ssh server',pty,setsid
// 3) from script
(sleep 5; echo PASSWORD; echo ls; sleep 1) |./socat - EXEC:'ssh server',pty,setsid,ctty
// Download with proxy CONNECT
// use echo -e if required for \n
$ (echo -e "CONNECT 128.129.130.131:80 HTTP/1.0\n"; sleep 5; echo -e "GET /download/file HTTP/1.0\n"; sleep 10) |
socat -d -d -t 3600 - tcp:proxy:8080,crlf
// Retrieve a file from an sshd site with sourceforge style entry menu;
// fill in your personal values; cat lets you enter your password (will be
// visible on screen)
$ (sleep 10; read pass; echo $pass; sleep 10; echo M; sleep 5; echo cat FILENAME; sleep 10) |
./socat -d -d -ly - EXEC:'ssh -c 3des -l USER cf.sourceforge.net',pty,setsid,ctty |
tee FILENAME
// Multicast community on local network: start the following command on all
// participating hosts; like a conference call:
# socat -d -d -d -d - \
UDP-DATAGRAM:224.0.0.2:6666,bind=:6666,ip-add-membership=224.0.0.2:eth0,bindtodevice=eth0
// or
$ socat -d -d -d -d - \
UDP-DATAGRAM:224.0.0.2:6666,bind=:6666,ip-add-membership=224.0.0.2:eth0
// Possible reasons for failure:
// iptables or other filters (open your filters as required)
// Packets leave via wrong interface (set route: ...)
// Socket bound to specific address
//=============================================================================
// GENERIC FUNCTION CALLS
// ioctl(): open CD drive (given value valid on Linux)
// on my Linux system I find in /usr/include/linux/cdrom.h the define:
// #define CDROMEJECT 0x5309 /* Ejects the cdrom media */
// The following command makes something like ioctl(fd, CDROMEJECT, NULL)
// (don't care about the read error):
$ socat /dev/cdrom,o-nonblock,ioctl-void=0x5309 -
// setsockopt(): SO_REUSEADDR
// The following command performs - beyond lots of overhead - something like:
// myint=1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &myint, sizeof(myint))
$ socat -u UDP-RECV:7777,setsockopt-int=1:2:1 -
// setsockopt(): SO_BINDTODEVICE
// Ways to apply SO_BINDTODEVICE without using the special socat address option
// so-bindtodevice:
// with string argument:
$ sudo socat TCP-L:7777,setsockopt-string=1:25:eth0 PIPE
// with binary argument:
$ sudo socat TCP-L:7777,setsockopt-bin=1:25:x6574683000 PIPE
===============================================================================
// Not tested, just ideas, or have problems
// Traverse firewall for making internal telnet server accessible for outside
// telnet client, when only outbound traffic (syn-filter) is allowed:
// on external client run "double server". this process waits for a
// connection from localhost on port 10023, and, when it is established, waits
// for a connection from anywhere to port 20023:
ext$ socat -d \
TCP-LISTEN:10023,range=localhost \
TCP-LISTEN:20023
// on internal server run double client:
int$ socat -d \
TCP:localhost:23 \
TCP:extclient:10023
// or, with socks firewall:
int$ socat -d \
TCP:localhost:23 \
SOCKS:socksserver:extclient:10023
// login with:
ext$ telnet localhost 20023
// YOU can make a double server capable of handling multiple instances:
ext$ socat -d \
TCP-LISTEN:10023,range=localhost,fork \
TCP-LISTEN:20023,reuseaddr
// Access remote display via ssh, when ssh port forwarding is disabled
$ socat -d -d \
EXEC:"ssh target socat - UNIX:/tmp/.X11-unix/X0" \
TCP-LISTEN:6030
$ xclock -display localhost:30
// Relay multiple webserver addresses through your firewall into your DMZ:
// Make IP aliases on your firewall, and then:
# socat -d -d \
TCP-L:80,bind=fw-addr1,fork \
TCP:dmz-www1:80
# socat -d -d \
TCP-L:80,bind=fw-addr2,fork \
TCP:dmz-www2:80
// and for improved security:
# socat -d -d \
TCP-L:80,bind=fw-addr3,su=nobody,fork \
TCP:dmz-www3:80
// Proxy an arbitrary IP protocol over your firewall (answers won't work)
# socat -d -d \
IP:0.0.0.0:150,bind=fwnonsec \
IP:sec-host:150,bind=fwsec
// Proxy an unsupported IP protocol over your firewall, point to point
// end points see firewall interfaces as IP peers!
# socat -d -d \
IP:nonsec-host:150,bind=fwnonsec \
IP:sec-host:150,bind=fwsec
// note that, for IPsec, you might face problems that are known with NAT

96
FAQ Normal file
View File

@@ -0,0 +1,96 @@
Q: What is the clue of socat?
A: socat probably doesn't have any clue. It is more an attempt to smoothly
integrate similar I/O features that are usually handled differently under
UNIX.
Q: What does the prefix XIO mean?
A: XIO means "extended input/output". It is a library/API that provides a
common way for handling files, sockets and other forms of I/O. Its advantage is
that the application may reduce its I/O to open / read+write / close calls,
while the user controls all I/O details (and even basic process properties) by
packing options into the filename string. This is the basic part of socat.
Q: Is there a Windows port of socat available?
A: Try with Cygwin from http://www.cygwin.com/, or upgrade to Linux.
Q: I succeeded to configure and make socat, but ./test.sh says something
like:
./test.sh: No such file or directory
A: You need a bash shell in your executable path (locations in $PATH)
Q: configure disables readline / openssl / libwrap support because it does not
find an include file / the library. How can I tell configure where these files
are?
A: For include locations, use the environment variable CPPFLAGS, for library
locations use LIBS, e.g.:
export CPPFLAGS="-I/home/user/ssl/include"
export LIBS="-L/home/user/ssl/lib"
On some systems (SunOS), you might also need to set LD_LIBRARY_PATH:
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/home/user/ssl/lib"
Then try again:
make distclean; ./configure; make
Q: I succeeded to make socat, but the test.sh script fails for many tests.
Is my socat build corrupt?
A: Probably your socat program is ok; the tests have been developed on Linux
2.4, and there they usually succeed.
But the following OS differences result in errors on non Linux systems:
* Linux allows to bind a socket to any address of range 127.0.0.0/8, not
only 127.0.0.1. Some tests are built on this feature, but they might fail on
other systems.
* Your OS might have no IP6 implementation
* MacOS X has some difficulties, e.g. distinguishing sockets and pipes.
* the OpenSSL tests require OpenSSL support by socat, must have openssl in
$PATH, and "openssl s_server ..." needs enough entropy to generate a key.
Q: When I specify a dual address (two partial addresses linked with "!!") on
the command line, I get some message "event not found", and my shell history
has the line truncated. Not even protecting the '!'s with '\' helps.
A: '!' is appearently used by your shell as history expansion character. Say
"set +H" and add this line to your (bash) profile.
Q: On Solaris, socat was built successfully, but when started, it gets killed
with something like "ld.so.1: ./socat: fatal: libreadline.so.4: open failed: no
such file or directory"
A: The configure script finds your libreadline, but the runtime loader
doesn't. Add the directory where the library resides to your LD_LIBRARY_PATH
variable, e.g.:
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/sfw/lib/
make distclean; ./configure; make
Q: On Solaris, socat was built successfully, but when started, an assertion
fails: "xioinitialize.c:25: failed assertion `3 << opt_crdly.arg3 == CRDLY'
A: Probably, in a second attempt you set the correct LD_LIBARY_PATH for socat,
but it had not been set during the ./configure run, or you did not "make clean"
before running configure. Try it again:
make distclean; ./configure; make
Q: A socat process, run in background from an interactive shell, is always
stopped with all its child processes after about 5 minutes. killall -9 socat is
required to clean the system and allow socat to be started again.
A: The terminal (window) might have the TOSTOP flag set and one of the socat
processes wants to write to the terminal. Clear this flag in your shell:
stty -tostop
and start socat again.
Thanks to Philippe Teuwen for reporting this situation.

81
FILES Normal file
View File

@@ -0,0 +1,81 @@
The socat distribution contains the following files:
* README: an introduction to socat
* FILES: a navigator through the socat distribution (this file)
* EXAMPLES: a collection of simple examples how to use socat.
* COPYING: what you and others are allowed to do with socat.
* PORTING: instructions and tips if you want to try socat on a new platform.
* BUGREPORTS: instructions what to do with problems and contributions.
* SECURITY: tips if you want to use socat in a security relevant environment.
* DEVELOPMENT: infos for programmers
* VERSION: the version of the socat distribution, for inclusion during
compilation
* CHANGES: what happened since first public release
* socat.1: man page of socat
* socat.html: html version of man page
* daemon.sh: example shell script for running socat as TCP relay daemon
* ftp.sh: example shell based ftp client, using socat for transport
* mail.sh: example shell based smtp client, for execution by socat
* gatherinfo.sh: shell script for gathering info about platform and socat
implementation
* server.pem: a self signed test cerificate, for self test only
The source code system:
* configure: the autoconf generated configurator script
* Makefile.in: the Makefile source input to configure
* config.h.in: the config.h source input to configure
* Config/config.<platform>.h: sample config.h for platform.
* Config/Makefile.<platform>: sample Makefile for platform.
Copy the appropriate files to ./config.h and ./Makefile if configure fails
* socat.c: the main C source, including option parsing, general control, and
the data shuffler
* xio-*.c, xio-*.h: the source of the different address type implementations
with all their modes and options
* xio*.c, xio*.h: the source of the xio API and xio utilities
* filan.c, filan.h: file descriptor analyzer function
* dalan.c, dalan.h: data language, a most primitive subset of what should
become a language for describing/generating all kinds of binary data.
* error.c, error.h: the logging subsystem
* sycls.c, sycls.h: explicit system call and C library trace functions
* sslcls.c, sslcls.h: explicit openssl call trace functions
* xioconfig.h: ensures some dependencies between configure WITH defines; to be
included immediately after config.h
* sysutils.c, sysutils.h: some more general system (socket, IP) related
functions, e.g. converting socket addresses to human readable form
* utils.c, utils.h: useful additions to C library; currently memdup, binary
search, and setenv.
* mytypes.h: some types and macros I miss in C89
* test.sh: an incomplete attempt to automate tests of socat
* compat.h: ensure some features that might be missing on some platforms

208
Makefile.in Normal file
View File

@@ -0,0 +1,208 @@
# source: Makefile.in
# Copyright Gerhard Rieger and contributors (see file CHANGES)
# Published under the GNU General Public License V.2, see file COPYING
# note: @...@ forms are filled in by configure script
SHELL = /bin/sh
AR = @AR@
RANLIB = @RANLIB@
.SUFFIXES: .c .o
prefix = @prefix@
exec_prefix = @exec_prefix@
BINDEST = @bindir@
datarootdir = @datarootdir@
MANDEST = @mandir@
srcdir = @srcdir@
VPATH = @srcdir@
CC = @CC@
#CCOPT1=-no-pie -fstack-protector
#CCOPT=$(CCOPT1) -fcf-protection=none # for gdb on Ubuntu-20.04
CCOPTS = $(CCOPT)
SYSDEFS = @SYSDEFS@
CPPFLAGS = -I. @CPPFLAGS@
#0 INCLS = -I. @V_INCL@
DEFS = @DEFS@
LIBS = @LIBS@
LDFLAGS = @LDFLAGS@
INSTALL = @INSTALL@
#OBJ = $(CSRC:.c=.o) $(GENSRC:.c=.o) @LIBOBJS@
#0 CFLAGS = @CFLAGS@ $(CCOPTS) $(DEFS) $(INCLS)
CFLAGS = @CFLAGS@ $(CCOPTS) $(DEFS) $(CPPFLAGS)
CLIBS = $(LIBS)
#CLIBS = $(LIBS) -lm -lefence
XIOSRCS = xioinitialize.c xiohelp.c xioparam.c xiodiag.c xioopen.c xioopts.c \
xiosignal.c xiosigchld.c xioread.c xiowrite.c \
xiolayer.c xioshutdown.c xioclose.c xioexit.c \
xio-process.c xio-fd.c xio-fdnum.c xio-stdio.c xio-pipe.c \
xio-socketpair.c xio-gopen.c xio-creat.c xio-file.c xio-named.c \
xio-socket.c xio-interface.c xio-listen.c xio-unix.c xio-vsock.c \
xio-ip.c xio-ip4.c xio-ip6.c xio-ipapp.c xio-tcp.c \
xio-sctp.c xio-dccp.c xio-rawip.c xio-posixmq.c \
xio-socks.c xio-socks5.c xio-proxy.c xio-udp.c xio-udplite.c \
xio-progcall.c xio-exec.c xio-system.c xio-shell.c \
xio-termios.c xio-readline.c \
xio-pty.c xio-openssl.c xio-streams.c xio-namespaces.c \
xio-ascii.c xiolockfile.c xio-tcpwrap.c xio-fs.c xio-tun.c
XIOOBJS = $(XIOSRCS:.c=.o)
UTLSRCS = error.c dalan.c procan.c procan-cdefs.c hostan.c fdname.c sysutils.c utils.c nestlex.c vsnprintf_r.c snprinterr.c @FILAN@ sycls.c @SSLCLS@
UTLOBJS = $(UTLSRCS:.c=.o)
CFILES = $(XIOSRCS) $(UTLSRCS) socat.c procan_main.c filan_main.c
OFILES = $(CFILES:.c=.o)
PROGS = socat procan filan
HFILES = sycls.h sslcls.h error.h dalan.h procan.h filan.h hostan.h sysincludes.h xio.h xioopen.h sysutils.h utils.h nestlex.h vsnprintf_r.h snprinterr.h compat.h \
xioconfig.h mytypes.h xioopts.h xiodiag.h xiohelp.h xiosysincludes.h \
xiomodes.h xiolayer.h xio-process.h xio-fd.h xio-fdnum.h xio-stdio.h \
xio-named.h xio-file.h xio-creat.h xio-gopen.h xio-pipe.h \
xio-socketpair.h xio-socket.h xio-interface.h xio-listen.h xio-unix.h xio-vsock.h \
xio-ip.h xio-ip4.h xio-ip6.h xio-rawip.h xio-posixmq.h \
xio-ipapp.h xio-tcp.h xio-udp.h xio-sctp.h xio-dccp.h xio-udplite.h \
xio-socks.h xio-socks5.h xio-proxy.h xio-progcall.h xio-exec.h \
xio-system.h xio-shell.h xio-termios.h xio-readline.h \
xio-pty.h xio-openssl.h xio-streams.h xio-namespaces.h \
xio-ascii.h xiolockfile.h xio-tcpwrap.h xio-fs.h xio-tun.h
DOCFILES = README README.FIPS CHANGES FILES EXAMPLES PORTING SECURITY DEVELOPMENT doc/socat.yo doc/socat.1 doc/socat.html FAQ BUGREPORTS COPYING COPYING.OpenSSL doc/dest-unreach.css doc/socat-openssltunnel.html doc/socat-multicast.html doc/socat-tun.html doc/socat-genericsocket.html
SHFILES = socat-chain.sh socat-mux.sh socat-broker.sh \
daemon.sh mail.sh ftp.sh readline.sh \
socat_buildscript_for_android.sh
TESTFILES = test.sh socks4echo.sh proxyecho.sh readline-test.sh \
proxy.sh socks4a-echo.sh
all: progs doc
scmclean: gitclean
gitclean: distclean docclean
rm -f Makefile.bak configure
doc: doc/socat.1 doc/socat.html
docclean:
rm -f doc/socat.1 doc/socat.html
doc/socat.1: doc/socat.yo
-mkdir -p $(@D); yodl2man -o $@ $+
doc/socat.html: doc/socat.yo
# care for refs in html
-mkdir -p $(@D); cd $(@D); yodl2html -o socat.html ../$+; cd ..
progs: $(PROGS)
depend: $(CFILES) $(HFILES)
makedepend $(SYSDEFS) $(CFILES)
socat: socat.o libxio.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ socat.o libxio.a $(CLIBS)
procan.o: procan.c
$(CC) $(CFLAGS) -c -D CC=\"$(CC)\" -o $@ procan.c
PROCAN_OBJS=procan_main.o procan.o procan-cdefs.o hostan.o error.o sycls.o sysutils.o utils.o vsnprintf_r.o snprinterr.o
procan: $(PROCAN_OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(PROCAN_OBJS) $(CLIBS)
FILAN_OBJS=filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o vsnprintf_r.o snprinterr.o
filan: $(FILAN_OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(FILAN_OBJS) $(CLIBS)
libxio.a: $(XIOOBJS) $(UTLOBJS)
$(AR) r $@ $(XIOOBJS) $(UTLOBJS)
$(RANLIB) $@
strip: progs
strip $(PROGS)
install: progs $(srcdir)/doc/socat.1
mkdir -p $(DESTDIR)$(BINDEST)
$(INSTALL) -m 755 socat $(DESTDIR)$(BINDEST)/socat1
ln -sf socat1 $(DESTDIR)$(BINDEST)/socat
$(INSTALL) -m 755 socat-chain.sh $(DESTDIR)$(BINDEST)
$(INSTALL) -m 755 socat-mux.sh $(DESTDIR)$(BINDEST)
$(INSTALL) -m 755 socat-broker.sh $(DESTDIR)$(BINDEST)
$(INSTALL) -m 755 procan $(DESTDIR)$(BINDEST)
$(INSTALL) -m 755 filan $(DESTDIR)$(BINDEST)
mkdir -p $(DESTDIR)$(MANDEST)/man1
$(INSTALL) -m 644 $(srcdir)/doc/socat.1 $(DESTDIR)$(MANDEST)/man1/socat1.1
ln -sf socat1.1 $(DESTDIR)$(MANDEST)/man1/socat.1
uninstall:
rm -f $(DESTDIR)$(BINDEST)/socat
rm -f $(DESTDIR)$(BINDEST)/socat1
rm -f $(DESTDIR)$(BINDEST)/socat-chain.sh
rm -f $(DESTDIR)$(BINDEST)/socat-mux.sh
rm -f $(DESTDIR)$(BINDEST)/socat-broker.sh
rm -f $(DESTDIR)$(BINDEST)/procan
rm -f $(DESTDIR)$(BINDEST)/filan
rm -f $(DESTDIR)$(MANDEST)/man1/socat.1
rm -f $(DESTDIR)$(MANDEST)/man1/socat1.1
# make a GNU-zipped tar ball of the source files
dist: socat.tar.gz socat.tar.bz2
socat.tar.gz: socat.tar
gzip -9 <socat.tar >socat.tar.gz
socat.tar.bz2: socat.tar
bzip2 -9 <socat.tar >socat.tar.bz2
VERSION = `sed 's/"//g' VERSION`
TARDIR = socat-$(VERSION)
socat.tar: configure.in configure Makefile.in config.h.in install-sh VERSION $(CFILES) $(HFILES) $(DOCFILES) $(SHFILES) $(TESTFILES) socat.spec \
configure.ac
if [ ! -d $(TARDIR) ]; then mkdir $(TARDIR); fi
tar cf - $+ |(cd $(TARDIR); tar xf -)
tar cvf socat.tar $(TARDIR)
rm -f $(TARDIR)/COPYING # write protected
rm -r $(TARDIR)
clean:
rm -f *.o libxio.a socat procan filan \
socat.tar socat.tar.Z socat.tar.gz socat.tar.bz2 \
socat.out compile.log test.log
# remove all files that are generated from the original socat distribution
# note that Makefile is also removed, so you have to start with ./configure
# again
distclean: clean
rm -f config.status config.cache config.log config.h Makefile
rm -rf autom4te.cache
info: socat
uname -a >socat.out
./socat -V >>socat.out
./socat -hh >>socat.out
# perform some tests on socat
test: progs
./test.sh
cert:
# prepare critical files with correct permissions to avoid race cond
>cert.key
>cert.pem
chmod 600 cert.key cert.pem
# generate a private key
openssl genrsa -out cert.key 1024
# generate a self signed cert
openssl req -new -key cert.key -x509 -days 3653 -out cert.crt
# ...enter fields
# generate the pem file
cat cert.key cert.crt >cert.pem
#echo use cert.pem on requestors side, i.e. with option cert=cert.pem
#echo use cert.crt on checkers side, i.e. with option cafile=cert.crt

72
PORTING Normal file
View File

@@ -0,0 +1,72 @@
DEVELOPMENT PLATFORMS
Primary development platform for socat is currently SuSE Linux 8.2 with
a 2.4.20 kernel. New features are then ported to the non-Linux platforms on the
Sourceforge compile farm (per July 2003: SunOS 5.8 with gcc, and MacOS X 10.2),
and AIX 5.1 with gcc. But due to limited time resources and restricted
(non-root) access to these systems I cannot extensively test socat there.
PORTING STEPS
If you want to port socat to another operating system you will typically go
through two phases: First, you might just try to compile and run the actual
socat distribution (passive phase). Then, you should see if your platform
has some nice features that are not yet used in socat, and add code for
supporting them (active phase). At last, I encourage you to send me your
changes so I can integrate them into the main socat distribution.
PASSIVE PHASE:
* Generate Makefile and config.h:
. If you have gcc, then just invoke "./configure".
. If you use another C compiler, configure might not work properly;
You will have to adapt config.h and Makefile manually.
Change compiler options or defines to use all features of the operating
system (not only ANSI-C; e.g. HP-UX: -Ae!)
Some practical config.<platform>.h examples have been included in the
Config directory of the source that might serve as starting point.
* Try to "make" socat; correct the errors. If some constants are undefined,
please disable these parts option-dependent, not platform-dependent (use
#ifdef TCP_OPTION instead of #if MY_OS)
* If you have big troubles compiling socat then try configure with options
--disable-filan --disable-sycls; this excludes some of the most system
dependent parts.
* After successful compilation and linking, run "make test" and try some
examples.
ACTIVE PHASE:
* Check the man pages of your operating system for open(2), fcntl(2),
setsockopt(2), ioctl(2), socket(7), ip(7), tcp(7), termios etc. and the
include files where you find the definitions of existing options, for new
options and implement them - again option-dependent.
Places to add code for the new options:
. xioopts.h: enum e_optcode (sorted numerically/alphabetically by name)
. xio-*.c: select the appropriate address file (e.g., xio-tcp.c for
TCP-options) and make a record of type struct optdesc: opt_newoption
. xio-*.h: the declation of struct optdesc
. xioopts.c: add records to struct optname optionnames for all appropriate
names (sorted strictly ASCII for binary search)
. filan.c: add the option to the appropriate array (sockopts, ipopts,
tcpopts)
. socat.html, socat.1: write a short documentation and tell which
platform and version implements this option
* problems may occur especially:
. with 16 or 64 bit systems
. if snprintf() etc. is missing
. on UNIX emulations, e.g. Cygwin
INTEGRATION
* If you ported socat to another platform:
To let other people participate please send the modified files or a patch
file and the files generated by ./gatherinfo.sh to socat@dest-unreach.org.

287
README Normal file
View File

@@ -0,0 +1,287 @@
about
-----
socat is a relay for bidirectional data transfer between two independent data
channels. Each of these data channels may be a file, pipe, device (serial line
etc. or a pseudo terminal), a socket (UNIX, IP4, IP6 - raw, UDP, TCP), an
SSL socket, proxy CONNECT connection, a file descriptor (stdin etc.), the GNU
line editor (readline), a program, or a combination of two of these.
These modes include generation of "listening" sockets, named pipes, and pseudo
terminals.
socat can be used, e.g., as TCP port forwarder (one-shot or daemon), as an
external socksifier, for attacking weak firewalls, as a shell interface to UNIX
sockets, IP6 relay, for redirecting TCP oriented programs to a serial line, to
logically connect serial lines on different computers, or to establish a
relatively secure environment (su and chroot) for running client or server
shell scripts with network connections.
Many options are available to refine socats behaviour:
terminal parameters, open() options, file permissions, file and process owners,
basic socket options like bind address, advanced socket options like IP source
routing, linger, TTL, TOS (type of service), or TCP performance tuning.
More capabilities, like daemon mode with forking, client address check,
"tail -f" mode, some stream data processing (line terminator conversion),
choosing sockets, pipes, or ptys for interprocess communication, debug and
trace options, logging to syslog, stderr or file, and last but not least
precise error messages make it a versatile tool for many different purposes.
In fact, many of these features already exist in specialized tools; but until
now, there does not seem to exists another tool that provides such a generic,
flexible, simple and almost comprehensive (UNIX) byte stream connector.
packages
--------
before bothering with compilers, dependencies and include files, you might
try to get a binary distribution that matches your platform. Have a look at
the projects home page for actual information regarding socat binary
distributions.
platforms
---------
socat 1.8.0 was compiled and more or less successfully tested under the
following operating systems:
Debian 4 on x86_64
FreeBSD 10 on amd64
OpenBSD 7.2 on amd64
OpenIndiana 2021-04 on i386 with gcc
Ubuntu 10.04 on i386
Ubuntu 12..22
Rocky 9
Cygwin 10.0
install
-------
Get the tarball and extract it:
tar xzf socat.tar.gz
cd socat-1.8.0.0
./configure
make
su
make install # installs socat, filan, and procan in /usr/local/bin
For compiling socat, gcc (or clang) is recommended.
If gcc (or a compiler with similar front end) is not available, the configure
script might fail to determine some features
If you have problems with the OpenSSL library, you can apply the option
"--disable-openssl" to configure.
If you have problems with the readline library or (n)curses, you can apply the
option "--disable-readline" to configure.
If you have problems with the tcp wrappers library, you can apply the option
"--disable-libwrap" to configure.
If you still get errors or a tremendous amount of warnings you can exclude
the features for system call tracing and file descriptor analyzing by
applying the options "--disable-sycls --disable-filan" to configure.
You still need the functions vsnprintf and snprintf that are in the GNU libc,
but might not be available with some proprietary libc's.
The configure script looks for headers and libraries of openssl, readline, and
tcp wrappers in the OS'es standard places and in the subdirectories include/
and lib/ of the following places:
/sw/
/usr/local/
/opt/freeware/
/usr/sfw/
and for openssl also in:
/usr/local/ssl/
In case of unexpected behaviour it is important to understand that configure
first searches for the appropriate include file and then expects to find the
library in the associated lib directory. That means, when e.g. a OpenSSL
installation resides under /usr/local and there is a symbolic link from
/usr/include/ssl/ssl.h to /usr/local/ssl/include/ssl/ssl.h, configure will find
the /usr/include/... header and will therefore expect libssl in /usr/lib
instead of /usr/local/...
If configure does not find a header file or library but you know where it is,
you can specify additional search locations, e.g.:
export LIBS="-L$HOME/lib"
export CPPFLAGS="-I$HOME/include"
before running configure and make.
For other operating systems, if socat does not compile without errors, refer to
the file PORTING.
platform specifics - Debian (Ubuntu, ...)
-----------------------------------------
libssl-dev
platform specifics - redhat
---------------------------
Install the following packages before building socat:
tcp_wrappers-devel
readline-devel
openssl-devel
On RedHat Linux 9.0, including openssl/ssl.h might fail due to problems with
the krb5-devel package. configure reacts with disabling openssl integration.
To solve this issue, help cpp to find the krb5.h include file:
CPPFLAGS="-I/usr/kerberos/include" ./configure
platform specifics - aix
------------------------
The flock() prototype is not available but the function is. Thus, to enable the
socat flock options, run configure and then change in config.h the line
/* #undef HAVE_FLOCK */
to
#define HAVE_FLOCK 1
and continue the build process.
When using the OpenSSL rpm provided by IBM, configure might need the
environment variable setting:
LIBS="-L/opt/freeware/lib"
When using the OpenSSL bundle provided by IBM, egd needs to be installed too
to get enough entropy.
socat compiles not only with gcc, but also with xlc. Just adapt the Makefile:
replace gcc by /usr/vac/bin/xlc and remove gcc specific options
"-Wall -Wno-parentheses".
When linking with the OpenSSL library provided by IBM, errors may occur:
ld: 0711-317 ERROR: Undefined symbol: .__umoddi3
In this case, you need to link with libgcc or compile libcrypt yourself using
xlc, or disable SSL (in config.h, undefine WITH_OPENSSL and recompile)
The score of test.sh can be improved by uncommenting MISCDELAY=1 in this
script.
platform specifics - solaris
----------------------------
If libreadline or libssl are in a directory not searched by the loader per
default, e.g. /opt/sfw/lib, you must add this directory to $LD_LIBRARY_PATH,
for running both configure and the socat executables, e.g.:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/sfw/lib
For some shell scripts, it is preferable to have /usr/xpg4/bin at a prominent
position in $PATH.
With the default compiler define _GNU_SOURCE, the CMSG_* macros are not
available, and therefore ancillary messages cannot be used. To enable these try
the following:
After running ./configure, edit Makefile and replace "-D_GNU_SOURCE" with
"-D_XPG4_2 -D__EXTENSIONS__" and run make
platform specifics - hp-ux
--------------------------
Ancillary messages cannot be compiled in with socat: both struct msghdr and
struct cmsghdr are required. Compiling with -D_XOPEN_SOURCE_EXTENDED provides
struct msghdr but disables struct cmsghdr while -D_OPEN_SOURCE disables struct
msghdr but disables struct cmsghdr. Please contact socat development if you
know a solution.
Shutting down the write channel of a UNIX domain socket does not seem to
trigger an EOF on the peer socket. This makes problems with the exec and
system addresses.
This OS provides the type "long long", but not the strtoll() function to read
data into a long long variable.
UNIX domain sockets are only supported with SOCK_STREAM, not with datagrams
(see man 7 unix).
With UDP sockets it seems to happen that the select() call reports available
data (or EOF) but a subsequent read() call hangs.
platform specifics - tru64
--------------------------
When the use of the readline address fails with an error like:
socat: /sbin/loader: Fatal Error: Reference to unresolvable symbol "tgetent" in ".../libreadline.so.4"
and you still want to use shared libraries, try the following workaround:
$ make distclean; LIBS="-static" ./configure
remove the "-static" occurrence in Makefile
$ make
documentation
-------------
These files reside in the doc subdirectory:
socat.1 is the man page, socat.html is the HTML based man page. It is actual,
but describes only the more useful options.
doc/socat-openssltunnel.html is a simple tutorial for a private SSL connection.
doc/socat-multicast.html is a short tutorial for multicast and broadcast
communications.
doc/socat-tun shows how to build a virtual network between two hosts.
socat.1 and socat.html can be generated from socat.yo (which is released with
socat 1.6.0.1 and later) using the yodl document language package. Maintenance
of yodl had been discontinued by its author
(http://www.xs4all.nl/~jantien/yodl/) (there seems to be a revival at
http://yodl.sourceforge.net/ though). For socat, the revival version 3.03 is used,
license
-------
socat is distributed under the terms of the GNU GPLv2;
except for install-sh, which is copyright MIT, with its own license;
In addition, as a special exception, the copyright holder
gives permission to link the code of this program with
any version of the OpenSSL library which is distributed
under a license identical to that listed in the included
COPYING.OpenSSL file, and distribute linked combinations
including the two. You must obey the GNU General Public
License in all respects for all of the code used other
than OpenSSL. If you modify this file, you may extend this
exception to your version of the file, but you are not
obligated to do so. If you do not wish to do so, delete
this exception statement from your version.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 2 of the License
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
contact
-------
For questions, bug reports, ideas, contributions etc. please contact
socat@dest-unreach.org
For socat source distribution, bug fixes, and latest news see
http://www.dest-unreach.org/socat/
www.socat.org is an alternate site providing the same contents.
public git repository:
git://repo.or.cz/socat.git
http://repo.or.cz/socat.git

67
README.FIPS Normal file
View File

@@ -0,0 +1,67 @@
David Acker has patched socat to add OpenSSL FIPS.
See http://oss-institute.org/fips-faq.html and
http://linuxdevices.com/news/NS4742716157.html for more information.
The patch that is integrated into socat 1.5 does the following:
Add support for LDFLAGS in Makefile. LDFLAGS can be specified on the
configure command line and then will be carried over into the make.
Add fips support. Requires OpenSSL 0.9.7j-fips-dev from
http://www.openssl.org/source/OpenSSL-fips-1.0.tar.gz built with fips
support turned on. use ./Configure fips [os-arc], for example
./Configure fips linux-pentium
The LDFLAGS is needed to point a build against a library
located in a non-standard location. For example, if you download and
build openssl manually, it gets installed in /usr/local/ssl by default.
The FIPS support patches involve adding an option to enable/disable fips
in configure (enabled by default), checking the system for FIPS support
during configure, and then adding a fips option to socats openssl address
to turn on fips mode. The openssl binary uses an environment variable
instead of a command line flag.
FIPS mode requires both a compile time flag of OPENSSL_FIPS and a
runtime call of FIPS_mode_set(1). Fips mode requires building with the
fipsld script provided by OpenSSL. FIPS tracks the pid of the process that
initializes things so after a fork, the child must reinitialize. When the
ssl code detects a forks occur and if FIPS mode was enabled, it reinitializes
FIPS by disabling and then enabling it again.
To produce Davids enviroment, do the following:
To build openssl
download OpenSSL 0.9.7j-fips-dev from
http://www.openssl.org/source/OpenSSL-fips-1.0.tar.gz
tar xzf OpenSSL-fips-1.0.tar.gz
cd openssl
./Configure fips linux-pentium
make
make test
(become root)
make install
This leaves an install in /usr/local/ssl
To build socat:
setup directory with socat 1.5 or higher.
cd socat-1.5.0.0
./configure CPPFLAGS=-I/usr/local/ssl/include/ LDFLAGS=-L/usr/local/ssl/lib/ FIPSLD=/usr/local/ssl/bin/fipsld
make
(become root)
make install
To run tests we make sure the new openssl is used:
export PATH=/usr/local/ssl/bin:$PATH
./test.sh fips
There are two tests in test.sh that depend on fips:
OPENSSL_FIPS_BOTHAUTH performs a SSL client to server connection with
certificate based authentication in both directions. If it works FIPS mode
seems to be ok.
OPENSSL_FIPS_SECURITY generates a certificaet/key pair without fips support. It
then tries a SSL connection in "normal" mode which is expected to work. In the
second phase it uses fips mode with these credentials which is expected to
fail. If so, the test succeeded.

41
SECURITY Normal file
View File

@@ -0,0 +1,41 @@
Tips for using socat in secured environments:
* Configure socat to only enable the required features, e.g. to protect your
filesystem from any accesses through socat:
make distclean
./configure --disable-file --disable-creat --disable-gopen \
--disable-pipe --disable-unix --disable-exec --disable-system
use "socat -V" to see what features are still enabled; see
./configure --help for more options to disable
* Do NOT install socat SUID root or so when you have untrusted users or
unprivileged daemons on your machine, because the full install of socat can
override arbitrary files and execute arbitrary programs!
* Set logging to "-d -d" (in special cases even higher)
* With files, protect against symlink attacks with nofollow (Linux), and
avoid accessing files in world-writable directories like /tmp
* When listening, use bind option (except UNIX domain sockets)
* When listening, use range option (currently only for IP4 sockets)
* When using socat with system, exec, or in a shell script, know what you do
* With system and exec, use absolute pathes or set the path option
* When starting programs with socat, consider using the chroot option (this
requires root, so use the substuser option too).
* Start socat as root only if required; if so, use substuser option
Note: starting a SUID program after applying substuser or setuid gives the
process the SUID owner, which might give root privileges again.
* Socat, like netcat, is what intruders like to have on their victims machine:
once they have gained a toehold they try to establish a versatile connection
back to their attack base, and they want to attack other systems. For both
purposes, socat could be helpful. Therefore, it might be useful to install
socat with owner/permissions root:socatgrp/750, and to make all trusted users
members of group socatgrp.

1
VERSION Normal file
View File

@@ -0,0 +1 @@
"1.8.0.0"

869
compat.h Normal file
View File

@@ -0,0 +1,869 @@
/* source: compat.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __compat_h_included
#define __compat_h_included 1
#if !HAVE_DECL_ENVIRON && HAVE_VAR_ENVIRON
extern char **environ;
#endif
/*****************************************************************************/
/* I dont like this system dependent part, but it would be quite a challenge
for configure */
/* define if the following does not work:
socket()
connect() -> Connection refused
connect() -> ok
instead, it needs close() and socket() between the two connect() attmpts: */
#if __FreeBSD__ || __APPLE__ || _AIX || __hpux__ || __osf__
# undef SOCKET_CAN_RECOVER
#else
# define SOCKET_CAN_RECOVER 1
#endif
/* define if stat() says that pipes are sockets */
#if __APPLE__
# define PIPE_STATES_SOCKET 1
#else
# undef PIPE_STATES_SOCKET
#endif
#if defined(__sun) || defined(__sun__) || defined(__SunOS)
# define XIO_ANCILLARY_TYPE_SOLARIS 1
#endif
/*****************************************************************************/
/* substitute some features that might be missing on some platforms */
#if !HAVE_TYPE_SIG_ATOMIC_T
typedef int sig_atomic_t;
#endif
#ifndef SHUT_RD
# define SHUT_RD 0
#endif
#ifndef SHUT_WR
# define SHUT_WR 1
#endif
#ifndef SHUT_RDWR
# define SHUT_RDWR 2
#endif
#ifndef MIN
# define MIN(x,y) ((x)<=(y)?(x):(y))
#endif
#ifndef MAX
# define MAX(x,y) ((x)>=(y)?(x):(y))
#endif
/* O_ASYNC: Linux 2.2.10 */
#if !defined(O_ASYNC) && defined(FASYNC)
# define O_ASYNC FASYNC
#endif
/* NGROUPS not defined on Solaris */
#if !defined(NGROUPS) && defined(NGROUPS_MAX)
# define NGROUPS NGROUPS_MAX
#endif
/* UNIX_PATH_MAX: AIX 4.3.3 */
#ifndef UNIX_PATH_MAX
# define UNIX_PATH_MAX 104 /*! why 104? Linux: 108 ! */
#endif
/* SOL_IP: AIX 4.3.3 */
#ifndef SOL_IP
# define SOL_IP 0
#endif
/* SOL_TCP: AIX 4.3.3 */
#ifndef SOL_TCP
# ifdef IPPROTO_TCP
# define SOL_TCP IPPROTO_TCP
# endif
#endif
/* POSIX.1 doesn't seem to know sockets */
#ifndef S_ISSOCK
# define S_ISSOCK(fmode) 0
#endif
#if defined(IPPROTO_IPV6) && !defined(SOL_IPV6)
# define SOL_IPV6 IPPROTO_IPV6
#endif
#define F_uint8_t "%hu"
#define F_uint8_x "%02hx"
#define F_int8_t "%hd"
#ifndef F_uint16_t
# if HAVE_BASIC_UINT16_T==0
# define F_uint16_t "%hu"
# define F_uint16_x "%04hx"
# elif HAVE_BASIC_UINT16_T==2
# define F_uint16_t "%hu"
# define F_uint16_x "%04hx"
# elif HAVE_BASIC_UINT16_T==4
# define F_uint16_t "%u"
# define F_uint16_x "%04x"
# elif HAVE_BASIC_UINT16_T==6
# define F_uint16_t "%lu"
# define F_uint16_x "%04lx"
# else
# error "HAVE_BASIC_UINT16_T is out of range:" HAVE_BASIC_UINT16_T
# endif
#endif
#ifndef F_uint32_t
# if HAVE_BASIC_UINT32_T==0
# define F_uint32_t "%hu"
# define F_uint32_x "%08hx"
# elif HAVE_BASIC_UINT32_T==2
# define F_uint32_t "%hu"
# define F_uint32_x "%08hx"
# elif HAVE_BASIC_UINT32_T==4
# define F_uint32_t "%u"
# define F_uint32_x "%08x"
# elif HAVE_BASIC_UINT32_T==6
# define F_uint32_t "%lu"
# define F_uint32_x "%08lx"
# else
# error "HAVE_BASIC_UINT32_T is out of range:" HAVE_BASIC_UINT32_T
# endif
#endif
#ifndef F_uint64_t
# if HAVE_BASIC_UINT64_T==0
# define F_uint64_t "%hu"
# define F_uint64_x "%016hx"
# elif HAVE_BASIC_UINT64_T==2
# define F_uint64_t "%hu"
# define F_uint64_x "%016hx"
# elif HAVE_BASIC_UINT64_T==4
# define F_uint64_t "%u"
# define F_uint64_x "%016x"
# elif HAVE_BASIC_UINT64_T==6
# define F_uint64_t "%lu"
# define F_uint64_x "%016lx"
# elif HAVE_BASIC_UINT64_T==8
# define F_uint64_t "%llu"
# define F_uint64_x "%016llx"
# else
# error "HAVE_BASIC_UINT64_T is out of range:" HAVE_BASIC_UINT64_T
# endif
#endif
#ifndef F_int16_t
# if HAVE_BASIC_INT16_T==0
# define F_int16_t "%hd"
# elif HAVE_BASIC_INT16_T==1
# define F_int16_t "%hd"
# elif HAVE_BASIC_INT16_T==3
# define F_int16_t "%d"
# elif HAVE_BASIC_INT16_T==5
# define F_int16_t "%ld"
# else
# error "HAVE_BASIC_INT16_T is out of range:" HAVE_BASIC_INT16_T
# endif
#endif
#ifndef F_int32_t
# if HAVE_BASIC_INT32_T==0
# define F_int32_t "%hd"
# elif HAVE_BASIC_INT32_T==1
# define F_int32_t "%hd"
# elif HAVE_BASIC_INT32_T==3
# define F_int32_t "%d"
# elif HAVE_BASIC_INT32_T==5
# define F_int32_t "%ld"
# else
# error "HAVE_BASIC_INT32_T is out of range:" HAVE_BASIC_INT32_T
# endif
#endif
#ifndef F_int64_t
# if HAVE_BASIC_INT64_T==0
# define F_int64_t "%hd"
# elif HAVE_BASIC_INT64_T==1
# define F_int64_t "%hd"
# elif HAVE_BASIC_INT64_T==3
# define F_int64_t "%d"
# elif HAVE_BASIC_INT64_T==5
# define F_int64_t "%ld"
# elif HAVE_BASIC_INT64_T==7
# define F_int64_t "%lld"
# else
# error "HAVE_BASIC_INT64_T is out of range:" HAVE_BASIC_INT64_T
# endif
#endif
/* all unsigned */
#if !defined(HAVE_BASIC_SIZE_T) || !HAVE_BASIC_SIZE_T
# undef HAVE_BASIC_SIZE_T
# define HAVE_BASIC_SIZE_T 6
#endif
#if HAVE_BASIC_SIZE_T==2
# define SIZET_MAX USHRT_MAX
# define SSIZET_MIN SHRT_MIN
# define SSIZET_MAX SHRT_MAX
# define F_Zd "%hd"
# define F_Zu "%hu"
#elif HAVE_BASIC_SIZE_T==4
# define SIZET_MAX UINT_MAX
# define SSIZET_MIN INT_MIN
# define SSIZET_MAX INT_MAX
# define F_Zd "%""d"
# define F_Zu "%u"
#elif HAVE_BASIC_SIZE_T==6
# define SIZET_MAX ULONG_MAX
# define SSIZET_MIN LONG_MIN
# define SSIZET_MAX LONG_MAX
# define F_Zd "%ld"
# define F_Zu "%lu"
#elif HAVE_BASIC_SIZE_T==8
# define SIZET_MAX ULLONG_MAX
# define SSIZET_MIN LLONG_MIN
# define SSIZET_MAX LLONG_MAX
# define F_Zd "%Ld"
# define F_Zu "%Lu"
#else
# error "HAVE_BASIC_SIZE_T is out of range:" HAVE_BASIC_SIZE_T
#endif
#if HAVE_FORMAT_Z
# undef F_Zd
# undef F_Zu
# define F_Zd "%Zd"
# define F_Zu "%Zu"
#endif
/* mode_t is always unsigned; default: unsigned int */
#if !defined(HAVE_BASIC_MODE_T) || !HAVE_BASIC_MODE_T
# undef HAVE_BASIC_MODE_T
# define HAVE_BASIC_MODE_T 4
#endif
#ifndef F_mode
# if HAVE_BASIC_MODE_T==1 || HAVE_BASIC_MODE_T==2
#define F_mode "0%03ho"
# elif HAVE_BASIC_MODE_T==3 || HAVE_BASIC_MODE_T==4
#define F_mode "0%03o"
# elif HAVE_BASIC_MODE_T==5 || HAVE_BASIC_MODE_T==6
#define F_mode "0%03lo"
# else
#error "HAVE_BASIC_MODE_T is out of range:" HAVE_BASIC_MODE_T
# endif
#endif
/* default: unsigned int */
#if !defined(HAVE_BASIC_PID_T) || !HAVE_BASIC_PID_T
# undef HAVE_BASIC_PID_T
# define HAVE_BASIC_PID_T 4
#endif
#ifndef F_pid
# if HAVE_BASIC_PID_T==1
#define F_pid "%hd"
# elif HAVE_BASIC_PID_T==2
#define F_pid "%hu"
# elif HAVE_BASIC_PID_T==3
#define F_pid "%""d"
# elif HAVE_BASIC_PID_T==4
#define F_pid "%u"
# elif HAVE_BASIC_PID_T==5
#define F_pid "%ld"
# elif HAVE_BASIC_PID_T==6
#define F_pid "%lu"
# else
#error "HAVE_BASIC_PID_T is out of range:" HAVE_BASIC_PID_T
# endif
#endif
/* default: unsigned int */
#if !defined(HAVE_BASIC_UID_T) || !HAVE_BASIC_UID_T
# undef HAVE_BASIC_UID_T
# define HAVE_BASIC_UID_T 4
#endif
#ifndef F_uid
# if HAVE_BASIC_UID_T==1
#define F_uid "%hd"
# elif HAVE_BASIC_UID_T==2
#define F_uid "%hu"
# elif HAVE_BASIC_UID_T==3
#define F_uid "%""d"
# elif HAVE_BASIC_UID_T==4
#define F_uid "%u"
# elif HAVE_BASIC_UID_T==5
#define F_uid "%ld"
# elif HAVE_BASIC_UID_T==6
#define F_uid "%lu"
# else
#error "HAVE_BASIC_UID_T is out of range:" HAVE_BASIC_UID_T
# endif
#endif
/* default: unsigned int */
#if !defined(HAVE_BASIC_GID_T) || !HAVE_BASIC_GID_T
# undef HAVE_BASIC_GID_T
# define HAVE_BASIC_GID_T 4
#endif
#ifndef F_gid
# if HAVE_BASIC_GID_T==1
#define F_gid "%hd"
# elif HAVE_BASIC_GID_T==2
#define F_gid "%hu"
# elif HAVE_BASIC_GID_T==3
#define F_gid "%""d"
# elif HAVE_BASIC_GID_T==4
#define F_gid "%u"
# elif HAVE_BASIC_GID_T==5
#define F_gid "%ld"
# elif HAVE_BASIC_GID_T==6
#define F_gid "%lu"
# else
#error "HAVE_BASIC_GID_T is out of range:" HAVE_BASIC_GID_T
# endif
#endif
/* all signed; default: long */
#if !defined(HAVE_BASIC_TIME_T) || !HAVE_BASIC_TIME_T
# undef HAVE_BASIC_TIME_T
# define HAVE_BASIC_TIME_T 5
#endif
#ifndef F_time
# if HAVE_BASIC_TIME_T==1
#define F_time "%hd"
# elif HAVE_BASIC_TIME_T==2
#define F_time "%hu"
# elif HAVE_BASIC_TIME_T==3
#define F_time "%""d"
# elif HAVE_BASIC_TIME_T==4
#define F_time "%u"
# elif HAVE_BASIC_TIME_T==5
#define F_time "%ld"
# elif HAVE_BASIC_TIME_T==6
#define F_time "%lu"
# elif HAVE_BASIC_TIME_T==7
#define F_time "%Ld"
# elif HAVE_BASIC_TIME_T==8
#define F_time "%Lu"
# else
#error "HAVE_BASIC_TIME_T is out of range:" HAVE_BASIC_TIME_T
# endif
#endif
/* default: int */
#if !defined(HAVE_BASIC_SOCKLEN_T) || !HAVE_BASIC_SOCKLEN_T
# undef HAVE_BASIC_SOCKLEN_T
# define HAVE_BASIC_SOCKLEN_T 3
#endif
#ifndef F_socklen
# if HAVE_BASIC_SOCKLEN_T==1
#define F_socklen "%hd"
# elif HAVE_BASIC_SOCKLEN_T==2
#define F_socklen "%hu"
# elif HAVE_BASIC_SOCKLEN_T==3
#define F_socklen "%""d"
# elif HAVE_BASIC_SOCKLEN_T==4
#define F_socklen "%u"
# elif HAVE_BASIC_SOCKLEN_T==5
#define F_socklen "%ld"
# elif HAVE_BASIC_SOCKLEN_T==6
#define F_socklen "%lu"
# elif HAVE_BASIC_SOCKLEN_T==7
#define F_socklen "%Ld"
# elif HAVE_BASIC_SOCKLEN_T==8
#define F_socklen "%Lu"
# else
#error "HAVE_BASIC_SOCKLEN_T is out of range:" HAVE_BASIC_SOCKLEN_T
# endif
#endif
#if !defined(HAVE_BASIC_OFF_T) || !HAVE_BASIC_OFF_T
# undef HAVE_BASIC_OFF_T
# define HAVE_BASIC_OFF_T 5 /*long*/
#endif
#ifndef F_off
# if HAVE_BASIC_OFF_T==3
# define F_off "%""d"
# elif HAVE_BASIC_OFF_T==5
# define F_off "%ld"
# elif HAVE_BASIC_OFF_T==7
# define F_off "%Ld"
# else
#error "HAVE_BASIC_OFF_T is out of range:" HAVE_BASIC_OFF_T
# endif
#endif
/* default: long long */
#if !defined(HAVE_BASIC_OFF64_T) || !HAVE_BASIC_OFF64_T
# undef HAVE_BASIC_OFF64_T
# define HAVE_BASIC_OFF64_T 7
#endif
#ifndef F_off64
# if HAVE_BASIC_OFF64_T==1
#define F_off64 "%hd"
# elif HAVE_BASIC_OFF64_T==2
#define F_off64 "%hu"
# elif HAVE_BASIC_OFF64_T==3
#define F_off64 "%""d"
# elif HAVE_BASIC_OFF64_T==4
#define F_off64 "%u"
# elif HAVE_BASIC_OFF64_T==5
#define F_off64 "%ld"
# elif HAVE_BASIC_OFF64_T==6
#define F_off64 "%lu"
# elif HAVE_BASIC_OFF64_T==7
#define F_off64 "%Ld"
# elif HAVE_BASIC_OFF64_T==8
#define F_off64 "%Lu"
# else
#error "HAVE_BASIC_OFF64_T is out of range:" HAVE_BASIC_OFF64_T
# endif
#endif
/* all unsigned; default: unsigned long */
#if !defined(HAVE_BASIC_DEV_T) || !HAVE_BASIC_DEV_T
# undef HAVE_BASIC_DEV_T
# define HAVE_BASIC_DEV_T 6
#endif
#ifndef F_dev
# if HAVE_BASIC_DEV_T==1
#define F_dev "%hd"
# elif HAVE_BASIC_DEV_T==2
#define F_dev "%hu"
# elif HAVE_BASIC_DEV_T==3
#define F_dev "%""d"
# elif HAVE_BASIC_DEV_T==4
#define F_dev "%u"
# elif HAVE_BASIC_DEV_T==5
#define F_dev "%ld"
# elif HAVE_BASIC_DEV_T==6
#define F_dev "%lu"
# elif HAVE_BASIC_DEV_T==7
#define F_dev "%Ld"
# elif HAVE_BASIC_DEV_T==8
#define F_dev "%Lu"
# else
#error "HAVE_BASIC_DEV_T is out of range:" HAVE_BASIC_DEV_T
# endif
#endif
#if _WITH_TERMIOS
#if !defined(HAVE_BASIC_SPEED_T) || !HAVE_BASIC_SPEED_T
# undef HAVE_BASIC_SPEED_T
# define HAVE_BASIC_SPEED_T 4
#endif
#ifndef F_speed
# if HAVE_BASIC_SPEED_T==1
#define F_speed "%hd"
# elif HAVE_BASIC_SPEED_T==2
#define F_speed "%hu"
# elif HAVE_BASIC_SPEED_T==3
#define F_speed "%""d"
# elif HAVE_BASIC_SPEED_T==4
#define F_speed "%u"
# elif HAVE_BASIC_SPEED_T==5
#define F_speed "%ld"
# elif HAVE_BASIC_SPEED_T==6
#define F_speed "%lu"
# elif HAVE_BASIC_SPEED_T==7
#define F_speed "%Ld"
# elif HAVE_BASIC_SPEED_T==8
#define F_speed "%Lu"
# else
#error "HAVE_BASIC_SPEED_T is out of range:" HAVE_BASIC_SPEED_T
# endif
#endif
#endif /* _WITH_TERMIOS */
/* all unsigned; default; unsigned long */
#if !defined(HAVE_TYPEOF_ST_INO) || !HAVE_TYPEOF_ST_INO
# undef HAVE_TYPEOF_ST_INO
# define HAVE_TYPEOF_ST_INO 6
#endif
#ifndef F_st_ino
# if HAVE_TYPEOF_ST_INO==1
#define F_st_ino "%hd"
# elif HAVE_TYPEOF_ST_INO==2
#define F_st_ino "%hu"
# elif HAVE_TYPEOF_ST_INO==3
#define F_st_ino "%""d"
# elif HAVE_TYPEOF_ST_INO==4
#define F_st_ino "%u"
# elif HAVE_TYPEOF_ST_INO==5
#define F_st_ino "%ld"
# elif HAVE_TYPEOF_ST_INO==6
#define F_st_ino "%lu"
# elif HAVE_TYPEOF_ST_INO==7 /* Cygwin 1.5 */
#define F_st_ino "%Ld"
# elif HAVE_TYPEOF_ST_INO==8
#define F_st_ino "%Lu"
# else
#error "HAVE_TYPEOF_ST_INO is out of range:" HAVE_TYPEOF_ST_INO
# endif
#endif
/* all unsigned; default; unsigned long long */
#if !defined(HAVE_TYPEOF_ST64_INO) || !HAVE_TYPEOF_ST64_INO
# undef HAVE_TYPEOF_ST64_INO
# define HAVE_TYPEOF_ST64_INO 8
#endif
#ifndef F_st64_ino
# if HAVE_TYPEOF_ST64_INO==1
#define F_st64_ino "%hd"
# elif HAVE_TYPEOF_ST64_INO==2
#define F_st64_ino "%hu"
# elif HAVE_TYPEOF_ST64_INO==3
#define F_st64_ino "%""d"
# elif HAVE_TYPEOF_ST64_INO==4
#define F_st64_ino "%u"
# elif HAVE_TYPEOF_ST64_INO==5
#define F_st64_ino "%ld"
# elif HAVE_TYPEOF_ST64_INO==6
#define F_st64_ino "%lu"
# elif HAVE_TYPEOF_ST64_INO==7
#define F_st64_ino "%Ld"
# elif HAVE_TYPEOF_ST64_INO==8
#define F_st64_ino "%Lu"
# else
#error "HAVE_TYPEOF_ST64_INO is out of range:" HAVE_TYPEOF_ST64_INO
# endif
#endif
/* default: unsigned short */
#if !defined(HAVE_TYPEOF_ST_NLINK) || !HAVE_TYPEOF_ST_NLINK
# undef HAVE_TYPEOF_ST_NLINK
# define HAVE_TYPEOF_ST_NLINK 2
#endif
#ifndef F_st_nlink
# if HAVE_TYPEOF_ST_NLINK==1
#define F_st_nlink "%hd"
# elif HAVE_TYPEOF_ST_NLINK==2
#define F_st_nlink "%hu"
# elif HAVE_TYPEOF_ST_NLINK==3
#define F_st_nlink "%""d"
# elif HAVE_TYPEOF_ST_NLINK==4
#define F_st_nlink "%u"
# elif HAVE_TYPEOF_ST_NLINK==5
#define F_st_nlink "%ld"
# elif HAVE_TYPEOF_ST_NLINK==6
#define F_st_nlink "%lu"
# elif HAVE_TYPEOF_ST_NLINK==7
#define F_st_nlink "%Ld"
# elif HAVE_TYPEOF_ST_NLINK==8
#define F_st_nlink "%Lu"
# else
#error "HAVE_TYPEOF_ST_NLINK is out of range:" HAVE_TYPEOF_ST_NLINK
# endif
#endif
/* all signed; default: long */
#if !defined(HAVE_TYPEOF_ST_SIZE) || !HAVE_TYPEOF_ST_SIZE
# undef HAVE_TYPEOF_ST_SIZE
# define HAVE_TYPEOF_ST_SIZE 5
#endif
#ifndef F_st_size
# if HAVE_TYPEOF_ST_SIZE==1
#define F_st_size "%hd"
# elif HAVE_TYPEOF_ST_SIZE==2
#define F_st_size "%hu"
# elif HAVE_TYPEOF_ST_SIZE==3
#define F_st_size "%""d"
# elif HAVE_TYPEOF_ST_SIZE==4
#define F_st_size "%u"
# elif HAVE_TYPEOF_ST_SIZE==5
#define F_st_size "%ld"
# elif HAVE_TYPEOF_ST_SIZE==6
#define F_st_size "%lu"
# elif HAVE_TYPEOF_ST_SIZE==7
#define F_st_size "%Ld"
# elif HAVE_TYPEOF_ST_SIZE==8
#define F_st_size "%Lu"
# else
#error "HAVE_TYPEOF_ST_SIZE is out of range:" HAVE_TYPEOF_ST_SIZE
# endif
#endif
/* all signed; default: long long */
#if !defined(HAVE_TYPEOF_ST64_SIZE) || !HAVE_TYPEOF_ST64_SIZE
# undef HAVE_TYPEOF_ST64_SIZE
# define HAVE_TYPEOF_ST64_SIZE 7
#endif
#ifndef F_st64_size
# if HAVE_TYPEOF_ST64_SIZE==1
#define F_st64_size "%hd"
# elif HAVE_TYPEOF_ST64_SIZE==2
#define F_st64_size "%hu"
# elif HAVE_TYPEOF_ST64_SIZE==3
#define F_st64_size "%""d"
# elif HAVE_TYPEOF_ST64_SIZE==4
#define F_st64_size "%u"
# elif HAVE_TYPEOF_ST64_SIZE==5
#define F_st64_size "%ld"
# elif HAVE_TYPEOF_ST64_SIZE==6
#define F_st64_size "%lu"
# elif HAVE_TYPEOF_ST64_SIZE==7
#define F_st64_size "%Ld"
# elif HAVE_TYPEOF_ST64_SIZE==8
#define F_st64_size "%Lu"
# else
#error "HAVE_TYPEOF_ST64_SIZE is out of range:" HAVE_TYPEOF_ST64_SIZE
# endif
#endif
/* very different results; default: long */
#if !defined(HAVE_TYPEOF_ST_BLKSIZE) || !HAVE_TYPEOF_ST_BLKSIZE
# undef HAVE_TYPEOF_ST_BLKSIZE
# define HAVE_TYPEOF_ST_BLKSIZE 5
#endif
#ifndef F_st_blksize
# if HAVE_TYPEOF_ST_BLKSIZE==1
#define F_st_blksize "%hd"
# elif HAVE_TYPEOF_ST_BLKSIZE==2
#define F_st_blksize "%hu"
# elif HAVE_TYPEOF_ST_BLKSIZE==3
#define F_st_blksize "%""d"
# elif HAVE_TYPEOF_ST_BLKSIZE==4
#define F_st_blksize "%u"
# elif HAVE_TYPEOF_ST_BLKSIZE==5
#define F_st_blksize "%ld"
# elif HAVE_TYPEOF_ST_BLKSIZE==6
#define F_st_blksize "%lu"
# elif HAVE_TYPEOF_ST_BLKSIZE==7
#define F_st_blksize "%Ld"
# elif HAVE_TYPEOF_ST_BLKSIZE==8
#define F_st_blksize "%Lu"
# else
#error "HAVE_TYPEOF_ST_BLKSIZE is out of range:" HAVE_TYPEOF_ST_BLKSIZE
# endif
#endif
/* default: long */
#if !defined(HAVE_TYPEOF_ST_BLOCKS) || !HAVE_TYPEOF_ST_BLOCKS
# undef HAVE_TYPEOF_ST_BLOCKS
# define HAVE_TYPEOF_ST_BLOCKS 5
#endif
#ifndef F_st_blocks
# if HAVE_TYPEOF_ST_BLOCKS==1
#define F_st_blocks "%hd"
# elif HAVE_TYPEOF_ST_BLOCKS==2
#define F_st_blocks "%hu"
# elif HAVE_TYPEOF_ST_BLOCKS==3
#define F_st_blocks "%""d"
# elif HAVE_TYPEOF_ST_BLOCKS==4
#define F_st_blocks "%u"
# elif HAVE_TYPEOF_ST_BLOCKS==5
#define F_st_blocks "%ld"
# elif HAVE_TYPEOF_ST_BLOCKS==6
#define F_st_blocks "%lu"
# elif HAVE_TYPEOF_ST_BLOCKS==7
#define F_st_blocks "%Ld"
# elif HAVE_TYPEOF_ST_BLOCKS==8
#define F_st_blocks "%Lu"
# else
#error "HAVE_TYPEOF_ST_BLOCKS is out of range:" HAVE_TYPEOF_ST_BLOCKS
# endif
#endif
/* default: long long */
#if !defined(HAVE_TYPEOF_ST64_BLOCKS) || !HAVE_TYPEOF_ST64_BLOCKS
# undef HAVE_TYPEOF_ST64_BLOCKS
# define HAVE_TYPEOF_ST64_BLOCKS 7
#endif
#ifndef F_st64_blocks
# if HAVE_TYPEOF_ST64_BLOCKS==1
#define F_st64_blocks "%hd"
# elif HAVE_TYPEOF_ST64_BLOCKS==2
#define F_st64_blocks "%hu"
# elif HAVE_TYPEOF_ST64_BLOCKS==3
#define F_st64_blocks "%""d"
# elif HAVE_TYPEOF_ST64_BLOCKS==4
#define F_st64_blocks "%u"
# elif HAVE_TYPEOF_ST64_BLOCKS==5
#define F_st64_blocks "%ld"
# elif HAVE_TYPEOF_ST64_BLOCKS==6
#define F_st64_blocks "%lu"
# elif HAVE_TYPEOF_ST64_BLOCKS==7
#define F_st64_blocks "%Ld"
# elif HAVE_TYPEOF_ST64_BLOCKS==8
#define F_st64_blocks "%Lu"
# else
#error "HAVE_TYPEOF_ST64_BLOCKS is out of range:" HAVE_TYPEOF_ST64_BLOCKS
# endif
#endif
/* at least for Linux */
#define F_tv_sec "%ld"
/* default: long */
#if !defined(HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC) || !HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC
# undef HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC
# define HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC 5
#endif
#ifndef F_tv_usec
# if HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC==1
#define F_tv_usec "%06hd"
# elif HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC==2
#define F_tv_usec "%06hu"
# elif HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC==3
#define F_tv_usec "%06d"
# elif HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC==4
#define F_tv_usec "%06u"
# elif HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC==5
#define F_tv_usec "%06ld"
# elif HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC==6
#define F_tv_usec "%06lu"
# elif HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC==7
#define F_tv_usec "%06Ld"
# elif HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC==8
#define F_tv_usec "%06Lu"
# else
#error "HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC is out of range:" HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC
# endif
#endif
/* default: long */
#if !defined(HAVE_TYPEOF_STRUCT_TIMESPEC_TV_NSEC) || !HAVE_TYPEOF_STRUCT_TIMESPEC_TV_NSEC
# undef HAVE_TYPEOF_STRUCT_TIMESPEC_TV_NSEC
# define HAVE_TYPEOF_STRUCT_TIMESPEC_TV_NSEC 5
#endif
#ifndef F_tv_nsec
# if HAVE_TYPEOF_STRUCT_TIMESPEC_TV_NSEC==1
#define F_tv_nsec "%09hd"
# elif HAVE_TYPEOF_STRUCT_TIMESPEC_TV_NSEC==2
#define F_tv_nsec "%09hu"
# elif HAVE_TYPEOF_STRUCT_TIMESPEC_TV_NSEC==3
#define F_tv_nsec "%09d"
# elif HAVE_TYPEOF_STRUCT_TIMESPEC_TV_NSEC==4
#define F_tv_nsec "%09u"
# elif HAVE_TYPEOF_STRUCT_TIMESPEC_TV_NSEC==5
#define F_tv_nsec "%09ld"
# elif HAVE_TYPEOF_STRUCT_TIMESPEC_TV_NSEC==6
#define F_tv_nsec "%09lu"
# elif HAVE_TYPEOF_STRUCT_TIMESPEC_TV_NSEC==7
#define F_tv_nsec "%09Ld"
# elif HAVE_TYPEOF_STRUCT_TIMESPEC_TV_NSEC==8
#define F_tv_nsec "%09Lu"
# else
#error "HAVE_TYPEOF_STRUCT_TIMESPEC_TV_NSEC is out of range:" HAVE_TYPEOF_STRUCT_TIMESPEC_TV_NSEC
# endif
#endif
/* default: long */
#if !defined(HAVE_TYPEOF_RLIM_MAX) || !HAVE_TYPEOF_RLIM_MAX
# undef HAVE_TYPEOF_RLIM_MAX
# define HAVE_TYPEOF_RLIM_MAX 5
#endif
#ifndef F_rlim_max
# if HAVE_TYPEOF_RLIM_MAX==1
#define F_rlim_max "hd"
# elif HAVE_TYPEOF_RLIM_MAX==2
#define F_rlim_max "hu"
# elif HAVE_TYPEOF_RLIM_MAX==3
#define F_rlim_max "d"
# elif HAVE_TYPEOF_RLIM_MAX==4
#define F_rlim_max "u"
# elif HAVE_TYPEOF_RLIM_MAX==5
#define F_rlim_max "ld"
# elif HAVE_TYPEOF_RLIM_MAX==6
#define F_rlim_max "lu"
# elif HAVE_TYPEOF_RLIM_MAX==7
#define F_rlim_max "Ld"
# elif HAVE_TYPEOF_RLIM_MAX==8
#define F_rlim_max "Lu"
# else
#error "HAVE_TYPEOF_RLIM_MAX is out of range:" HAVE_TYPEOF_RLIM_MAX
# endif
#endif
/* sigset_t printing - not an exact solution yet */
#define F_sigset "0x%06lx"
typedef unsigned long T_sigset;
/* default: socklen_t */
#if !defined(HAVE_TYPEOF_STRUCT_CMSGHDR_CMSG_LEN) || !HAVE_TYPEOF_STRUCT_CMSGHDR_CMSG_LEN
# undef HAVE_TYPEOF_STRUCT_CMSGHDR_CMSG_LEN
# define HAVE_TYPEOF_STRUCT_CMSGHDR_CMSG_LEN HAVE_BASIC_SOCKLEN_T
#endif
#ifndef F_cmsg_len
# if HAVE_TYPEOF_STRUCT_CMSGHDR_CMSG_LEN==1
#define F_cmsg_len "%""hd"
# elif HAVE_TYPEOF_STRUCT_CMSGHDR_CMSG_LEN==2
#define F_cmsg_len "%""hu"
# elif HAVE_TYPEOF_STRUCT_CMSGHDR_CMSG_LEN==3
#define F_cmsg_len "%""d"
# elif HAVE_TYPEOF_STRUCT_CMSGHDR_CMSG_LEN==4
#define F_cmsg_len "%""u"
# elif HAVE_TYPEOF_STRUCT_CMSGHDR_CMSG_LEN==5
#define F_cmsg_len "%""ld"
# elif HAVE_TYPEOF_STRUCT_CMSGHDR_CMSG_LEN==6
#define F_cmsg_len "%""lu"
# elif HAVE_TYPEOF_STRUCT_CMSGHDR_CMSG_LEN==7
#define F_cmsg_len "%""Ld"
# elif HAVE_TYPEOF_STRUCT_CMSGHDR_CMSG_LEN==8
#define F_cmsg_len "%""Lu"
# else
#error "HAVE_TYPEOF_STRUCT_CMSGHDR_CMSG_LEN is out of range:" HAVE_TYPEOF_STRUCT_CMSGHDR_CMSG_LEN
# endif
#endif
/* basic type of struct timeval tv_usec */
#ifndef F_tv_usec
# if TYPEOF_STRUCT_TIMEVAL_TV_USEC==1
# define F_tv_usec "%hu"
# elif TYPEOF_STRUCT_TIMEVAL_TV_USEC==3
# define F_tv_usec "%u"
# elif TYPEOF_STRUCT_TIMEVAL_TV_USEC==5
# define F_tv_usec "%lu"
# endif
#endif
/* OpenBSD (at least 7.2) does better with this special setting */
#if __FreeBSD__ || __OpenBSD__
# define UNIX_TIGHTSOCKLEN false
#else
# define UNIX_TIGHTSOCKLEN true
#endif
/* Cygwin 1.3.22 has the prototypes, but not the type... */
#ifndef HAVE_TYPE_STAT64
# undef HAVE_STAT64
# undef HAVE_FSTAT64
# undef HAVE_LSTAT64
#endif
#ifndef HAVE_TYPE_OFF64
# undef HAVE_LSEEK64
# undef HAVE_FTRUNCATE64
#endif
#if !defined(NETDB_INTERNAL) && defined(h_NETDB_INTERNAL)
# define NETDB_INTERNAL h_NETDB_INTERNAL
#endif
#ifndef INET_ADDRSTRLEN
# define INET_ADDRSTRLEN sizeof(struct sockaddr_in)
#endif
#if !HAVE_PROTOTYPE_HSTRERROR
/* with MacOSX this is char * */
extern const char *hstrerror(int);
#endif
#if !HAVE_PROTOTYPE_LIB_strndup
extern char *strndup (const char *s, size_t n);
#endif
#endif /* !defined(__compat_h_included) */

762
config.h.in Normal file
View File

@@ -0,0 +1,762 @@
/* source: config.h.in */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __config_h_included
#define __config_h_included 1
/* Define to empty if the keyword does not work. */
#undef const
/* Define to `int' if <sys/types.h> doesn't define. */
#undef gid_t
/* Define if your struct stat has st_blksize. */
#undef HAVE_ST_BLKSIZE
/* Define if your struct stat has st_blocks. */
#undef HAVE_ST_BLOCKS
/* Define if your struct stat has st_rdev. */
#undef HAVE_ST_RDEV
/* Define if you have the strftime function. */
#undef HAVE_STRFTIME
/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
#undef HAVE_SYS_WAIT_H
/* Define to `int' if <sys/types.h> doesn't define. */
#undef mode_t
/* Define to `long' if <sys/types.h> doesn't define. */
#undef off_t
/* Define to `int' if <sys/types.h> doesn't define. */
#undef pid_t
/* Define as the return type of signal handlers (int or void). */
#undef RETSIGTYPE
/* Define to `unsigned' if <sys/types.h> doesn't define. */
#undef size_t
/* Define if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define if you can safely include both <sys/time.h> and <time.h>. */
#undef TIME_WITH_SYS_TIME
/* Define to `int' if <sys/types.h> doesn't define. */
#undef uid_t
/* Define if you have the putenv function. */
#undef HAVE_PUTENV
/* Define if your cc provides char **environ declaration.
This implies HAVE_VAR_ENVIRON */
#undef HAVE_DECL_ENVIRON
/* Define if you have the char **environ variable */
#undef HAVE_VAR_ENVIRON
/* Define if you have the select function. */
#undef HAVE_SELECT
/* Define if you have the pselect function. */
#undef HAVE_PSELECT
/* Define if you have the poll function. */
#undef HAVE_POLL
/* Define if you have the socket function. */
#undef HAVE_SOCKET
/* Define if you have the posix_memalign function. */
#undef HAVE_PROTOTYPE_LIB_posix_memalign
/* Define if you have the strdup function. */
#undef HAVE_PROTOTYPE_LIB_strdup
/* Define if you have the strerror function. */
#undef HAVE_PROTOTYPE_LIB_strerror
/* Define if you have the strstr function. */
#undef HAVE_PROTOTYPE_LIB_strstr
/* Define if you have the strtod function. */
#undef HAVE_STRTOD
/* Define if you have the strtol function. */
#undef HAVE_STRTOL
/* Define if you have the strtoul function. */
#undef HAVE_STRTOUL
/* Define if you have the uname function. */
#undef HAVE_UNAME
/* Define if you have the getpgid function. */
#undef HAVE_GETPGID
/* Define if you have the getsid function. */
#undef HAVE_GETSID
/* Define if you have the nanosleep function. */
#undef HAVE_NANOSLEEP
/* Define if you have the gethostbyname function. */
#undef HAVE_GETHOSTBYNAME
/* Define if you have the getaddrinfo function. */
#undef HAVE_GETADDRINFO
/* Define if you have the getipnodebyname function. */
#undef HAVE_PROTOTYPE_LIB_getipnodebyname
/* Define if you have the getprotobynumber_r function. */
#undef HAVE_GETPROTOBYNUMBER_R
/* Define if you have the getprotobynumber function. */
#undef HAVE_GETPROTOBYNUMBER
/* Define if you have the setgroups function. */
#undef HAVE_SETGROUPS
/* Define if you have the inet_aton function. */
#undef HAVE_INET_ATON
/* Define if you have the strndup function. */
#undef HAVE_PROTOTYPE_LIB_strndup
/* Define if you have the memrchr function. */
#undef HAVE_PROTOTYPE_LIB_memrchr
/* Define if you have the if_indextoname function. */
#undef HAVE_PROTOTYPE_LIB_if_indextoname
/* Define if you have the sigaction function */
#undef HAVE_SIGACTION
/* Define if you have the stat64 function */
#undef HAVE_STAT64
/* Define if you have the fstat64 function */
#undef HAVE_FSTAT64
/* Define if you have the lstat64 function */
#undef HAVE_LSTAT64
/* Define if you have the lseek64 function */
#undef HAVE_LSEEK64
/* Define if you have the truncate64 function */
#undef HAVE_TRUNCATE64
/* Define if you have the ftruncate64 function */
#undef HAVE_FTRUNCATE64
/* Define if you have the gettimeofday function */
#undef HAVE_PROTOTYPE_LIB_gettimeofday
/* Define if you have the clock_gettime function */
#undef HAVE_CLOCK_GETTIME
/* Define if you have the strtoll function */
#undef HAVE_STRTOLL
/* Define if you have the hstrerror function */
#undef HAVE_HSTRERROR
/* Define if you have the inet_ntop function */
#undef HAVE_INET_NTOP
/* Define if you have the hstrerror prototype */
#undef HAVE_PROTOTYPE_HSTRERROR
/* Define if you have the <stdbool.h> header file. */
#undef HAVE_STDBOOL_H
/* Define if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
/* Define if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define if you have the <sys/param.h> header file. */
#undef HAVE_SYS_PARAM_H
/* Define if you have the <sys/ioctl.h> header file. */
#undef HAVE_SYS_IOCTL_H
/* Define if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define if you have the <syslog.h> header file. */
#undef HAVE_SYSLOG_H
/* Define if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define if you have the <pwd.h> header file. */
#undef HAVE_PWD_H
/* Define if you have the <grp.h> header file. */
#undef HAVE_GRP_H
/* Define if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define if you have the <poll.h> header file. */
#undef HAVE_POLL_H
/* Define if you have the <sys/poll.h> header file. */
#undef HAVE_SYS_POLL_H
/* Define if you have the <sys/socket.h> header file. */
#undef HAVE_SYS_SOCKET_H
/* Define if you have the <sys/uio.h> header file. */
#undef HAVE_SYS_UIO_H
/* Define if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define if you have the <netdb.h> header file. */
#undef HAVE_NETDB_H
/* Define if you have the <sys/un.h> header file. */
#undef HAVE_SYS_UN_H
/* Define if you have the <pty.h> header file. */
#undef HAVE_PTY_H
/* Define if you have the <netinet/in.h> header file. */
#undef HAVE_NETINET_IN_H
/* Define if you have the <netinet/in_systm.h> header file. */
#undef HAVE_NETINET_IN_SYSTM_H
/* Define if you have the <netinet/ip.h> header file. */
#undef HAVE_NETINET_IP_H
/* Define if you have the <netinet/tcp.h> header file. */
#undef HAVE_NETINET_TCP_H
/* Define if you have the <netinet/ip6.h> header file. */
#undef HAVE_NETINET_IP6_H
/* Define if you have the <netinet6/in6.h> header file. */
#undef HAVE_NETINET6_IN6_H
/* Define if you have the <arpa/nameser.h> header file. */
#undef HAVE_ARPA_NAMESER_H
/* Define if you have the <resolv.h> header file. */
#undef HAVE_RESOLV_H
/* Define if you have the <termios.h> header file. */
#undef HAVE_TERMIOS_H
/* Define if you have the <net/if.h> header file. */
#undef HAVE_NET_IF_H
/* Define if you have the <net/if_dl.h> header file. */
#undef HAVE_NET_IF_DL_H
/* Define if you have the <linux/types.h> header file. */
#undef HAVE_LINUX_TYPES_H
/* Define if you have the <linux/errqueue.h> header file. */
#undef HAVE_LINUX_ERRQUEUE_H
/* Define if you have the <linux/if_tun.h> header file. */
#undef HAVE_LINUX_IF_TUN_H
/* Define if you have the <linux/dccp.h> header file. */
#undef HAVE_LINUX_DCCP_H
/* Define if you have the <linux/vm_sockets.h> header file. */
#undef HAVE_LINUX_VM_SOCKETS_H
/* Define if you have the <sched.h> header file. */
#undef HAVE_SCHED_H
/* Define if you have the <linux/if_packet.h> header file. */
#undef HAVE_LINUX_IF_PACKET_H
/* Define if you have the <netinet/if_ether.h> header file. */
#undef HAVE_NETINET_IF_ETHER_H
/* Define if you have the <sys/utsname.h> header file. */
#undef HAVE_SYS_UTSNAME_H
/* Define if you have the <sys/select.h> header file. (AIX) */
#undef HAVE_SYS_SELECT_H
/* Define if you have the <sys/file.h> header file. (AIX) */
#undef HAVE_SYS_FILE_H
/* Define if you have the <util.h> header file. (NetBSD, OpenBSD: openpty()) */
#undef HAVE_UTIL_H
/* Define if you have the <bsd/libutil.h> header file. */
#undef HAVE_BSD_LIBUTIL_H
/* Define if you have the <libutil.h> header file. (FreeBSD: openpty()) */
#undef HAVE_LIBUTIL_H
/* Define if you have the <sys/stropts.h> header file. (stream opts on SunOS)*/
#undef HAVE_SYS_STROPTS_H
/* Define if you have the <regex.h> header file. */
#undef HAVE_REGEX_H
/* Define if you have the <linux/fs.h> header file. */
#undef HAVE_LINUX_FS_H
/* Define if you have the <linux/ext2_fs.h> header file. */
#undef HAVE_LINUX_EXT2_FS_H
/* Define if you have the <readline/readline.h> header file. */
#undef HAVE_READLINE_READLINE_H
/* Define if you have the <readline/history.h> header file. */
#undef HAVE_READLINE_HISTORY_H
/* Define if you have the readline library. */
#undef HAVE_LIBREADLINE
/* Define if you have the m library (-lm). */
#undef HAVE_LIBM
/* Define if you have the floor function */
#undef HAVE_FLOOR
/* some platforms need _XOPEN_EXTENDED_SOURCE to get syslog headers (AIX4.1) */
#undef _XOPEN_EXTENDED_SOURCE
/* fdset may have component fds_bits or __fds_bits */
#undef HAVE_FDS_BITS
/* struct termios may have components c_ispeed,c_ospeed */
#undef HAVE_STRUCT_TERMIOS_C_ISPEED
#undef HAVE_STRUCT_TERMIOS_C_OSPEED
/* Define if you have the sa_family_t */
#undef HAVE_TYPE_SA_FAMILY_T
/* define if your struct sigaction has sa_sigaction */
#undef HAVE_STRUCT_SIGACTION_SA_SIGACTION
/* define if you have struct sock_extended_err */
#undef HAVE_STRUCT_SOCK_EXTENDED_ERR
/* Define if your termios.h likes _SVID3 defined */
#undef _SVID3
/* Define if your sys/socket.h likes _XPG4_2 defined */
#undef _XPG4_2
/* Define if your ctime_r() choices need _POSIX_PTHREAD_SEMANTICS */
#undef _POSIX_PTHREAD_SEMANTICS
/* Define if you need __EXTENSIONS__ */
#undef __EXTENSIONS__
/* Define if you have struct timespec (e.g. for nanosleep) */
#undef HAVE_STRUCT_TIMESPEC
/* Define if you have struct linger */
#undef HAVE_STRUCT_LINGER
/* Define if you have struct ip */
#undef HAVE_STRUCT_IP
/* Define if you have struct ip_mreq */
#undef HAVE_STRUCT_IP_MREQ
/* Define if you have struct ip_mreqn */
#undef HAVE_STRUCT_IP_MREQN
/* Define if you have struct ipv6_mreq */
#undef HAVE_STRUCT_IPV6_MREQ
/* Define if you have struct ip_mreq_source */
#undef HAVE_STRUCT_IP_MREQ_SOURCE
/* Define if you have struct group_source_req */
#undef HAVE_STRUCT_GROUP_SOURCE_REQ
/* Define if you have struct ifreq */
#undef HAVE_STRUCT_IFREQ
/* Define if you have struct ifreq.ifr_index */
#undef HAVE_STRUCT_IFREQ_IFR_INDEX
/* Define if you have struct ifreq.ifr_ifindex; not on HPUX */
#undef HAVE_STRUCT_IFREQ_IFR_IFINDEX
/* Define if your struct sockaddr has sa_len */
#undef HAVE_STRUCT_SOCKADDR_SALEN
/* there are several implementations of sockaddr_in6 */
#undef HAVE_IP6_SOCKADDR
/* Define if you have struct iovec */
#undef HAVE_STRUCT_IOVEC
/* define if your struct msghdr has msg_control */
#undef HAVE_STRUCT_MSGHDR_MSGCONTROL
/* define if your struct msghdr has msg_controllen */
#undef HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
/* define if your struct msghdr has msg_flag */
#undef HAVE_STRUCT_MSGHDR_MSGFLAGS
/* define if you have struct cmsghdr */
#undef HAVE_STRUCT_CMSGHDR
/* define if you have struct in_pktinfo */
#undef HAVE_STRUCT_IN_PKTINFO
/* define if your struct in_pktinfo has component ipi_spec_dst */
#undef HAVE_PKTINFO_IPI_SPEC_DST
/* define if you have struct in6_pktinfo */
#undef HAVE_STRUCT_IN6_PKTINFO
/* define if you have struct tpacket_auxdata */
#undef HAVE_STRUCT_TPACKET_AUXDATA
/* define if you have struct tpacket_auxdata and it has tp_vlan_tpid */
#undef HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TPID
/* define if your struct ip has ip_hl; otherwise assume ip_vhl */
#undef HAVE_STRUCT_IP_IP_HL
/* Define if you have the setns function */
#undef HAVE_SETNS
/* Define if you have the setenv function */
#undef HAVE_SETENV
/* Define if you have the unsetenv function. not on HP-UX */
#undef HAVE_UNSETENV
/* Define if you have the cfsetispeed,cfgetispeed,cfsetspeed,cfgetospeed function */
#undef HAVE_CFSETISPEED
#undef HAVE_CFSETOSPEED
#if HAVE_CFSETISPEED
# define HAVE_TERMIOS_ISPEED 1
#endif
#if HAVE_CFSETOSPEED
# define HAVE_TERMIOS_OSPEED 1
#endif
#if defined(HAVE_TERMIOS_ISPEED) && defined(HAVE_TERMIOS_OSPEED)
# define HAVE_TERMIOS_SPEED 1
#endif
/* Define if you have the OPENSSL_init_ssl function */
#undef HAVE_OPENSSL_INIT_SSL
/* Define if you have the OPENSSL_INIT_SETTINGS type (guarded for OpenBSD) */
#undef HAVE_OPENSSL_INIT_SETTINGS
/* Define if you have the SSL_library_init function */
#undef HAVE_SSL_library_init
/* Define if you have the OPENSSL_INIT_new function */
#undef HAVE_OPENSSL_INIT_new
/* Define if you have the SSLv2 client and server method functions. not in new openssl */
#undef HAVE_SSLv2_client_method
#undef HAVE_SSLv2_server_method
/* Define if you have the HAVE_SSL_CTX_set_default_verify_paths function */
#undef HAVE_SSL_CTX_set_default_verify_paths
/* Define if you have the TLS client and server method functions. not in old openssl? */
#undef HAVE_TLS_client_method
#undef HAVE_TLS_server_method
/* Define if you have the SSLv3 client and server method functions. not in new openssl */
#undef HAVE_SSLv3_client_method
#undef HAVE_SSLv3_server_method
/* Define if you have the SSLv3 client and server method functions with rollback to v2 */
#undef HAVE_SSLv23_client_method
#undef HAVE_SSLv23_server_method
/* Define if you have the TLSv1.0 client and server method functions */
#undef HAVE_TLSv1_client_method
#undef HAVE_TLSv1_server_method
/* Define if you have the TLSv1.1 client and server method functions */
#undef HAVE_TLSv1_1_client_method
#undef HAVE_TLSv1_1_server_method
/* Define if you have the TLSv1.2 client and server method functions */
#undef HAVE_TLSv1_2_client_method
#undef HAVE_TLSv1_2_server_method
/* Define if you have the DTLS client and server method functions */
#undef HAVE_DTLS_client_method
#undef HAVE_DTLS_server_method
/* Define if you have the DTLSv1 client and server method functions */
#undef HAVE_DTLSv1_client_method
#undef HAVE_DTLSv1_server_method
/* Define if you have the SSL CTX_set_min_proto_version function/macro */
#undef HAVE_SSL_CTX_set_min_proto_version
/* Define if you have the SSL_CTX_set_max_proto_version function/macro */
#undef HAVE_SSL_CTX_set_max_proto_version
/* Define if you have the DTLSv1_2 client and server method functions */
#undef HAVE_DTLSv1_2_client_method
#undef HAVE_DTLSv1_2_server_method
/* Define if you have the EC_KEY type */
#undef HAVE_TYPE_EC_KEY
/* Define if you have the OpenSSL RAND_egd function */
#undef HAVE_RAND_egd
/* Define if you have the OpenSSL RAND_status function */
#undef HAVE_RAND_status
/* Define if you have the OpenSSL DH_set0_pqg function */
#undef HAVE_DH_set0_pqg
/* Define if you have the OpenSSL ASN1_STRING_get0_data function */
#undef HAVE_ASN1_STRING_get0_data
/* Define if you have the OpenSSL SSL_CTX_clear_mode macro or function */
#undef HAVE_SSL_CTX_clear_mode
/* Define if you have the OpenSSL SSL_set_tlsext_host_name define/function */
#undef HAVE_SSL_set_tlsext_host_name
/* Define if you have the OpenSSL SSL_CTX_set_tlsext_max_fragment_length define/function */
#undef HAVE_SSL_CTX_set_tlsext_max_fragment_length
/* Define if you have the OpenSSL SSL_CTX_set_max_send_fragment define/function */
#undef HAVE_SSL_CTX_set_max_send_fragment
/* Define if you have the flock function */
#undef HAVE_FLOCK
/* Define if you have the openpty function */
#undef HAVE_OPENPTY
/* Define if you have the grantpt function */
#undef HAVE_GRANTPT
/* Define if you have the unlockpt function */
#undef HAVE_UNLOCKPT
/* Define if you have the ptsname function */
#undef HAVE_PROTOTYPE_LIB_ptsname
/* Define if you have the /dev/ptmx pseudo terminal multiplexer */
#undef HAVE_DEV_PTMX
/* Define if you have the /dev/ptc pseudo terminal multiplexer */
#undef HAVE_DEV_PTC
/* Define if you have the cfmakeraw() function */
#undef HAVE_CFMAKERAW
/* Define if you have the long long type */
#undef HAVE_TYPE_LONGLONG
/* is sig_atomic_t declared */
#undef HAVE_TYPE_SIG_ATOMIC_T
/* is bool already typedef'd? */
#undef HAVE_TYPE_BOOL
/* is socklen_t already typedef'd? */
#undef HAVE_TYPE_SOCKLEN
/* Define if you have the struct stat64 type */
#undef HAVE_TYPE_STAT64
/* Define if you have the struct off64_t type */
#undef HAVE_TYPE_OFF64
/* is sighandler_t already typedef'd? */
#undef HAVE_TYPE_SIGHANDLER
/* is uint8_t already defined? */
#undef HAVE_TYPE_UINT8
/* is uint16_t already defined? */
#undef HAVE_TYPE_UINT16
/* is uint32_t already defined? */
#undef HAVE_TYPE_UINT32
/* is uint64_t already defined? */
#undef HAVE_TYPE_UINT64
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS
/* Define for large files, on AIX-style hosts. */
#undef _LARGE_FILES
/* Define if snprintf() returns required len on truncation (C-99 conform) */
#undef HAVE_C99_SNPRINTF
/* Define if you have the printf "Z" modifier */
#undef HAVE_FORMAT_Z
/* Define the shift offset of the CRDLY mask */
#undef CRDLY_SHIFT
/* Define the shift offset of the TABDLY mask */
#undef TABDLY_SHIFT
/* Define the shift offset of the CSIZE mask */
#undef CSIZE_SHIFT
/* Define if you have tcpwrappers (libwrap, tcpd) and it declares hosts_allow_table */
#undef HAVE_HOSTS_ALLOW_TABLE
#if defined(HAVE_HOSTS_ALLOW_TABLE) && HAVE_HOSTS_ALLOW_TABLE
# define HAVE_HOSTS_DENY_TABLE 1
#else
# undef HAVE_HOSTS_DENY_TABLE
#endif
/* 1..short, 3..int, 5..long; 2,4,6..unsigned */
#undef HAVE_BASIC_UINT16_T
#undef HAVE_BASIC_UINT32_T
#undef HAVE_BASIC_UINT64_T
#undef HAVE_BASIC_INT16_T
#undef HAVE_BASIC_INT32_T
#undef HAVE_BASIC_INT64_T
#undef HAVE_BASIC_SIZE_T
#undef HAVE_BASIC_MODE_T
#undef HAVE_BASIC_PID_T
#undef HAVE_BASIC_UID_T
#undef HAVE_BASIC_GID_T
#undef HAVE_BASIC_TIME_T
#undef HAVE_BASIC_OFF_T
#undef HAVE_BASIC_OFF64_T
#undef HAVE_BASIC_DEV_T
#undef HAVE_BASIC_SPEED_T
#undef HAVE_BASIC_SOCKLEN_T
#undef HAVE_TYPEOF_ST_INO
#undef HAVE_TYPEOF_ST_NLINK
#undef HAVE_TYPEOF_ST_SIZE
#undef HAVE_TYPEOF_ST_BLKSIZE
#undef HAVE_TYPEOF_ST_BLOCKS
#undef HAVE_TYPEOF_ST64_DEV
#undef HAVE_TYPEOF_ST64_INO
#undef HAVE_TYPEOF_ST64_NLINK
#undef HAVE_TYPEOF_ST64_SIZE
#undef HAVE_TYPEOF_ST64_BLKSIZE
#undef HAVE_TYPEOF_ST64_BLOCKS
#undef HAVE_TYPEOF_STRUCT_TIMEVAL_TV_USEC
#undef HAVE_TYPEOF_STRUCT_TIMESPEC_TV_NSEC
#undef HAVE_TYPEOF_RLIM_MAX
#undef HAVE_TYPEOF_STRUCT_CMSGHDR_CMSG_LEN
/* Define if you have the /proc filesystem */
#undef HAVE_PROC_DIR
/* Define if you have the /proc/$$/fd directories */
#undef HAVE_PROC_DIR_FD
#undef HAVE_PROC_DIR_PATH
#undef HAVE_DIRENT_D_TYPE
#undef HAVE_RES_RETRANS
#undef HAVE_RES_RETRY
#undef HAVE_RES_NSADDR_LIST
#undef HAVE_SETGRENT
#undef HAVE_GETGRENT
#undef HAVE_ENDGRENT
#undef HAVE_GETGROUPLIST
#undef WITH_HELP
#undef WITH_STATS
#undef WITH_STDIO
#undef WITH_FDNUM
#undef WITH_FILE
#undef WITH_CREAT
#undef WITH_GOPEN
#undef WITH_TERMIOS
#undef WITH_PIPE
#undef WITH_SOCKETPAIR
#undef WITH_UNIX
#undef WITH_ABSTRACT_UNIXSOCKET
#undef WITH_IP4
#undef WITH_IP6
#undef WITH_RAWIP
#undef WITH_GENERICSOCKET
#undef WITH_INTERFACE
#undef WITH_TCP
#undef WITH_UDP
#undef WITH_UDPLITE
#undef WITH_SCTP
#undef WITH_DCCP
#undef WITH_LISTEN
#undef WITH_POSIXMQ
#undef WITH_SOCKS4
#undef WITH_SOCKS4A
#undef WITH_SOCKS5
#undef WITH_VSOCK
#undef WITH_NAMESPACES
#undef WITH_PROXY
#undef WITH_EXEC
#undef WITH_SYSTEM
#undef WITH_SHELL
#undef WITH_READLINE
#undef WITH_TUN
#undef WITH_PTY
#undef WITH_FS
#undef WITH_OPENSSL
#undef WITH_OPENSSL_METHOD
#undef WITH_RESOLVE
#undef WITH_RES_DEPRECATED /* AAONLY,PRIMARY */
#define WITH_STREAMS 1
#undef WITH_FIPS
#undef OPENSSL_FIPS
#undef WITH_LIBWRAP
#undef HAVE_TCPD_H
#undef HAVE_LIBWRAP
#undef WITH_SYCLS
#undef WITH_FILAN
#undef WITH_RETRY
#undef WITH_MSGLEVEL
#undef WITH_DEFAULT_IPV /* default IP version: "0", "4", "6" */
#define BUILD_DATE __DATE__ " " __TIME__
#endif /* !defined(__config_h_included) */

24007
configure vendored Executable file

File diff suppressed because it is too large Load Diff

2376
configure.ac Normal file

File diff suppressed because it is too large Load Diff

1
configure.in Symbolic link
View File

@@ -0,0 +1 @@
configure.ac

34
daemon.sh Executable file
View File

@@ -0,0 +1,34 @@
#! /bin/sh
# source: daemon.sh
# Copyright Gerhard Rieger and contributors (see file CHANGES)
# Published under the GNU General Public License V.2, see file COPYING
# This script assumes that you create group daemon1 and user daemon1 before.
# they need only the right to exist (no login etc.)
# Note: this pid file mechanism is not robust!
# You will adapt these variables
USER=daemon1
GROUP=daemon1
INIF=fwnonsec.domain.org
OUTIF=fwsec.domain.org
TARGET=w3.intra.domain.org
INPORT=80
DSTPORT=80
#
INOPTS="fork,setgid=$GROUP,setuid=$USER"
OUTOPTS=
PIDFILE=/var/run/socat-$INPORT.pid
OPTS="-d -d -lm" # notice to stderr, then to syslog
SOCAT=/usr/local/bin/socat
if [ "$1" = "start" -o -z "$1" ]; then
$SOCAT $OPTS tcp-l:$INPORT,bind=$INIF,$INOPTS tcp:$TARGET:$DSTPORT,bind=$OUTIF,$OUTOPTS </dev/null &
echo $! >$PIDFILE
elif [ "$1" = "stop" ]; then
/bin/kill $(/bin/cat $PIDFILE)
fi

330
dalan.c Normal file
View File

@@ -0,0 +1,330 @@
/* source: dalan.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* idea of a low level data description language. currently only a most
primitive subset exists. */
#include "config.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#if HAVE_STDBOOL_H
#include <stdbool.h>
#endif
#include <ctype.h>
#include "dalan.h"
/* test structure to find maximal alignment */
static struct {
char a;
long double b;
} maxalign;
/* test structure to find minimal alignment */
static struct {
char a;
char b;
} minalign;
/* test union to find kind of byte ordering */
static union {
char a[2];
short b;
} byteorder = { "01" };
struct dalan_opts_s dalan_opts = {
sizeof(int),
sizeof(short),
sizeof(long),
sizeof(char),
sizeof(float),
sizeof(double)
} ;
/* fill the dalan_opts structure with machine dependent defaults values. */
static void _dalan_dflts(struct dalan_opts_s *dlo) {
dlo->c_int = sizeof(int);
dlo->c_short = sizeof(short);
dlo->c_long = sizeof(long);
dlo->c_char = sizeof(char);
dlo->c_float = sizeof(float);
dlo->c_double = sizeof(double);
dlo->maxalign = (char *)&maxalign.b-&maxalign.a;
dlo->minalign = &minalign.b-&minalign.a;
dlo->byteorder = (byteorder.b!=7711);
}
/* allocate a new dalan_opts structure, fills it with machine dependent
defaults values, and returns the pointer. */
struct dalan_opts_s *dalan_props(void) {
struct dalan_opts_s *dlo;
dlo = malloc(sizeof(struct dalan_opts_s));
if (dlo == NULL) {
return NULL;
}
_dalan_dflts(dlo);
return dlo;
}
void dalan_init(void) {
_dalan_dflts(&dalan_opts);
}
/* Parses and coverts a data item.
Returns 0 on success,
-1 if the data was cut due to n limit,
1 if a syntax error occurred
2 if the actual character is white space
3 if the first character is not a type specifier
*/
static int dalan_item(int c, const char **line0, uint8_t *data, size_t *p, size_t n) {
const char *line = *line0;
size_t p1 = *p;
switch (c) {
case ' ':
case '\t':
case '\r':
case '\n':
return 2;
case '"':
while (1) {
switch (c = *line++) {
case '\0': fputs("unterminated string\n", stderr);
*line0 = line;
return 1;
case '"':
break;
case '\\':
if (!(c = *line++)) {
fputs("continuation line not implemented\n", stderr);
*line0 = line;
return 1;
}
switch (c) {
case 'n': c = '\n'; break;
case 'r': c = '\r'; break;
case 't': c = '\t'; break;
case 'f': c = '\f'; break;
case 'b': c = '\b'; break;
case 'a': c = '\a'; break;
#if 0
case 'e': c = '\e'; break;
#else
case 'e': c = '\033'; break;
#endif
case '0': c = '\0'; break;
}
/* PASSTHROUGH */
default:
if (p1 >= n) {
*p = p1;
*line0 = line;
return -1;
}
data[p1++] = c;
continue;
}
if (c == '"')
break;
}
break;
case '\'':
switch (c = *line++) {
case '\0': fputs("unterminated character\n", stderr);
*line0 = line;
return 1;
case '\'': fputs("error in character\n", stderr);
*line0 = line;
return 1;
case '\\':
if (!(c = *line++)) {
fputs("continuation line not implemented\n", stderr);
*line0 = line;
return 1;
}
switch (c) {
case 'n': c = '\n'; break;
case 'r': c = '\r'; break;
case 't': c = '\t'; break;
case 'f': c = '\f'; break;
case 'b': c = '\b'; break;
case 'a': c = '\a'; break;
#if 0
case 'e': c = '\e'; break;
#else
case 'e': c = '\033'; break;
#endif
}
/* PASSTHROUGH */
default:
if (p1 >= n) { *p = p1; return -1; }
data[p1++] = c;
break;
}
if (*line != '\'') {
fputs("error in character termination\n", stderr);
*p = p1;
*line0 = line;
return 1;
}
++line;
break;
case 'x':
/* expecting hex data, must be an even number of digits!! */
while (true) {
int x;
c = *line;
if (isdigit(c&0xff)) {
x = (c-'0') << 4;
} else if (isxdigit(c&0xff)) {
x = ((c&0x07) + 9) << 4;
} else
break;
++line;
c = *line;
if (isdigit(c&0xff)) {
x |= (c-'0');
} else if (isxdigit(c&0xff)) {
x |= (c&0x07) + 9;
} else {
fputs("odd number of hexadecimal digits\n", stderr);
*p = p1;
*line0 = line;
return 1;
}
++line;
if (p1 >= n) {
*p = p1;
*line0 = line;
return -1;
}
data[p1++] = x;
}
break;
case 'l':
/* expecting decimal number, with target type long */
{
char *endptr;
*(long *)&data[p1] = strtol(line, &endptr, 10);
p1 += sizeof(long);
line = endptr;
}
break;
case 'L':
/* expecting decimal number, with target type unsigned long */
{
char *endptr;
*(unsigned long *)&data[p1] = strtol(line, &endptr, 10);
p1 += sizeof(unsigned long);
line = endptr;
}
break;
case 'i':
/* expecting decimal number, with target type int */
{
char *endptr;
*(int *)&data[p1] = strtol(line, &endptr, 10);
p1 += sizeof(int);
line = endptr;
}
break;
case 'I':
/* expecting decimal number, with target type unsigned int */
{
char *endptr;
*(unsigned int *)&data[p1] = strtol(line, &endptr, 10);
p1 += sizeof(unsigned int);
line = endptr;
}
break;
case 's':
/* expecting decimal number, with target type short */
{
char *endptr;
*(short *)&data[p1] = strtol(line, &endptr, 10);
p1 += sizeof(short);
line = endptr;
}
break;
case 'S':
/* expecting decimal number, with target type unsigned short */
{
char *endptr;
*(unsigned short *)&data[p1] = strtol(line, &endptr, 10);
p1 += sizeof(unsigned short);
line = endptr;
}
break;
case 'b':
/* expecting decimal number, with target type byte (int8_t) */
{
char *endptr;
*(int8_t *)&data[p1] = strtoul(line, &endptr, 10);
p1 += sizeof(uint8_t);
line = endptr;
}
case 'B':
/* expecting decimal number, with target type byte (uint8_t) */
{
char *endptr;
*(uint8_t *)&data[p1] = strtoul(line, &endptr, 10);
p1 += sizeof(uint8_t);
line = endptr;
}
break;
default:
*line0 = line;
return 3;
}
*p = p1;
*line0 = line;
return 0;
}
/* read data description from line (\0-terminated), write result to data; do
not write so much data that *p exceeds n !
*p must be initialized.
return 0 on success,
-1 if the data was cut due to n limit,
1 if a syntax error occurred
*p is a global data counter; especially it must be used when calculating
alignment. On successful return from the function *p must be actual!
*/
int dalan(const char *line, uint8_t *data, size_t *p, size_t n, char deflt) {
size_t p0;
char c;
int rc;
while (1) {
/* assume there is a type specifier on beginning of rest of line */
c = *line++;
if (c == '\0')
break;
p0 = *p;
rc = dalan_item(c, &line, data, p, n);
if (rc == 0) {
deflt = c; /* continue with this type as default */
} else if (rc == 2) {
/* white space */
continue;
} else if (rc == 3) {
const char *line0;
--line;
line0 = line;
/* No, we did not recognize c as type specifier, try default type */
rc = dalan_item(deflt, &line, data, p, n);
if (line == line0) {
/* Nothing was parsed */
return 1;
}
}
if (rc != 0) {
return rc;
}
/* rc == 0 */
n -= (*p-p0);
}
return 0;
}

30
dalan.h Normal file
View File

@@ -0,0 +1,30 @@
/* source: dalan.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __dalan_h_included
#define __dalan_h_included 1
#include "mytypes.h"
/* machine properties and command line options */
struct dalan_opts_s {
int c_int; /* natural int size / C int size */
int c_short; /* C short size */
int c_long; /* C long size */
int c_char; /* C char size */
int c_float; /* C float size */
int c_double; /* C double size */
int maxalign; /* maximal alignment (double after char) */
int minalign; /* minimal alignment (char after char) */
int byteorder; /* 0: Motorola, network, big endian; 1: Intel, little
endian */
} ;
extern struct dalan_opts_s dalan_opts;
extern void dalan_init(void);
extern struct dalan_opts_s *dalan_props(void);
extern int dalan(const char *line, uint8_t *data, size_t *p, size_t n, char deflt);
#endif /* !defined(__dalan_h_included) */

28
doc/dest-unreach.css Normal file
View File

@@ -0,0 +1,28 @@
table {
empty-cells: show;
}
.shell {
display: block;
font-family: Courier;
padding: 6px;
padding-top: 10px;
padding-bottom: 4px;
border: 3px solid grey;
color: lightgreen;
background-color: black;
text-align: left;
white-space: pre;
}
.error {
display: inline;
block-size: auto;
font-family: monospace;
background-color: #e08080;
border: 4px;
padding: 2px;
padding-right: 4px;
border-style: ridge;
border-color: #e08080;
}

View File

@@ -0,0 +1,328 @@
<html><head>
<title>Generic sockets with Socat</title>
<link rel="stylesheet" type="text/css" href="dest-unreach.css">
</head>
<body>
<h1>Generic sockets with Socat</h1>
<h2>Introduction</h2>
<p>Beginning with version 1.7.0 socat provides means to freely control
important aspects of socket handling. This allows to experiment with socket
types and protocols that are not explicitely implemented in socat.
</p>
<p>The related socat features fall into three major categories:<p>
<ul>
<li>address options for changing socket parameters while using common
socket types:
<tt>pf (protocol-family), so-type (socktype), so-prototype (protocol)</tt>
</li>
<li>address options for setting arbitrary socket options:
<tt>setsockopt-int, setsockopt-string, setsockopt-bin</tt></li>
<li>address types for passing almost arbitrary parameters and address data to
the standard system calls:
<tt>socket-connect, socket-listen, socket-sendto, socket-recv,
socket-recvfrom, socket-datagram</tt></li>
</ul>
<p>In practice this gives you two possibilities:</p>
<p>If you want to cope with sockets staying within the usual domains ( =
protocol families = address families) which are IPv4, IPv6, UNIX/local, and
raw interface for socat 1.7.0, it is sufficient to learn about a couple of
<a href="#GENERIC_OPTIONS">address options</a> that allow to change default
parameters, and to apply generic socket options.</p>
<p>For other address families socat provides <a
href="#GENERIC_ADDRESSES">generic socket addresses</a>.
</p>
<a name="GENERIC_OPTIONS"></a>
<h2>Generic socket options</h2>
<h3>Example 1: DCCP communication</h3>
<p>A relatively new communication protocol has been introduced in the Internet
community for which no socat address type has been implemented up to version
1.7.0
(see <a href="http://www.ietf.org/html.charters/dccp-charter.html">IETF's
Datagram Congestion Control Protocol</a>
and <a href="http://www.linuxfoundation.org/en/Net:DCCP#python_support">Linux
foundation Net:DCCP</a> for more info). Taken that the
operating system implements DCCP, it is possible to use this protocol
with socat while just employing standard socket addresses and some options.
</p>
<p>A simple server that accepts a DCCP connection, passes the arriving data to a
subprocess for converting upper case to lower case characters, and then
returns it to the client:
</p>
<span class="shell">socat \
TCP4-LISTEN:4096,reuseaddr,type=6,prototype=33 \
EXEC:'tr A-Z a-z',pty,raw,echo=0
</span>
<p>A simple client that sends some upper case characters to the server via DCCP
and prints what the server returns:
</p>
<span class="shell">echo ABCD | \
socat - \
TCP4-CONNECT:localhost:4096,type=6,prototype=33
</span>
<p>We choose the TCP4 addresses as base because it best matches the DCCP
requirements:
<ol>
<li>DCCP is (here) based on IPv4</li>
<li>DCCP is stream oriented and uses <tt>connect()</tt> and <tt>listen();
accept()</tt> calls</li>
<li>DCCP protocol uses ports</li>
</ol>
</p>
<p>Option <tt><a href="socat.html#OPTION_SO_TYPE">type</a>=6</tt> changes TCP's
<tt>SOCK_STREAM</tt> parameter to <tt>SOCK_DCCP</tt>, and <tt>
<a href="socat.html#OPTION_SO_PROTOTYPE">prototype</a>=33</tt> replaces the
default <tt>IPPROTO_TCP</tt> with <tt>IPPROTO_DCCP</tt>.
</p>
<p>DCCP has an important parameter, the service code. It provides another
multiplexing layer beyond the protocol ports. The Linux implementation of DCCP
allows to set this parameter with code like <tt>setsocktopt(fd, SOL_DCCP,
DCCP_SOCKOPT_SERVICE, {1}, sizeof(int))</tt>. The equivalent generic socat
option is: <tt><a href="socat.html#OPTION_SETSOCKOPT_INT">setsockopt-int</a>=269:2:1</tt> for service code 1.
If the service codes on server and client do not match the <tt>connect()</tt>
operation fails with error:<p>
<span class="error">... E connect(3, AF=2 127.0.0.1:4096, 16): Invalid request code</span>
<p>Please note that this examples works with IPv6 as well, you just need to
replace the TCP4 words with TCP6, and the IPv4 socket address with an
appropriate IPv6 socket address, e.g. <tt>[::1]</tt>!
</p>
<a name="GENERIC_ADDRESSES"></a>
<h2>Generic socket addresses</h2>
<p>socat's generic socket addresses are a more comprehensive mechanism that
allows to deal with protocol families whose socket addresses are not supported
by socat - no semantical parsing, no structured assignment to the struct
components are available. Instead, the socket address records for binding and
connecting/sending are specified in unstructured hexadecimal form. The
following example demonstrates this by performing simple data transfer over
raw AppleTalk protocol.
</p>
<p>Note: I do not have any knowledge about AppleTalk. I just managed to
configure my Linux host to tolerate the creation of a receiving and a sending
socket. Don't blame me nor ask me for support if it does not work for you.
</p>
<a name="EXAMPLE_APPLETALK"></a>
<h3>Enabling AppleTalk protocol</h3>
<p>Install the <tt>netatalk</tt> package. Check that <tt>/etc/netatalk/atalkd.conf</tt>
has an entry like <tt>eth0 -phase 2 -net 0-65534 -addr 65280.243</tt>. The
last part is an arbitrary (?) host address, some of the following values must
fit it. Make sure the <tt>atalkd</tt> daemon is running. Run the AppleTalk
ping command:
</p>
<span class="shell">aecho 65280.243
</span>
<p>If you get an error like:
</p>
<span class="error">Device or resource busy</span>
<p>then try to restart <tt>atalkd</tt>:</p>
<span class="shell">/etc/init.d/atalkd restart
</span>
<p>When <tt>aecho</tt> works like <tt>ping</tt> you are ready for the next step.
</p>
<h3>Example 2: AppleTalk datagram communication</h3>
<p>We start a socat process with a receiver and echo service:
</p>
<span class="shell">socat \
SOCKET-RECVFROM:5:2:0:x40x00x0000x00x00x0000000000000000 \
PIPE
</span>
<p>Then, in another shell on the same host, we start a client socket process
that sends data to the server and gets the answer:
</p>
<span class="shell">echo ABCD | \
socat - \
SOCKET-DATAGRAM:5:2:0:x40x00xff00xf3x00x0000000000000000
</span>
<p>The client process should print the data.
</p>
<p>How did this work? The generic socat address has just used the system call
parameters that were provided on command line, without knowing anything about
AppleTalk sockets and protocol. The values 5, 2, and 0 are directly used for
the <tt>socket()</tt> call: they specify the domain (<tt>PF_APPLETALK=5</tt>),
socket type (<tt>SOCK_DGRAM=2</tt>), and no protocol (0) - values for Linux.
The long hex strings define the socket addresses. They can only be constructed
with knowledge of the underlying structure. In
<tt>/usr/include/linux/atalk.h</tt> we find the following declarations:
</p>
<pre>
struct atalk_addr {
__be16 s_net;
__u8 s_node;
};
struct sockaddr_at {
sa_family_t sat_family;
__u8 sat_port;
struct atalk_addr sat_addr;
char sat_zero[8];
</pre>
<p>After rolling out <tt>atalk_addr</tt> and considering implicit padding by the
C programming language we get the following byte map:
</p>
<table border="1">
<tr><th>component</th><th>offset</th><th>length</th><th>value</th><th>meaning</th></tr>
<tr><td>sat_family</td><td>0</td><td>2</td><td>x0005</td><td>address family</td></tr>
<tr><td>sat_port</td><td>2</td><td>1</td><td>x40</td><td>port</td></tr>
<tr><td>-</td><td>3</td><td>1</td><td>x00</td><td>padding</td></tr>
<tr><td>sat_addr.s_net</td><td>4</td><td>2</td><td>xff00</td><td>network address</td></tr>
<tr><td>sat_addr.s_node</td><td>6</td><td>1</td><td>xf3</td><td>node address</td></tr>
<tr><td>-</td><td>7</td><td>1</td><td>x00</td><td>padding</td></tr>
<tr><td>sat_zero</td><td>8</td><td>8</td><td>x0000000000000000</td><td>padding</td></tr>
</table>
<p>Note that hexadecimal ff00 is the same as decimal 65280, and hexadecimal xf3
is the same as decimal 243 - these are the numbers specified in
<tt>atalkd.conf</tt>.
</p>
<p>The address family component must be omitted from the socket address because
it is added by socat implicitely. The resulting hexadecimal representation of
the target socket address is therefore:
</p>
<tt>x40x00xff00xf3x00x0000000000000000</tt>
<p>The receiver just has to specify the port, so its bind address data is:
</p>
<tt>x40x00x0000x00x00x0000000000000000</tt>
<h2>Parameters for well known socket types</h2>
<p>Finding the correct parameters and socket addresses is not always trivial.
Therefore this section provides tables with the parameters of common socket
types. Some of these types are directly implemented by socat (and other
programs). Establishing interoperability between a directly implemented
socket and a generic socket might be your first step before entering unknown
ground.</p>
<h3>Socket parameters</h3>
<h4>Table: parameter names for "well known" sockets:</h4>
<table border=1>
<tr><th>name</th><th>domain</th><th>socktype</th><th>protocol</th><th> </th><th>level</th><th>remark</th></tr>
<tr><td>UDP4</td><td>PF_INET</td><td>SOCK_DGRAM</td><td>IPPROTO_UDP</td><td> </td><td>SOL_UDP</td><td></td></tr>
<tr><td>UDP6</td><td>PF_INET6</td><td>SOCK_DGRAM</td><td>IPPROTO_UDP</td><td> </td><td>SOL_UDP</td><td></td></tr>
<tr><td>raw IPv4</td><td>PF_INET</td><td>SOCK_RAW</td><td>IPPROTO_RAW</td><td> </td><td>SOL_IP</td><td></td></tr>
<tr><td>raw IPv6</td><td>PF_INET6</td><td>SOCK_RAW</td><td>IPPROTO_RAW</td><td> </td><td>SOL_IPV6</td><td></td></tr>
<tr><td>UNIX</td><td>PF_LOCAL</td><td>SOCK_DGRAM</td><td>0</td><td> </td><td>SOL_SOCKET</td><td> </td></tr>
<tr><td>PACKET</td><td>PF_PACKET</td><td>SOCK_RAW</td><td>768</td><td></td><td>SOL_PACKET</td><td>tcpdump (include layer 2 header)</td></tr>
<tr><td>PACKET</td><td>PF_PACKET</td><td>SOCK_DGRAM</td><td>768</td><td></td><td>SOL_PACKET</td><td>no level 2 header</td></tr>
<tr><td>SCTP4</td><td>PF_INET</td><td>SOCK_SEQPACKET</td><td>IPPROTO_SCTP</td><td> </td><td>SOL_SCTP</td><td> </td></tr>
</table>
<h4>Table: parameter values:</h4>
<table border=1>
<tr><th>name</th><th>Linux</th><th>FreeBSD</th><th>NetBSD</th><th>OpenBSD</th><th>Solaris</th><th>AIX</th><th>Cygwin</th><th>Mac OS X</th><th>HP-UX</th></tr>
<tr><td>PF_LOCAL</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td></tr>
<tr><td>PF_INET</td><td>2</td><td>2</td><td>2</td><td>2</td><td>2</td><td>2</td><td>2</td><td>2</td><td>2</td></tr>
<tr><td>PF_APPLETALK</td><td>5</td><td>16</td><td>16</td><td>16</td><td>16</td><td>16</td><td>16</td><td>16</td><td>16</td></tr>
<tr><td>PF_INET6</td><td>10</td><td>28</td><td>24</td><td>24</td><td>26</td><td>24</td><td>-</td><td>30</td><td>22</td></tr>
<tr><td>PF_PACKET</td><td>17</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
<tr><td>SOCK_STREAM</td><td>1</td><td>1</td><td>1</td><td>1</td><td>2</td><td>1</td><td>1</td><td>1</td><td>1</td></tr>
<tr><td>SOCK_DGRAM</td><td>2</td><td>2</td><td>2</td><td>2</td><td>1</td><td>2</td><td>2</td><td>2</td><td>2</td></tr>
<tr><td>SOCK_RAW</td><td>3</td><td>3</td><td>3</td><td>3</td><td>4</td><td>3</td><td>3</td><td>3</td><td>3</td></tr>
<tr><td>SOCK_SEQPACKET</td><td>5</td><td>5</td><td>5</td><td>5</td><td>6</td><td>5</td><td>5</td><td>5</td><td>5</td></tr>
<tr><td>SOCK_DCCP</td><td>(6)</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
<tr><td>SOCK_PACKET</td><td>10</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
<tr><td>IPPROTO_IP</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td></tr>
<tr><td>IPPROTO_TCP</td><td>6</td><td>6</td><td>6</td><td>6</td><td>6</td><td>6</td><td>6</td><td>6</td><td>6</td></tr>
<tr><td>IPPROTO_UDP</td><td>17</td><td>17</td><td>17</td><td>17</td><td>17</td><td>17</td><td>17</td><td>17</td><td>17</td></tr>
<tr><td>IPPROTO_DCCP</td><td>33</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
<tr><td>IPPROTO_SCTP</td><td>132</td><td>132</td><td>-</td><td>-</td><td>132</td><td>132</td><td>-</td><td>-</td><td>-</td></tr>
<tr><td>IPPROTO_RAW</td><td>255</td><td>255</td><td>255</td><td>255</td><td>255</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
<tr><td>SOL_SOCKET</td><td>1</td><td>65535</td><td>65535</td><td>65535</td><td>65535</td><td>65535</td><td>65535</td><td>65535</td><td>65535</td></tr>
<tr><td>SOL_IP</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td></tr>
<tr><td>SOL_TCP</td><td>6</td><td>6</td><td>6</td><td>6</td><td>6</td><td>6</td><td>6</td><td>6</td><td>6</td></tr>
<tr><td>SOL_UDP</td><td>17</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>17</td><td>-</td><td>-</td></tr>
<tr><td>SOL_IPV6</td><td>41</td><td>41</td><td>41</td><td>41</td><td>41</td><td>41</td><td>-</td><td>41</td><td>41</td></tr>
<tr><td>SOL_PACKET</td><td>263</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
<tr><td>SOL_DCCP</td><td>269</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
</table>
<h3>Socket address specifications</h3>
<p>These hexadecimal data define socket addresses for local and remote sockets,
and for bind and range options. The basis is the <tt>struct sockaddr_*</tt> for
the respective address family that should be declared in the C include files.
Please keep in mind that their first two bytes (<tt>sa_family</tt> and - on BSD
- <tt>sa_len</tt>) are implicitely prepended by socat.</p>
<h4>Linux on 32bit Intel:</h4>
<table border=1>
<tr><th>name</th><th>socket address type (without leading address family)</th><th>binary specification</th></tr>
<tr><td>IPv4</td><td>2 bytes port, 4 bytes IPv4 addr, 8 bytes 0</td><td>x0016
x7f000001 x0000000000000000</td></tr>
<tr><td>IPv6</td><td>2 bytes port, 4 bytes flowinfo, 16 bytes IPv6 addr, 4 bytes scope-id</td><td>x0016 x00000000 x0102030405060708090a0b0c0d0e0f x00000000</td></tr>
<tr><td>UNIX</td><td>variable length path name, 0 terminated</td><td>x2f746d702f736f636b00</td></tr>
<tr><td>PACKET</td><td>2 bytes protocol (0x0003), interface index as int in host byte order, 8 bytes 0</td><td>x0003 x02000000 x0000000000000000</td></tr>
</table>
<p>For AppleTalk see above <a href="#EXAMPLE_APPLETALK">example</a>.</p>
<h4>Solaris on 32bit Intel:</h4>
<table border=1>
<tr><th>name</th><th>socket address type (without leading address family)</th><th>binary specification</th></tr>
<tr><td>IPv6</td><td>2 bytes port, 4 bytes flowinfo, 16 bytes IPv6 addr, 4
bytes scope-id, 4 bytes src-id</td><td>x0016 x00000000 x0102030405060708090a0b0c0d0e0f x00000000 x00000000</td></tr>
</table>
<h3>Forever - play on...</h3>
<p>Eager to experiment with exotic socket types? Run nmap's protocol scan and
see what is available on your system:
</p>
<span class="shell">nmap -sO localhost
</span>
<p>
<small>Copyright: Gerhard Rieger 2008</small><br>
<small>License: <a href="http://www.fsf.org/licensing/licenses/fdl.html">GNU Free Documentation License (FDL)</a></small>
</p>
</body>
</html>

400
doc/socat-multicast.html Normal file
View File

@@ -0,0 +1,400 @@
<!-- source: doc/socat-multicast.html -->
<html><head>
<title>IP Multicasting with Socat</title>
<link rel="stylesheet" type="text/css" href="dest-unreach.css">
</head>
<body>
<h1>IP Multicasting with Socat</h1>
<h2>Introduction</h2>
<p>
Multicasting (and broadcasting which is also discussed in this article)
provides a means to direct a single packet to more than one host. Special
addresses are defined for this purpose and are handled specially by network
adapters, networking hardware, and IP stacks.
</p>
<p>
IPv4 specifications provide broadcasting and multicasting; IPv6 provides
multicasting but replaces broadcasting by special multicast modes. UNIX domain
sockets do not know broadcasting or multicasting.
</p>
<p>
The following examples use UDP/IPv4 only. However, they can easily be
adapted for raw IPv4 sockets. IPv6 multicasting has not yet been successfully
used with socat; please contact the author if you have positive experiences or
ideas that go beyond <tt>IPV6_ADD_MEMBERSHIP</tt>.
</p>
<p>
All multicast examples presented in this document use multicast address
224.1.0.1; it can be replaced by any valid IPv4 multicast address (except
<a href="#ALLSYSTEMS">all-systems</a>).
</p>
<p>
We assume a local network with address 192.168.10.0 and mask 255.255.255.0; an
eventual "client" has 192.168.10.1, example "server" and example peer have
192.168.10.2 in all examples. Change these addresses and mask to your own
requirements.
</p>
<p>
All the following examples work bidirectionally except when otherwise noticed.
For "clients" we just use <tt>STDIO</tt>, and for "servers" we use <tt>EXEC:hostname</tt> which
ingores its input but shows us which host the reply comes from. Replace these
socat addresses with what is appropriate for your needs (e.g. shell script
invocations). Port 6666 can be replaced with any other port (but for ports &lt;
1024 root privilege might be required).
</p>
<p>
Different kinds of broadcast addresses exist: 255.255.255.255 is local network
only; for the IPv4 network 192.168.10.0/24 the "official" broadcast address
is 192.168.10.255; the network address 192.168.10.0 is also interpreted as
broadcast by some hosts. The two latter forms are routed by gateways. In the
following examples we only use broadcast address 192.168.10.255.
</p>
<h2>Example 1: Multicast client and servers</h2>
<p>This example builds something like a "supervisor" or "client" that
communicates with a set of "servers". The supervisor may send packets to the
multicast address, and the servers may send response packets. Note that the
servers would also respond to other clients' requests.</p>
<p>Multicast server:</p>
<div class="shell">socat \
UDP4-RECVFROM:6666,ip-add-membership=224.1.0.1:192.168.10.2,fork \
EXEC:hostname
</div>
<p>
This command receives multicast packets addressed to 224.1.0.1 and forks a
child process for each. The child processes may each send one or more reply
packets back to the particular sender. 192.168.10.2 means the address of the
interface where multicasts should be received.
Run this command on a number of hosts, and they will all respond in
parallel.</p>
<p>Multicast client:</p>
<span class="shell">socat \
STDIO \
UDP4-DATAGRAM:224.1.0.1:6666,range=192.168.10.0/24
</span>
<p>
This process transfers data from stdin to the multicast address, and transfers
packets received from the local network to stdout. It does not matter in which
direction the first data is passed.
A packet from the network is accepted by the IP stack for our socket if:
<ul>
<li>it is an incoming UDP/IPv4 packet</li>
<li>its target port matches the local port assigned to the socket (random)</li>
<li>its target address matches one of the hosts local addresses or the any-host
multicast address</li>
</ul>
Of these packets, socat handles only those matching the following criteria:
<ul>
<li>the source address is within the given range</li>
<li>the source port is 6666</li>
</ul>
</p>
<h2>Example 2: Broadcast client and servers</h2>
<p>Broadcast server:</p>
<span class="shell">socat \
UDP4-RECVFROM:6666,broadcast,fork \
EXEC:hostname
</span>
<p>
This command receives packets addressed to a local broadcast address and forks
a child process for each. The child processes may each send one or more reply
packets back to the particular sender.
Run this command on a number of hosts, and they will all respond in
parallel.</p>
<p>Broadcast client:</p>
<span class="shell">socat \
STDIO \
UDP4-DATAGRAM:192.168.10.255:6666,broadcast,range=192.168.10.0/24
</span>
<p>
This process transfers data from stdin to the broadcast address, and transfers
packets received from the local network to stdout. It does not matter in which
direction the first data is passed.
A packet from the network is accepted by the IP stack for our socket if:
<ul>
<li>it is an incoming UDP/IPv4 packet</li>
<li>its target port matches the local port assigned to the socket (6666)</li>
<li>its target address matches one of the hosts local addresses or the any-host
multicast address, or a local broadcast address</li>
</ul>
Of these packets, socat handles only those matching the following criteria:
<ul>
<li>the source address is within the given range</li>
<li>the source port is 6666</li>
</ul>
</p>
<p>The <tt>broadcast</tt> option is only required for sending or receiving
local broadcasts.</p>
<h2>Example 3: Multicast peers</h2>
<p>It is possible to combine multicast sender and receiver in one socat
address. This allows to start processes on different hosts on the local network
that will communicate symmetrically, so each process can send messages that are
received by all the other ones.</p>
<span class="shell">socat \
STDIO \
UDP4-DATAGRAM:224.1.0.1:6666,bind=:6666,range=192.168.10.0/24,ip-add-membership=224.1.0.1:192.168.10.2
</span>
<p>
This command is valid for host 192.168.10.2; adapt this address to the
particular interface addresses of the hosts.
</p>
<p>
Starting this process opens a socket on port 6666 that will receive packets
directed to multicast address 224.1.0.1. Only packets with matching source
address and source port 6666 will be handled though. When this process sends
data to the network the packets will be addressed to 224.1.0.1:6666 and have a
source address of 192.168.10.2:6666, matching the accept criteria of the peers
on the local network.
</p>
<p>Note: this command receives the packets it just has sent; add option
<tt>ip-multicast-loop=0</tt> if this in undesired.</p>
<h2>Example 4: Broadcast peers</h2>
<p>Just as with multicast, it is possible to combine broadcast sender and
receiver in one socat address.</p>
<span class="shell">socat \
STDIO \
UDP4-DATAGRAM:255.255.255.255:6666,bind=:6666,range=192.168.10.0/24,broadcast
</span>
<p>
Starting this process opens a socket on port 6666 that will receive packets
directed to a local broadcast addresses. Only packets with matching source
address and source port 6666 will be handled though. When this process sends
data to the network the packets will be addressed to 255.255.255.255:6666 and
have a source address of 192.168.10.2:6666, matching the accept criteria of
the peers on the local network.
</p>
<p>Note: this command receives the packets it just has sent; there does not
seem to exist a simple way to prevent this.</p>
<h2>Troubleshooting</h2>
<p>
If you do not get an error message during operation, but the packets do not
reach the target processes, use <tt>tcpdump</tt> to see if the packets have the
correct source and destination addresses and ports, and if they leave and enter
the hosts as expected.
</p>
<p>
The following subsections discuss some typical sources of trouble.
</p>
<h3>IP filters</h3>
<p>
If you do not succeed in receiving multicast or broadcast packets, check if
iptables are activated on the receiving or sending host. They might be
configured to disallow this traffic.
</p>
<h3>Do not bind()</h3>
<p>
When using multicast communications, you should not bind the sockets to a
specific IP address. It seems that the (Linux) IP stack compares the
destination address with the bind address, not taking care of the multicast
property of the incoming packet.
</p>
<h3>Routing</h3>
<p>
When you receive an error like:</p>
<span class="error">
... E sendto(3, 0x80c2e44, 4, 0, AF=2 224.1.0.1:6666, 16): Network is unreachable
</span>
<p>you have a routing problem. The (Linux) IP stack seems to handle multicast
addresses just like unicast addresses when determining their route (interface
and gateway), i.e. the routing table needs an entry that somehow matches the
target address. </p>
<p>
For the same reason, multicast packets will probably leave your host on the
interface with the default route if it is specified.</p>
<p>
Set a multicast/broadcast route with the following command (Linux):</p>
<span class="shell">route add -net 224.0.0.0/3 gw 192.168.10.2
</span>
<a name="ALLSYSTEMS"></a>
<h3>ALL-SYSTEMS multicast address</h3>
<p>
<tt>224.0.0.1</tt> is the all-systems multicast address: all
datagram sockets appear to be automatically member of this group on all
interfaces. This membership cannot be dropped on Linux (you need iptables to
filter packets).
</p>
<h2>(In)Security</h2>
<p>When you use the above examples you should understand that all datagram
sockets without exception accept all packets that are directly addressed to
them;
the multi- and broadcast receiving features are just extensions to this
functionality. socat currently has no means to handle incoming packets
differently whether they are addressed to unicast, multicast, or broadcast
addresses. However, for EXEC'd scripts socat can provide this info in
environment variables.
</p>
<p>Authentication or encryption are not available.</p>
<p>It is very easy to fake the source address of UDP (or raw IP) packets. You
should understand whether your network is protected from address spoofing
attacks.</p>
<p>Broadcast and multicast traffic can trivially be received by <em>any</em>
host on the local network.</p>
<h2>History</h2>
Starting with version 1.5.0, socat provides a set of address types that
allow various operations on datagram oriented sockets:
<dl>
<dt>SENDTO</dt><dd>send packets to a remote socket and receive packet from this
remote socket only</dd>
<dt>RECV</dt><dd>receive all packets that arrive on the local socket, but do
not reply</dd>
<dt>RECVFROM</dt><dd>receive all packets that arrive on the local socket, and
reply using child processes</dd>
</dl>
<p>
These modes already enable several different client/server oriented operations.
Moreover, the SENDTO addresses can send to multicast and broadcast addresses
(the latter requires the <tt>broadcast</tt> option though). RECV and RECVFROM
also would accept packets addressed to a local broadcast address (with option
<tt>broadcast</tt>) or the all-systems multicast address.
</p>
<p>
These address types had, however, two major caveats:
<ul>
<li>Missing control of multicast group membership in the RECV and RECVFROM
addresses</li>
<li>The SENDTO address would never accept a reply to a broadcast or multicast
addressed packet because the source address of incoming replies would not match
the target address of the sent packet.
</ul>
</p>
<h3>New Features in socat 1.6.0</h3>
<p>
socat version 1.6.0 addresses these problems and provides a new more generic
datagram address type (*-DATAGRAM) and the new address option IP-ADD-MEMBERSHIP.
</p>
<p>
Please note that the new features could not be successfully tested on IPv6;
these sections thus apply to IPv4 only.
</p>
<h3>New Features in socat 1.7.0</h3>
<p>
socat version 1.7.0 helps to find more information about incoming packets in
environment variables that can be used in scripts or programs invoked by
socat. The option <tt>ip-pktinfo</tt> (on non-BSD systems)
or <tt>ip-recvdstaddr</tt> (on BSD systems) is required to get basic
information about incoming packets.
</p>
<p>
Example: Start a receiver of the following form (tried on Linux):
</p>
<span class="shell">socat -u \
UDP-RECVFROM:8888,reuseaddr,ip-add-membership=224.1.0.1:192.168.10.2,ip-pktinfo,fork \
SYSTEM:export
</span>
<p>
Then send a multicast packet from the client:
</p>
<span class="shell">echo | \
socat -u \
STDIO \
UDP-DATAGRAM:224.1.0.1:8888
</span>
<p>
On the server the following text should appear (only interesting lines shown):
</p>
<pre>
export SOCAT_IP_DSTADDR="224.1.0.1"
export SOCAT_IP_IF="eth0"
export SOCAT_IP_LOCADDR="192.168.10.2"
export SOCAT_PEERADDR="192.168.10.1"
export SOCAT_PEERPORT="41159"
</pre>
<p>
<tt>SOCAT_IP_IF</tt> shows the interface where the packet entered the server;
<tt>SOCAT_IP_LOCADDR</tt> shows the IP address of this interface;
<tt>SOCAT_IP_DSTADDR</tt> shows the target address of the packet;
<tt>SOCAT_PEERADDR</tt> and <tt>SOCAT_PEERPORT</tt> are the client socket
values.
</p>
<h2>More info about socat datagrams</h2>
<h3>Links regarding this tutorial</h3>
<a href="socat.html#ADDRESS_UDP4_DATAGRAM">address UDP4-DATAGRAM</a><br>
<a href="socat.html#ADDRESS_UDP4_RECVFROM">address UDP4-RECVFROM</a><br>
<a href="socat.html#OPTION_RANGE">option range</a><br>
<a href="socat.html#OPTION_SO_BROADCAST">option broadcast</a><br>
<a href="socat.html#OPTION_IP_ADD_MEMBERSHIP">option ip-add-membership</a><br>
<a href="socat.html#OPTION_FORK">option fork</a><br>
<a href="socat.html#OPTION_BIND">option bind</a><br>
<h3>Other datagram addresses</h3>
<a href="socat.html#ADDRESS_UDP4_RECV">address UDP4-RECV</a>: pure datagram receiver<br>
<a href="socat.html#ADDRESS_UDP4_SENDTO">address UDP4-SENDTO</a>: communicate
with one peer address<br>
<a href="socat.html#ADDRESS_UDP4_LISTEN">address UDP4-LISTEN</a>: pseudo stream server<br>
<a href="socat.html#ADDRESS_UDP4_CONNECT">address UDP4-CONNECT</a>: pseudo stream client<br>
<h3>Related socat option groups</h3>
<a href="socat.html#GROUP_IP">IP options</a><br>
<a href="socat.html#GROUP_SOCKET">socket options</a><br>
<a href="socat.html#GROUP_FD">file descriptor options</a><br>
<a href="socat.html#GROUP_RANGE">range options</a><br>
<a href="socat.html#GROUP_CHILD">child process options</a><br>
<h2>References</h2>
<a href="http://www.dest-unreach.org/socat">socat home page</a><br>
<a href="socat.html">socat man page</a><br>
<a href="http://en.wikipedia.org/wiki/Multicast">multicasting on Wikipedia</a><br>
<a href="http://en.wikipedia.org/wiki/Broadcast_address">broadcasting on Wikipedia</a><br>
<p>
<small>This document was last modified in May 2009.</small><br>
<small>Copyright: Gerhard Rieger 2007-2009</small><br>
<small>License: <a href="http://www.fsf.org/licensing/licenses/fdl.html">GNU Free Documentation License (FDL)</a></small>
</p>
</body>
</html>

View File

@@ -0,0 +1,199 @@
<!-- $Revision: 1.1 $ $Date: 2007/03/06 20:54:43 $ -->
<html><head>
<title>Securing Traffic Between two Socat Instances Using SSL</title>
<link rel="stylesheet" type="text/css" href="dest-unreach.css">
</head>
<body>
<h1>Securing Traffic Between two Socat Instances Using SSL</h1>
<h2>Introduction</h2>
<p>
When you want to connect two socat processes running on different machines and
feel that you need to protect the connection against unauthorized access,
sniffing, data manipulation etc., you might want to encrypt the communications.
</p>
<p>
For this purpose socat integrates the OpenSSL library and provides SSL client
and server features.
</p>
<p>
SSL is a complex protocol that provides much more features than required for
protecting a single connection; in this document we present only a simple
scenario that provides just the basic security requirements.
</p>
<!-- discussion -->
<h2>Configuring OpenSSL in socat</h2>
<p>
This section shows how the SSL addresses can be configured in socat.
In this docu we only use self signed certificates for the sake of simplicity.
</p>
<p>We assume that the server host is called <tt>server.domain.org</tt> and the
server process uses port 4433. To keep it simple, we use a very simple server
funtionality that just echos data (<tt>echo</tt>), and <tt>stdio</tt> on the
client.</p>
<h3>Generate a server certificate</h3>
<p>Perform the following steps on a trusted host where OpenSSL is
installed. It might as well be the client or server host themselves.</p>
<p>Prepare a basename for the files related to the server certificate:</p>
<span class="shell">FILENAME=server</span>
<p>Generate a public/private key pair:</p>
<span class="shell">openssl genrsa -out $FILENAME.key 2048</span>
<p>Generate a self signed certificate:</p>
<span class="shell">openssl req -new -key $FILENAME.key -x509 -days 3653 -out $FILENAME.crt</span>
<p>You will be prompted for your country code, name etc.; you may quit all prompts
with the ENTER key, except for the Common Name which must be exactly the name or IP address of the server that the client will use.</p>
<p>Generate the PEM file by just appending the key and certificate files:<p>
<span class="shell">cat $FILENAME.key $FILENAME.crt &gt;$FILENAME.pem</span>
<p>The files that contain the private key should be kept secret, thus adapt
their permissions:<p>
<span class="shell">chmod 600 $FILENAME.key $FILENAME.pem</span>
<p>Now bring the file <tt>server.pem</tt> to the SSL server, e.g. to directory
<tt>$HOME/etc/</tt>, using a secure channel like USB memory stick or SSH. Keep
tight permissions on the file even on the target host, and remove all other
instances of <tt>server.key</tt> and <tt>server.pem</tt>.
</p>
<p>Copy the trust certificate server.crt to the SSL client host, e.g. to directory
<tt>$HOME/etc/</tt>; a secure channel is not required here, and the permissions
are not critical.
</p>
<h3>Generate a client certificate</h3>
<p>First prepare a different basename for the files related to the client certificate:</p>
<span class="shell">FILENAME=client</span>
<p>Repeat the procedure for certificate generation described above. A special common name is not required.
Copy <tt>client.pem</tt> to the SSL client, and <tt>client.crt</tt> to the
server.</p>
<h3>OpenSSL Server</h3>
<p>Instead of using a tcp-listen (tcp-l) address, we use openssl-listen (ssl-l)
for the server, <tt>cert=...</tt> tells the program to the file containing its
ceritificate and private key, and <tt>cafile=...</tt> points to the file
containing the certificate of the peer; we trust clients only if they can proof
that they have the related private key (OpenSSL handles this for us):<p>
<span class="shell">socat \
OPENSSL-LISTEN:4433,reuseaddr,cert=$HOME/etc/server.pem,cafile=$HOME/etc/client.crt \
PIPE</span>
<p>After starting this command, socat should be listening on port 4433, but
will require client authentication.</p>
<h3>OpenSSL Client</h3>
<p>Substitute your <tt>tcp-connect</tt> or <tt>tcp</tt> address keyword with
<tt>openssl-connect</tt> or just <tt>ssl</tt> and here too add the
<tt>cert</tt> and <tt>cafile</tt> options:<p>
<span class="shell">socat STDIO \
OPENSSL-CONNECT:server.domain.org:4433,cert=$HOME/etc/client.pem,cafile=$HOME/etc/server.crt</span>
<p>This command should establish a secured connection to the server
process.</p>
<h3>TCP/IP version 6</h3>
<p>If the communication is to go over IPv6, the above described commands have
to be adapted; <tt>ip6name.domain.org</tt> is assumed to resolve to the IPv6
address of the server:</p>
<p>Server:</p>
<span class="shell">socat \
OPENSSL-LISTEN:4433,<b style="color:yellow">pf=ip6</b>,reuseaddr,cert=$HOME/etc/server.pem,cafile=$HOME/etc/client.crt \
PIPE</span>
<p>Client:</p>
<span class="shell">socat STDIO \
OPENSSL-CONNECT:<b style="color:yellow">ip6name</b>.domain.org:4433,cert=$HOME/etc/client.pem,cafile=$HOME/etc/server.crt</span>
<h2>Troubleshooting</h2>
<h3>Test OpenSSL Integration</h3>
<p>
If you get error messages like this:</p>
<span class="error">... E unknown device/address "OPENSSL-LISTEN"</span>
<p>your socat executable probably does not have the OpenSSL library linked in.
Check socat's compile time configuration with the following command:</p>
<span class="shell">socat -V |grep SSL</span>
<p>Positive output:
<tt>#define WITH_OPENSSL 1</tt><br>
Negative output:
<tt>#undef WITH_OPENSSL</tt><br>
</p>
<p>
In the latter case, make sure you have OpenSSL and its development package
(include files) installed, and check the run of the configure script.
</p>
<h2>History</h2>
<p>
A first OpenSSL client was implemented in socat 1.2.0; it did not support
client certificates and could not verify server certificates. It was rather
considered as a tool for probing typical SSL secured Internet services.
</p>
<p>
From version 1.4.0 on, socat provided experimental support for SSL client and
SSL server, implemented using the OpenSSL libraries. Only TCP/IPv4 transport
was supported. With both SSL client and server, trust certificates for checking
the peers authentication, and certificates for authentication could be
specified. This allowed for non interactive secure connection establishing.
The features were considered experimental; like most Internet sites, socat
server did not require the client to present a certificate per default, but the
client required a server certificate.
</p>
<p>
DSA certificate support is implemented since version 1.4.2.
</p>
<p>
Socat version 1.5.0 extended SSL to TCP/IPv6 transports.
</p>
<p>
With socat version 1.6.0, the SSL server per default requires the client to
present a trusted certificate. socat's OpenSSL implementation still does not
check the contents of a certificate like host name or host address.
</p>
<p>
Socat 1.7.3.0 introduces check of servers commonname by the client, and optionally check of clients commonname by the server.
</p>
<p>This document was last modified in Oct. 2023.</p>
<h2>More info about socat OpenSSL</h2>
<h3>Links regarding this tutorial</h3>
<a href="socat.html#ADDRESS_OPENSSL_CONNECT">address openssl-connect</a><br>
<a href="socat.html#ADDRESS_OPENSSL_LISTEN">address openssl-listen</a><br>
<a href="socat.html#OPTION_OPENSSL_CERTIFICATE">option cert</a><br>
<a href="socat.html#OPTION_OPENSSL_CAFILE">option cafile</a><br>
<h3>More socat options for OpenSSL addresses</h3>
<a href="socat.html#GROUP_OPENSSL">OpenSSL options</a><br>
<a href="socat.html#GROUP_TCP">TCP options</a><br>
<a href="socat.html#GROUP_IP">IP options</a><br>
<a href="socat.html#GROUP_SOCKET">socket options</a><br>
<a href="socat.html#GROUP_FD">file descriptor options</a><br>
<a href="socat.html#GROUP_RETRY">retry options</a><br>
<p>For openssl-listen only:</p>
<a href="socat.html#GROUP_LISTEN">listen options</a><br>
<a href="socat.html#GROUP_CHILD">child options</a><br>
<a href="socat.html#GROUP_RANGE">range options</a><br>
<h2>References</h2>
<a href="http://www.dest-unreach.org/socat">socat home page</a><br>
<a href="socat.html">socat man page</a><br>
<a href="http://www.openssl.org/">OpenSSL home page</a><br>
<a href="http://www.stunnel.org/">stunnel home page</a><br>
<a href="http://en.wikipedia.org/wiki/Secure_Sockets_Layer">secure sockets layer on Wikipedia</a><br>
<p>
<small>Copyright: Gerhard Rieger 2007</small><br>
<small>License: <a href="http://www.fsf.org/licensing/licenses/fdl.html">GNU Free Documentation License (FDL)</a></small>
</p>
</body>
</html>

175
doc/socat-tun.html Normal file
View File

@@ -0,0 +1,175 @@
<!-- source: doc/socat-tun.html -->
<html><head>
<title>Building TUN based virtual networks with socat</title>
<link rel="stylesheet" type="text/css" href="dest-unreach.css">
</head>
<body>
<h1>Building TUN based virtual networks with socat</h1>
<h2>Introduction</h2>
<p>
Some operating systems allow the generation of virtual network interfaces that
do not connect to a wire but to a process that simulates the network. Often
these devices are called TUN or TAP.
</p>
<p>
socat provides an address type that creates a TUN device on Linux; the other
socat address can be any type; it transfers the "wire" data as desired.
</p>
<p>
This document shows how a simple virtual network can be created between
two hosts that may be far (many network hops) apart. On both hosts a socat
instance is started that connects to the other host using TCP and creates a TUN
device. See <a href="socat-openssltunnel.html">socat-openssltunnel.html</a> for
a guide on securing the connection using SSL.
</p>
<p>
The following IP addresses are used in the example; replace them in the
following commands with the requirements of your situation:</p>
<table border="1">
<tr><th>host</th><th>address</th><th>mask</th></tr>
<tr><td>physical "server" address</td><td>1.2.3.4</td><td>n/a</td></tr>
<tr><td>physical "client" address</td><td>n/a</td><td>n/a</td></tr>
<tr><td>TUN on "server"</td><td>192.168.255.1</td><td>255.255.255.0</td></tr>
<tr><td>TUN on "client"</td><td>192.168.255.2</td><td>255.255.255.0</td></tr>
</table>
<p>The TCP connection uses port 11443.</p>
<p>On "default" Linux installations, creating TUN/TAP devices might require
root privilege.</p>
<!-- discussion -->
<h2>Generate TUN devices with socat</h2>
<p>In this section two instances of socat are used to generate TUN devices on
different hosts and connect the "wire" sides, providing a simple virtual
network.
</p>
<p>
We distinguish server and client only with respect to the connection between
the two socat instances; the TUN interfaces both have the same quality.
</p>
<h3>TUN Server</h3>
<span class="shell">socat -d -d \
UDP-LISTEN:11443 \
TUN:192.168.255.1/24,up
</span>
<p>After starting this command, socat will wait for a connection and then
create a TUN pseudo network device with address 192.168.255.1; the bit number
specifies the mask of the network that is pretended to be connected on this
interface.</p>
<h3>TUN Client</h3>
<span class="shell">socat \
UDP:1.2.3.4:11443 \
TUN:192.168.255.2/24,up
</span>
<p>This command should establish a connection to the server and create the TUN
device on the client.</p>
<h3>Seeing it work</h3>
<p>
After successful connection both TUN interfaces should be active and transfer
data between each other using the TCP connection. Try this by pinging
192.168.255.1 from the client and 192.168.255.2 from the server.
</p>
<h3>TCP/IP version 6</h3>
<p>IPv6 as transport should work just like any TCP/IPv6 connection.</p>
<p>Creation of an IPv6 virtual interface is not directly possible, but you can
generate an IPv4 interface as described above, and add IPv6 addresses using
the <tt>ifconfig</tt> command.
<h2>Troubleshooting</h2>
<h3>Test TUN integration</h3>
<p>
If you get error messages like this:</p>
<span class="error">... E unknown device/address "tun"</span>
<p>your socat executable probably does not provide TUN/TAP support. Potential
reasons: you are not on Linux or are using an older version of socat.
</p>
<h3>Missing kernel support</h3>
<p>An error message like:</p>
<span class="error">... E open("/dev/net/tun", 02, 0666): No such file or directory</span>
<p>indicates that your kernel either needs to load the tun module or does not
have TUN/TAP support compiled in. Try to load the module:</p>
<span class="shell">modprobe tun</span>
<p>and check
for /dev/net/tun. If that does not succeed you need to
rebuild your kernel with the appropriate configuration (probably under
<b>Device driver / Network device support / Network device / Universal TUN/TAP</b>).
</p>
<h3>TUN cloning device permissions</h3>
<p>An error message like:</p>
<span class="error">... E open("/dev/net/tun", 02, 0666): Permission denied</span>
<p>indicates that you do not have permission to read or write the TUN cloning
device. Check its permission and ownership.</p>
<h3>Interface down</h3>
<p>If no error occurs but the pings do not work check if the network devices
have been created:</p>
<span class="shell">ifconfig tun0</span>
<p>The output should look like:</p>
<pre>
tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:192.168.255.1 P-t-P:192.168.255.1 Mask:255.255.255.0
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:500
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
</pre>
<p>Check the "UP" keyword; you forget the "up" option in the socat command if
it is missing.<p>
<p>Check if the correct IP address and network mask are displayed.</p>
<h3>Routing</h3>
<p></p>
<span class="shell">netstat -an |fgrep 192.168.255</span>
<p>The output should look like:</p>
<pre>
192.168.255.0 0.0.0.0 255.255.255.0 U 0 0 0 tun0
</pre>
<h3>Other problems</h3>
<p>Another reason for failure might be iptables.</p>
<p>Run socat with options <tt>-d -d -d</tt>, this will show every data transfer
between the two processes. Each ping probe should cause a forth and a back
transfer.<p>
<h2>History</h2>
<p>
Linux TUN/TAP support was added to socat in version 1.6.0.</p>
<p>This document was last modified in February 2010.</p>
<h2>More info about socat TUN/TAP support</h2>
<h3>Links regarding this tutorial</h3>
<a href="socat.html#ADDRESS_TUN">socat address tun</a><br>
<h3>socat options for TUN/TAP addresses</h3>
<a href="socat.html#GROUP_TUN">TUN/TAP options</a><br>
<h2>References</h2>
<a href="http://www.dest-unreach.org/socat">socat home page</a><br>
<a href="socat.html">socat man page</a><br>
<a href="http://openvpn.net/">OpenVPN home page</a><br>
<a href="http://en.wikipedia.org/wiki/TUN/TAP">TUN/TAP on Wikipedia</a><br>
<p>
<small>Copyright: Gerhard Rieger 2007-2010</small><br>
<small>License: <a href="http://www.fsf.org/licensing/licenses/fdl.html">GNU Free Documentation License (FDL)</a></small>
</p>
</body>
</html>

4960
doc/socat.1 Normal file

File diff suppressed because it is too large Load Diff

4803
doc/socat.html Normal file

File diff suppressed because it is too large Load Diff

4810
doc/socat.yo Normal file

File diff suppressed because it is too large Load Diff

564
error.c Normal file
View File

@@ -0,0 +1,564 @@
/* source: error.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* the logging subsystem */
#include "config.h"
#include "sysincludes.h"
#include "mytypes.h"
#include "compat.h"
#include "utils.h"
#include "vsnprintf_r.h"
#include "snprinterr.h"
#include "error.h"
#include "sycls.h"
/* translate MSG level to SYSLOG level */
int syslevel[] = {
LOG_DEBUG,
LOG_INFO,
LOG_NOTICE,
LOG_WARNING,
LOG_ERR,
LOG_CRIT };
struct diag_opts {
const char *progname;
int msglevel;
int shutup; /* decrease msglevel by this value */
int exitlevel;
int syslog;
FILE *logfile;
int logfacility;
bool micros;
int exitstatus; /* pass signal number to error exit */
bool withhostname; /* in custom logs add hostname */
char *hostname;
bool signalsafe;
} ;
static void _diag_exit(int status);
struct diag_opts diagopts =
{ NULL, E_WARN, 0, E_ERROR, 0, NULL, LOG_DAEMON, false, 0, false, NULL, true } ;
static void msg2(
#if HAVE_CLOCK_GETTIME
struct timespec *now,
#elif HAVE_PROTOTYPE_LIB_gettimeofday
struct timeval *now,
#else
time_t *now,
#endif
int level, int exitcode, int handler, const char *text);
static void _msg(int level, const char *buff, const char *syslp);
volatile sig_atomic_t diag_in_handler; /* !=0 indicates to msg() that in signal handler */
volatile sig_atomic_t diag_immediate_msg; /* !=0 prints messages even from within signal handler instead of deferring them */
volatile sig_atomic_t diag_immediate_exit; /* !=0 calls exit() from diag_exit() even when in signal handler. For system() */
static struct wordent facilitynames[] = {
{"auth", (void *)LOG_AUTH},
#ifdef LOG_AUTHPRIV
{"authpriv", (void *)LOG_AUTHPRIV},
#endif
#ifdef LOG_CONSOLE
{"console", (void *)LOG_CONSOLE},
#endif
{"cron", (void *)LOG_CRON},
{"daemon", (void *)LOG_DAEMON},
#ifdef LOG_FTP
{"ftp", (void *)LOG_FTP},
#endif
{"kern", (void *)LOG_KERN},
{"local0", (void *)LOG_LOCAL0},
{"local1", (void *)LOG_LOCAL1},
{"local2", (void *)LOG_LOCAL2},
{"local3", (void *)LOG_LOCAL3},
{"local4", (void *)LOG_LOCAL4},
{"local5", (void *)LOG_LOCAL5},
{"local6", (void *)LOG_LOCAL6},
{"local7", (void *)LOG_LOCAL7},
{"lpr", (void *)LOG_LPR},
{"mail", (void *)LOG_MAIL},
{"news", (void *)LOG_NEWS},
#ifdef LOG_SECURITY
{"security", (void *)LOG_SECURITY},
#endif
{"syslog", (void *)LOG_SYSLOG},
{"user", (void *)LOG_USER},
{"uucp", (void *)LOG_UUCP}
} ;
/* serialize message for sending from signal handlers */
struct sermsg {
int severity;
#if HAVE_CLOCK_GETTIME
struct timespec ts;
#else
struct timeval tv;
#endif
} ;
static int diaginitialized;
static int diag_sock_send = -1;
static int diag_sock_recv = -1;
static volatile sig_atomic_t diag_msg_avail = 0; /* !=0: messages from within signal handler may be waiting */
static int diag_sock_pair(void) {
int handlersocks[2];
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, handlersocks) < 0) {
diag_sock_send = -1;
diag_sock_recv = -1;
return -1;
}
fcntl(handlersocks[0], F_SETFD, FD_CLOEXEC);
fcntl(handlersocks[1], F_SETFD, FD_CLOEXEC);
diag_sock_send = handlersocks[1];
diag_sock_recv = handlersocks[0];
#if !defined(MSG_DONTWAIT)
fcntl(diag_sock_send, F_SETFL, O_NONBLOCK);
fcntl(diag_sock_recv, F_SETFL, O_NONBLOCK);
#endif
fcntl(diag_sock_send, F_SETFD, FD_CLOEXEC);
fcntl(diag_sock_recv, F_SETFD, FD_CLOEXEC);
return 0;
}
static int diag_init(void) {
if (diaginitialized) {
return 0;
}
diaginitialized = 1;
/* gcc with GNU libc refuses to set this in the initializer */
diagopts.logfile = stderr;
if (diagopts.signalsafe) {
if (diag_sock_pair() < 0) {
return -1;
}
}
return 0;
}
#define DIAG_INIT ((void)(diaginitialized || diag_init()))
void diag_set(char what, const char *arg) {
switch (what) {
case 'I':
if (diagopts.signalsafe) {
if (diag_sock_send >= 0) { Close(diag_sock_send); diag_sock_send = -1; }
if (diag_sock_recv >= 0) { Close(diag_sock_recv); diag_sock_recv = -1; }
}
diagopts.signalsafe = false;
return;
}
DIAG_INIT;
switch (what) {
const struct wordent *keywd;
case 'y': diagopts.syslog = true;
if (arg && arg[0]) {
if ((keywd =
keyw(facilitynames, arg,
sizeof(facilitynames)/sizeof(struct wordent))) == NULL) {
Error1("unknown syslog facility \"%s\"", arg);
} else {
diagopts.logfacility = (int)(size_t)keywd->desc;
}
}
openlog(diagopts.progname, LOG_PID, diagopts.logfacility);
if (diagopts.logfile != NULL && diagopts.logfile != stderr) {
fclose(diagopts.logfile);
}
diagopts.logfile = NULL;
break;
case 'f':
if (diagopts.logfile != NULL && diagopts.logfile != stderr) {
fclose(diagopts.logfile);
}
if ((diagopts.logfile = fopen(arg, "a")) == NULL) {
Error2("cannot open log file \"%s\": %s", arg, strerror(errno));
}
break;
case 's':
if (diagopts.logfile != NULL && diagopts.logfile != stderr) {
fclose(diagopts.logfile);
}
diagopts.logfile = stderr; break; /* logging to stderr is default */
case 'p': diagopts.progname = arg;
openlog(diagopts.progname, LOG_PID, diagopts.logfacility);
break;
case 'u': diagopts.micros = true; break;
default: msg(E_ERROR, "unknown diagnostic option %c", what);
}
}
void diag_set_int(char what, int arg) {
DIAG_INIT;
switch (what) {
case 'D': diagopts.msglevel = arg; break;
case 'e': diagopts.exitlevel = arg; break;
case 'x': diagopts.exitstatus = arg; break;
case 'd':
diagopts.msglevel = arg;
break;
case 'h': diagopts.withhostname = arg;
if ((diagopts.hostname = getenv("HOSTNAME")) == NULL) {
struct utsname ubuf;
uname(&ubuf);
diagopts.hostname = strdup(ubuf.nodename);
}
break;
case 'u':
diagopts.shutup = arg;
diagopts.exitlevel -= arg;
break;
default: msg(E_ERROR, "unknown diagnostic option %c", what);
}
}
int diag_get_int(char what) {
DIAG_INIT;
switch (what) {
case 'y': return diagopts.syslog;
case 's': return diagopts.logfile == stderr;
case 'd': case 'D': return diagopts.msglevel;
case 'e': return diagopts.exitlevel;
}
return -1;
}
const char *diag_get_string(char what) {
DIAG_INIT;
switch (what) {
case 'p': return diagopts.progname;
}
return NULL;
}
/* make sure that the diag_sock fds do not have this num */
int diag_reserve_fd(int fd) {
DIAG_INIT;
if (diag_sock_send == fd) {
diag_sock_send = Dup(fd);
Close(fd);
}
if (diag_sock_recv == fd) {
diag_sock_recv = Dup(fd);
Close(fd);
}
return 0;
}
/* call this after a fork() from the child process to separate master/parent
sockets from child sockets */
int diag_fork() {
Close(diag_sock_send);
Close(diag_sock_recv);
if (diagopts.signalsafe) {
return diag_sock_pair();
}
return 0;
}
/* Linux and AIX syslog format:
Oct 4 17:10:37 hostname socat[52798]: D signal(13, 1)
*/
void msg(int level, const char *format, ...) {
struct diag_dgram diag_dgram;
va_list ap;
/* does not perform a system call if nothing todo, thanks diag_msg_avail */
diag_dgram._errno = errno; /* keep for passing from signal handler to sock.
reason is that strerror is definitely not
async-signal-safe */
DIAG_INIT;
/* in normal program flow (not in signal handler) */
/* first flush the queue of datagrams from the socket */
if (diag_msg_avail && !diag_in_handler) {
diag_flush();
}
level -= diagopts.shutup; /* decrease severity of messages? */
/* Just ignore this call when level too low for both logging and exiting */
if (level < diagopts.msglevel && level < diagopts.exitlevel)
return;
va_start(ap, format);
/* we do only a minimum in the outer parts which may run in a signal handler
these are: get actual time, level, serialized message and write them to socket
*/
diag_dgram.op = DIAG_OP_MSG;
#if HAVE_CLOCK_GETTIME
clock_gettime(CLOCK_REALTIME, &diag_dgram.now);
#elif HAVE_PROTOTYPE_LIB_gettimeofday
gettimeofday(&diag_dgram.now, NULL);
#else
diag_dgram.now = time(NULL);
#endif
diag_dgram.level = level;
diag_dgram.exitcode = diagopts.exitstatus;
if (level >= diagopts.msglevel)
vsnprintf_r(diag_dgram.text, sizeof(diag_dgram.text), format, ap);
else
diag_dgram.text[0] = '\0';
if (diagopts.signalsafe && diag_in_handler && !diag_immediate_msg) {
send(diag_sock_send, &diag_dgram, sizeof(diag_dgram)-TEXTLEN + strlen(diag_dgram.text)+1,
0 /* for canonical reasons */
#ifdef MSG_DONTWAIT
|MSG_DONTWAIT
#endif
#ifdef MSG_NOSIGNAL
|MSG_NOSIGNAL
#endif
);
diag_msg_avail = 1;
va_end(ap);
return;
}
msg2(&diag_dgram.now, diag_dgram.level, diagopts.exitstatus, 0, diag_dgram.text);
va_end(ap); return;
}
void msg2(
#if HAVE_CLOCK_GETTIME
struct timespec *now,
#elif HAVE_PROTOTYPE_LIB_gettimeofday
struct timeval *now,
#else
time_t *now,
#endif
int level, /* E_INFO... */
int exitcode, /* on exit use this exit code */
int handler, /* message comes from signal handler */
const char *text) {
time_t epoch;
unsigned long micros;
#if HAVE_STRFTIME
struct tm struct_tm;
#endif
#define MSGLEN 512
char buff[MSGLEN+2], *bufp = buff, *syslp = NULL;
size_t bytes;
if (text[0] != '\0') {
#if HAVE_CLOCK_GETTIME
epoch = now->tv_sec;
#elif HAVE_PROTOTYPE_LIB_gettimeofday
epoch = now->tv_sec;
#else
epoch = *now;
#endif
/*! consider caching instead of recalculating many times per second */
#if HAVE_STRFTIME
bytes = strftime(bufp, 20, "%Y/%m/%d %H:%M:%S", localtime_r(&epoch, &struct_tm));
#else
bytes = snprintf(bufp, 11, F_time, epoch);
#endif
bufp += bytes;
*bufp = '\0';
if (diagopts.micros) {
#if HAVE_CLOCK_GETTIME
micros = now->tv_nsec/1000;
#elif HAVE_PROTOTYPE_LIB_gettimeofday
micros = now->tv_usec;
#else
micros = 0;
#endif
bufp += sprintf(bufp, ".%06lu ", micros);
} else {
*bufp++ = ' ';
*bufp = '\0';
}
if (diagopts.withhostname) {
bytes = snprintf(bufp, MSGLEN-(bufp-buff), "%s ", diagopts.hostname);
if (bytes >= MSGLEN-(bufp-buff))
bytes = MSGLEN-(bufp-buff)-1;
bufp += bytes;
}
bytes = snprintf(bufp, MSGLEN-(bufp-buff), "%s["F_pid"] ", diagopts.progname, getpid());
if (bytes >= MSGLEN-(bufp-buff))
bytes = MSGLEN-(bufp-buff)-1;
bufp += bytes;
syslp = bufp; /* syslog prefixes with time etc.itself */
if (bufp < buff+MSGLEN)
*bufp++ = "DINWEF"[level];
#if 0 /* only for debugging socat */
if (handler) bufp[-1] = tolower((unsigned char)bufp[-1]); /* for debugging, low chars indicate messages from signal handlers */
#endif
if (bufp < buff+MSGLEN)
*bufp++ = ' ';
strncpy(bufp, text, MSGLEN-(bufp-buff));
bufp = strchr(bufp, '\0');
strcpy(bufp, "\n");
_msg(level, buff, syslp);
}
if (level >= diagopts.exitlevel) {
if (E_NOTICE >= diagopts.msglevel && text[0] != '\0') {
if ((syslp - buff) + 16 > MSGLEN+1)
syslp = buff + MSGLEN - 15;
snprintf_r(syslp, 16, "N exit(%d)\n", exitcode?exitcode:(diagopts.exitstatus?diagopts.exitstatus:1));
_msg(E_NOTICE, buff, syslp);
}
exit(exitcode?exitcode:(diagopts.exitstatus?diagopts.exitstatus:1));
}
}
static void _msg(int level, const char *buff, const char *syslp) {
if (diagopts.syslog) {
/* prevent format string attacks (thanks to CoKi) */
syslog(syslevel[level], "%s", syslp);
}
if (diagopts.logfile) {
fputs(buff, diagopts.logfile); fflush(diagopts.logfile);
}
}
/* handle the messages in the queue */
void diag_flush(void) {
struct diag_dgram recv_dgram;
char exitmsg[20];
if (diag_msg_avail == 0) {
return;
}
diag_msg_avail = 0;
if (!diagopts.signalsafe) {
return;
}
while (recv(diag_sock_recv, &recv_dgram, sizeof(recv_dgram)-1,
0 /* for canonical reasons */
#ifdef MSG_DONTWAIT
|MSG_DONTWAIT
#endif
) > 0) {
recv_dgram.text[TEXTLEN-1] = '\0';
switch (recv_dgram.op) {
case DIAG_OP_EXIT:
/* we want the actual time, not when this dgram was sent */
#if HAVE_CLOCK_GETTIME
clock_gettime(CLOCK_REALTIME, &recv_dgram.now);
#elif HAVE_PROTOTYPE_LIB_gettimeofday
gettimeofday(&recv_dgram.now, NULL);
#else
recv_dgram.now = time(NULL);
#endif
if (E_NOTICE >= diagopts.msglevel) {
snprintf_r(exitmsg, sizeof(exitmsg), "exit(%d)", recv_dgram.exitcode?recv_dgram.exitcode:1);
msg2(&recv_dgram.now, E_NOTICE, recv_dgram.exitcode?recv_dgram.exitcode:1, 1, exitmsg);
}
exit(recv_dgram.exitcode?recv_dgram.exitcode:1);
case DIAG_OP_MSG:
if (recv_dgram._errno) {
/* there might be a %m control in the string (glibc compatible,
replace with strerror(...errno) ) */
char text[TEXTLEN];
errno = recv_dgram._errno;
snprinterr(text, TEXTLEN, recv_dgram.text);
msg2(&recv_dgram.now, recv_dgram.level, recv_dgram.exitcode, 1, text);
} else {
msg2(&recv_dgram.now, recv_dgram.level, recv_dgram.exitcode, 1, recv_dgram.text);
}
break;
}
}
}
/* use a new log output file descriptor that is dup'ed from the current one.
this is useful when socat logs to stderr but fd 2 should be redirected to
serve other purposes */
int diag_dup(void) {
int newfd;
DIAG_INIT;
if (diagopts.logfile == NULL) {
return -1;
}
newfd = dup(fileno(diagopts.logfile));
Fcntl_l(newfd, F_SETFD, FD_CLOEXEC);
if (diagopts.logfile != stderr) {
fclose(diagopts.logfile);
}
if (newfd >= 0) {
diagopts.logfile = fdopen(newfd, "w");
}
return newfd;
}
/* this function is kind of async-signal-safe exit(). When invoked from signal
handler it defers exit. */
void diag_exit(int status) {
struct diag_dgram diag_dgram;
if (diag_in_handler && !diag_immediate_exit) {
diag_dgram.op = DIAG_OP_EXIT;
diag_dgram.exitcode = status;
send(diag_sock_send, &diag_dgram, sizeof(diag_dgram)-TEXTLEN,
0 /* for canonical reasons */
#ifdef MSG_DONTWAIT
|MSG_DONTWAIT
#endif
#ifdef MSG_NOSIGNAL
|MSG_NOSIGNAL
#endif
);
diag_msg_avail = 1;
return;
}
_diag_exit(status);
}
static void _diag_exit(int status) {
Exit(status);
}
/* a function that appears to the application like select() but that also
monitors the diag socket diag_sock_recv and processes its messages.
Do not call from within a signal handler. */
int diag_select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout) {
int result;
fd_set save_readfds, save_writefds, save_exceptfds;
if (readfds) { memcpy(&save_readfds, readfds, sizeof(*readfds)); }
if (writefds) { memcpy(&save_writefds, writefds, sizeof(*writefds)); }
if (exceptfds) { memcpy(&save_exceptfds, exceptfds, sizeof(*exceptfds)); }
while (1) {
FD_SET(diag_sock_recv, readfds);
result = Select(nfds, readfds, writefds,
exceptfds, timeout);
if (!FD_ISSET(diag_sock_recv, readfds)) {
/* select terminated not due to diag_sock_recv, normalt continuation */
break;
}
diag_flush();
if (readfds) { memcpy(readfds, &save_readfds, sizeof(*readfds)); }
if (writefds) { memcpy(writefds, &save_writefds, sizeof(*writefds)); }
if (exceptfds) { memcpy(exceptfds, &save_exceptfds, sizeof(*exceptfds)); }
}
return result;
}

249
error.h Normal file
View File

@@ -0,0 +1,249 @@
/* source: error.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __error_h_included
#define __error_h_included 1
/* these must be defines because they are used by cpp! */
#define E_DEBUG 0 /* all, including trace */
#define E_INFO 1 /* all status changes etc. */
#define E_NOTICE 2 /* all interesting, e.g. for firewall relay */
#define E_WARN 3 /* all unusual */
#define E_ERROR 4 /* errors */
#define E_FATAL 5 /* emergency abort */
#define F_strerror "%m" /* a pseudo format, replaced by strerror(errno) */
/* here are the macros for diag invocation; use WITH_MSGLEVEL to specify the
lowest priority that is compiled into your program */
#ifndef WITH_MSGLEVEL
# define WITH_MSGLEVEL E_NOTICE
#endif
#if WITH_MSGLEVEL <= E_FATAL
#define Fatal(m) msg(E_FATAL,"%s",m)
#define Fatal1(m,a1) msg(E_FATAL,m,a1)
#define Fatal2(m,a1,a2) msg(E_FATAL,m,a1,a2)
#define Fatal3(m,a1,a2,a3) msg(E_FATAL,m,a1,a2,a3)
#define Fatal4(m,a1,a2,a3,a4) msg(E_FATAL,m,a1,a2,a3,a4)
#define Fatal5(m,a1,a2,a3,a4,a5) msg(E_FATAL,m,a1,a2,a3,a4,a5)
#define Fatal6(m,a1,a2,a3,a4,a5,a6) msg(E_FATAL,m,a1,a2,a3,a4,a5,a6)
#define Fatal7(m,a1,a2,a3,a4,a5,a6,a7) msg(E_FATAL,m,a1,a2,a3,a4,a5,a6,a7)
#else /* !(WITH_MSGLEVEL <= E_FATAL) */
#define Fatal(m)
#define Fatal1(m,a1)
#define Fatal2(m,a1,a2)
#define Fatal3(m,a1,a2,a3)
#define Fatal4(m,a1,a2,a3,a4)
#define Fatal5(m,a1,a2,a3,a4,a5)
#define Fatal6(m,a1,a2,a3,a4,a5,a6)
#define Fatal7(m,a1,a2,a3,a4,a5,a6,a7)
#endif /* !(WITH_MSGLEVEL <= E_FATAL) */
#if WITH_MSGLEVEL <= E_ERROR
#define Error(m) msg(E_ERROR,"%s",m)
#define Error1(m,a1) msg(E_ERROR,m,a1)
#define Error2(m,a1,a2) msg(E_ERROR,m,a1,a2)
#define Error3(m,a1,a2,a3) msg(E_ERROR,m,a1,a2,a3)
#define Error4(m,a1,a2,a3,a4) msg(E_ERROR,m,a1,a2,a3,a4)
#define Error5(m,a1,a2,a3,a4,a5) msg(E_ERROR,m,a1,a2,a3,a4,a5)
#define Error6(m,a1,a2,a3,a4,a5,a6) msg(E_ERROR,m,a1,a2,a3,a4,a5,a6)
#define Error7(m,a1,a2,a3,a4,a5,a6,a7) msg(E_ERROR,m,a1,a2,a3,a4,a5,a6,a7)
#define Error8(m,a1,a2,a3,a4,a5,a6,a7,a8) msg(E_ERROR,m,a1,a2,a3,a4,a5,a6,a7,a8)
#define Error9(m,a1,a2,a3,a4,a5,a6,a7,a8,a9) msg(E_ERROR,m,a1,a2,a3,a4,a5,a6,a7,a8,a9)
#define Error10(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) msg(E_ERROR,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
#define Error11(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) msg(E_ERROR,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)
#else /* !(WITH_MSGLEVEL >= E_ERROR) */
#define Error(m)
#define Error1(m,a1)
#define Error2(m,a1,a2)
#define Error3(m,a1,a2,a3)
#define Error4(m,a1,a2,a3,a4)
#define Error5(m,a1,a2,a3,a4,a5)
#define Error6(m,a1,a2,a3,a4,a5,a6)
#define Error7(m,a1,a2,a3,a4,a5,a6,a7)
#define Error8(m,a1,a2,a3,a4,a5,a6,a7,a8)
#define Error9(m,a1,a2,a3,a4,a5,a6,a7,a8,a9)
#define Error10(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
#define Error11(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)
#endif /* !(WITH_MSGLEVEL <= E_ERROR) */
#if WITH_MSGLEVEL <= E_WARN
#define Warn(m) msg(E_WARN,"%s",m)
#define Warn1(m,a1) msg(E_WARN,m,a1)
#define Warn2(m,a1,a2) msg(E_WARN,m,a1,a2)
#define Warn3(m,a1,a2,a3) msg(E_WARN,m,a1,a2,a3)
#define Warn4(m,a1,a2,a3,a4) msg(E_WARN,m,a1,a2,a3,a4)
#define Warn5(m,a1,a2,a3,a4,a5) msg(E_WARN,m,a1,a2,a3,a4,a5)
#define Warn6(m,a1,a2,a3,a4,a5,a6) msg(E_WARN,m,a1,a2,a3,a4,a5,a6)
#define Warn7(m,a1,a2,a3,a4,a5,a6,a7) msg(E_WARN,m,a1,a2,a3,a4,a5,a6,a7)
#else /* !(WITH_MSGLEVEL <= E_WARN) */
#define Warn(m)
#define Warn1(m,a1)
#define Warn2(m,a1,a2)
#define Warn3(m,a1,a2,a3)
#define Warn4(m,a1,a2,a3,a4)
#define Warn5(m,a1,a2,a3,a4,a5)
#define Warn6(m,a1,a2,a3,a4,a5,a6)
#define Warn7(m,a1,a2,a3,a4,a5,a6,a7)
#endif /* !(WITH_MSGLEVEL <= E_WARN) */
#if WITH_MSGLEVEL <= E_NOTICE
#define Notice(m) msg(E_NOTICE,"%s",m)
#define Notice1(m,a1) msg(E_NOTICE,m,a1)
#define Notice2(m,a1,a2) msg(E_NOTICE,m,a1,a2)
#define Notice3(m,a1,a2,a3) msg(E_NOTICE,m,a1,a2,a3)
#define Notice4(m,a1,a2,a3,a4) msg(E_NOTICE,m,a1,a2,a3,a4)
#define Notice5(m,a1,a2,a3,a4,a5) msg(E_NOTICE,m,a1,a2,a3,a4,a5)
#define Notice6(m,a1,a2,a3,a4,a5,a6) msg(E_NOTICE,m,a1,a2,a3,a4,a5,a6)
#define Notice7(m,a1,a2,a3,a4,a5,a6,a7) msg(E_NOTICE,m,a1,a2,a3,a4,a5,a6,a7)
#define Notice8(m,a1,a2,a3,a4,a5,a6,a7,a8) msg(E_NOTICE,m,a1,a2,a3,a4,a5,a6,a7,a8)
#define Notice9(m,a1,a2,a3,a4,a5,a6,a7,a8,a9) msg(E_NOTICE,m,a1,a2,a3,a4,a5,a6,a7,a8,a9)
#else /* !(WITH_MSGLEVEL <= E_NOTICE) */
#define Notice(m)
#define Notice1(m,a1)
#define Notice2(m,a1,a2)
#define Notice3(m,a1,a2,a3)
#define Notice4(m,a1,a2,a3,a4)
#define Notice5(m,a1,a2,a3,a4,a5)
#define Notice6(m,a1,a2,a3,a4,a5,a6)
#define Notice7(m,a1,a2,a3,a4,a5,a6,a7)
#define Notice8(m,a1,a2,a3,a4,a5,a6,a7,a8)
#define Notice9(m,a1,a2,a3,a4,a5,a6,a7,a8,a9)
#endif /* !(WITH_MSGLEVEL <= E_NOTICE) */
#if WITH_MSGLEVEL <= E_INFO
#define Info(m) msg(E_INFO,"%s",m)
#define Info1(m,a1) msg(E_INFO,m,a1)
#define Info2(m,a1,a2) msg(E_INFO,m,a1,a2)
#define Info3(m,a1,a2,a3) msg(E_INFO,m,a1,a2,a3)
#define Info4(m,a1,a2,a3,a4) msg(E_INFO,m,a1,a2,a3,a4)
#define Info5(m,a1,a2,a3,a4,a5) msg(E_INFO,m,a1,a2,a3,a4,a5)
#define Info6(m,a1,a2,a3,a4,a5,a6) msg(E_INFO,m,a1,a2,a3,a4,a5,a6)
#define Info7(m,a1,a2,a3,a4,a5,a6,a7) msg(E_INFO,m,a1,a2,a3,a4,a5,a6,a7)
#define Info8(m,a1,a2,a3,a4,a5,a6,a7,a8) msg(E_INFO,m,a1,a2,a3,a4,a5,a6,a7,a8)
#define Info9(m,a1,a2,a3,a4,a5,a6,a7,a8,a9) msg(E_INFO,m,a1,a2,a3,a4,a5,a6,a7,a8,a9)
#define Info10(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) msg(E_INFO,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
#define Info11(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) msg(E_INFO,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)
#else /* !(WITH_MSGLEVEL <= E_INFO) */
#define Info(m)
#define Info1(m,a1)
#define Info2(m,a1,a2)
#define Info3(m,a1,a2,a3)
#define Info4(m,a1,a2,a3,a4)
#define Info5(m,a1,a2,a3,a4,a5)
#define Info6(m,a1,a2,a3,a4,a5,a6)
#define Info7(m,a1,a2,a3,a4,a5,a6,a7)
#define Info8(m,a1,a2,a3,a4,a5,a6,a7,a8)
#define Info9(m,a1,a2,a3,a4,a5,a6,a7,a8,a9)
#define Info10(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
#define Info11(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)
#endif /* !(WITH_MSGLEVEL <= E_INFO) */
#if WITH_MSGLEVEL <= E_DEBUG
#define Debug(m) msg(E_DEBUG,"%s",m)
#define Debug1(m,a1) msg(E_DEBUG,m,a1)
#define Debug2(m,a1,a2) msg(E_DEBUG,m,a1,a2)
#define Debug3(m,a1,a2,a3) msg(E_DEBUG,m,a1,a2,a3)
#define Debug4(m,a1,a2,a3,a4) msg(E_DEBUG,m,a1,a2,a3,a4)
#define Debug5(m,a1,a2,a3,a4,a5) msg(E_DEBUG,m,a1,a2,a3,a4,a5)
#define Debug6(m,a1,a2,a3,a4,a5,a6) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6)
#define Debug7(m,a1,a2,a3,a4,a5,a6,a7) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7)
#define Debug8(m,a1,a2,a3,a4,a5,a6,a7,a8) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8)
#define Debug9(m,a1,a2,a3,a4,a5,a6,a7,a8,a9) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8,a9)
#define Debug10(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
#define Debug11(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)
#define Debug12(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)
#define Debug13(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13)
#define Debug14(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14)
#define Debug15(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15)
#define Debug16(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)
#define Debug17(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17)
#define Debug18(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18) msg(E_DEBUG,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18)
#else /* !(WITH_MSGLEVEL <= E_DEBUG) */
#define Debug(m)
#define Debug1(m,a1)
#define Debug2(m,a1,a2)
#define Debug3(m,a1,a2,a3)
#define Debug4(m,a1,a2,a3,a4)
#define Debug5(m,a1,a2,a3,a4,a5)
#define Debug6(m,a1,a2,a3,a4,a5,a6)
#define Debug7(m,a1,a2,a3,a4,a5,a6,a7)
#define Debug8(m,a1,a2,a3,a4,a5,a6,a7,a8)
#define Debug9(m,a1,a2,a3,a4,a5,a6,a7,a8,a9)
#define Debug10(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
#define Debug11(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)
#define Debug12(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)
#define Debug13(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13)
#define Debug14(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14)
#define Debug15(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15)
#define Debug16(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)
#define Debug17(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17)
#define Debug18(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18)
#endif /* !(WITH_MSGLEVEL <= E_DEBUG) */
/* message with software controlled serverity */
#if WITH_MSGLEVEL <= E_FATAL
#define Msg(l,m) msg(l,"%s",m)
#define Msg1(l,m,a1) msg(l,m,a1)
#define Msg2(l,m,a1,a2) msg(l,m,a1,a2)
#define Msg3(l,m,a1,a2,a3) msg(l,m,a1,a2,a3)
#define Msg4(l,m,a1,a2,a3,a4) msg(l,m,a1,a2,a3,a4)
#define Msg5(l,m,a1,a2,a3,a4,a5) msg(l,m,a1,a2,a3,a4,a5)
#define Msg6(l,m,a1,a2,a3,a4,a5,a6) msg(l,m,a1,a2,a3,a4,a5,a6)
#define Msg7(l,m,a1,a2,a3,a4,a5,a6,a7) msg(l,m,a1,a2,a3,a4,a5,a6,a7)
#else /* !(WITH_MSGLEVEL >= E_FATAL) */
#define Msg(l,m)
#define Msg1(l,m,a1)
#define Msg2(l,m,a1,a2)
#define Msg3(l,m,a1,a2,a3)
#define Msg4(l,m,a1,a2,a3,a4)
#define Msg5(l,m,a1,a2,a3,a4,a5)
#define Msg6(l,m,a1,a2,a3,a4,a5,a6)
#define Msg7(l,m,a1,a2,a3,a4,a5,a6,a7)
#endif /* !(WITH_MSGLEVEL <= E_FATAL) */
enum diag_op {
DIAG_OP_MSG, /* a diagnostic message */
DIAG_OP_EXIT, /* exit the program */
} ;
/* datagram for communication between outer msg() call from signal handler to
inner msg() call in normal flow */
# define TEXTLEN 480
struct diag_dgram {
enum diag_op op;
#if HAVE_CLOCK_GETTIME
struct timespec now;
#elif HAVE_PROTOTYPE_LIB_gettimeofday
struct timeval now;
#else
time_t now;
#endif
int level; /* E_FATAL, ... E_DEBUG */
int _errno; /* for glibc %m format */
int exitcode; /* if exiting take this num */
char text[TEXTLEN];
} ;
extern volatile sig_atomic_t diag_in_handler;
extern volatile sig_atomic_t diag_immediate_msg;
extern volatile sig_atomic_t diag_immediate_exit;
extern void diag_set(char what, const char *arg);
extern void diag_set_int(char what, int arg);
extern int diag_get_int(char what);
extern const char *diag_get_string(char what);
extern int diag_reserve_fd(int fd);
extern int diag_fork(void);
extern int diag_dup(void);
extern int diag_dup2(int newfd);
extern void msg(int level, const char *format, ...);
extern void diag_flush(void);
extern void diag_exit(int status);
extern int diag_select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
#endif /* !defined(__error_h_included) */

516
fdname.c Normal file
View File

@@ -0,0 +1,516 @@
/* source: fdname.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* the subroutine sockname prints the basic info about the address of a socket
NOTE: it works on UNIX (kernel) file descriptors, not on libc files! */
#include "config.h"
#include "xioconfig.h" /* what features are enabled */
#include "sysincludes.h"
#include "mytypes.h"
#include "compat.h"
#include "error.h"
#include "sycls.h"
#include "sysutils.h"
#include "filan.h"
struct sockopt {
int so;
char *name;
};
int statname(const char *file, int fd, int filetype, FILE *outfile, char style);
int cdevname(int fd, FILE *outfile);
int sockname(int fd, FILE *outfile, char style);
int unixame(int fd, FILE *outfile);
int tcpname(int fd, FILE *outfile);
int fdname(const char *file, int fd, FILE *outfile, const char *numform,
char style) {
struct stat buf = {0};
int filetype;
Debug1("checking file descriptor %u", fd);
if (fd >= 0) {
if (Fstat(fd, &buf) < 0) {
if (errno == EBADF) {
Debug2("fstat(%d): %s", fd, strerror(errno));
return -1;
} else {
Error2("fstat(%d): %s", fd, strerror(errno));
}
}
filetype = (buf.st_mode&S_IFMT)>>12;
if (numform != NULL) {
fprintf(outfile, numform, fd);
}
return statname(file, fd, filetype, outfile, style);
} else {
if (Stat(file, &buf) < 0) {
Error2("stat(\"%s\"): %s", file, strerror(errno));
}
filetype = (buf.st_mode&S_IFMT)>>12;
return statname(file, -1, filetype, outfile, style);
}
}
#if HAVE_PROC_DIR_FD || HAVE_PROC_DIR_PATH
static int procgetfdname(int fd, char *filepath, size_t pathsize) {
static pid_t pid = -1;
char procpath[PATH_MAX];
int len;
/* even if configure has shown that we have /proc, we must check if it
exists at runtime, because we might be in a chroot environment */
#if HAVE_STAT64
{
struct stat64 buf;
if (Stat64("/proc", &buf) < 0) {
return -1;
}
if (!S_ISDIR(buf.st_mode)) {
return -1;
}
}
#else /* !HAVE_STAT64 */
{
struct stat buf;
if (Stat("/proc", &buf) < 0) {
return -1;
}
if (!S_ISDIR(buf.st_mode)) {
return -1;
}
}
#endif /* !HAVE_STAT64 */
if (pid < 0) pid = Getpid();
snprintf(procpath, sizeof(procpath), "/proc/"F_pid"/"
#if HAVE_PROC_DIR_PATH
"path"
#else
"fd"
#endif
"/%d", pid, fd);
if ((len = Readlink(procpath, filepath, pathsize-1)) < 0) {
Notice4("readlink(\"%s\", %p, "F_Zu"): %s",
procpath, filepath, pathsize, strerror(errno));
len = 0;
}
filepath[len] = '\0';
return 0;
}
#endif /* HAVE_PROC_DIR_FD || HAVE_PROC_DIR_PATH */
int statname(const char *file, int fd, int filetype, FILE *outfile,
char style) {
char filepath[PATH_MAX];
filepath[0] = '\0';
#if HAVE_PROC_DIR_FD || HAVE_PROC_DIR_PATH
if (fd >= 0) {
procgetfdname(fd, filepath, sizeof(filepath));
if (filepath[0] == '/') {
file = filepath;
}
}
#endif /* HAVE_PROC_DIR_FD || HAVE_PROC_DIR_PATH */
/* now see for type specific infos */
switch (filetype) {
case (S_IFIFO>>12): /* 1, FIFO */
fputs("pipe", outfile);
if (file) fprintf(outfile, " %s", file);
break;
case (S_IFCHR>>12): /* 2, character device */
if (cdevname(fd, outfile) == 0) {
if (file) fprintf(outfile, " %s", file);
}
break;
case (S_IFDIR>>12): /* 4, directory */
fputs("dir", outfile);
if (file) fprintf(outfile, " %s", file);
break;
case (S_IFBLK>>12): /* 6, block device */
fputs("blkdev", outfile);
if (file) fprintf(outfile, " %s", file);
break;
case (S_IFREG>>12): /* 8, regular file */
fputs("file", outfile);
if (file) fprintf(outfile, " %s", file);
break;
case (S_IFLNK>>12): /* 10, symbolic link */
fputs("link", outfile);
if (file) fprintf(outfile, " %s", file);
break;
case (S_IFSOCK>>12): /* 12, socket */
#if _WITH_SOCKET
if (fd >= 0) {
sockname(fd, outfile, style);
} else if (file) {
fprintf(outfile, "socket %s", file);
} else {
fputs("socket", outfile);
}
#else
Error("SOCKET support not compiled in");
return -1;
#endif /* !_WITH_SOCKET */
break;
#ifdef S_IFDOOR
case (S_IFDOOR>>12): /* 13, door (Solaris) */
fputs("door", outfile);
if (file) fprintf(outfile, " %s", file);
break;
#endif /* HAVE_MACRO_S_IFDOOR */
#ifdef S_IFPORT
case (S_IFPORT>>12): /* 14, event port (Solaris) */
fputs("event_port", outfile);
if (file) fprintf(outfile, " %s", file);
break;
#endif /* HAVE_MACRO_S_IFPORT */
}
/* ioctl() */
fputc('\n', outfile);
return 0;
}
/* character device analysis */
/* return -1 on error, 0 if no name was found, or 1 if it printed ttyname */
int cdevname(int fd, FILE *outfile) {
int ret;
if ((ret = Isatty(fd)) < 0) {
Error2("isatty(%d): %s", fd, strerror(errno));
return -1;
}
if (ret > 0) {
char *name;
fputs("tty", outfile);
if ((name = Ttyname(fd)) != NULL) {
fputc(' ', outfile);
fputs(name, outfile);
return 1;
}
} else {
fputs("chrdev", outfile);
}
return 0;
}
int sockettype(int socktype, char *typename, size_t typenamemax) {
switch (socktype) {
case SOCK_STREAM: strncpy(typename, "stream", typenamemax); break;
case SOCK_DGRAM: strncpy(typename, "dgram", typenamemax); break;
case SOCK_SEQPACKET: strncpy(typename, "seqpacket", typenamemax); break;
case SOCK_RAW: strncpy(typename, "raw", typenamemax); break;
case SOCK_RDM: strncpy(typename, "rdm", typenamemax); break;
#ifdef SOCK_PACKET
case SOCK_PACKET: strncpy(typename, "packet", typenamemax); break;
#endif
default: snprintf(typename, typenamemax, "socktype%u", socktype); break;
}
return 0;
}
#if _WITH_SOCKET
int sockname(int fd, FILE *outfile, char style) {
#define FDNAME_OPTLEN 256
#define FDNAME_NAMELEN 256
socklen_t optlen;
#if HAVE_GETPROTOBYNUMBER || HAVE_GETPROTOBYNUMBER_R
struct protoent protoent, *protoentp;
#endif
#define PROTONAMEMAX 1024
char protoname[PROTONAMEMAX] = "";
#if defined(SO_PROTOCOL) || defined(SO_PROTOTYPE)
int proto = 0;
#endif
int opttype;
#ifdef SO_ACCEPTCONN
int optacceptconn = 0; /* OpenBSD does not give value on unix dgram */
#endif
int result /*0, i*/;
char socknamebuff[FDNAME_NAMELEN];
char peernamebuff[FDNAME_NAMELEN];
/* in Linux these optcodes are 'enum', but on AIX they are bits! */
union sockaddr_union sockname, peername; /* the longest I know of */
socklen_t socknamelen, peernamelen;
# define TYPENAMEMAX 16
char typename[TYPENAMEMAX];
#if 0 && defined(SIOCGIFNAME)
/*Linux struct ifreq ifc = {{{ 0 }}};*/
struct ifreq ifc = {{ 0 }};
#endif
int rc;
#if defined(SO_PROTOCOL) || defined(SO_PROTOTYPE)
optlen = sizeof(proto);
#ifdef SO_PROTOCOL
rc = Getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &proto, &optlen);
#elif defined(SO_PROTOTYPE)
rc = Getsockopt(fd, SOL_SOCKET, SO_PROTOTYPE, &proto, &optlen);
#endif
if (rc < 0) {
Notice5("getsocktop(%d, SOL_SOCKET, "
#ifdef SO_PROTOCOL
"SO_PROTOCOL"
#else
"SO_PROTOTYPE"
#endif
", &%p, {"F_socklen"}): errno=%d (%s)", fd, &proto, optlen, errno, strerror(errno));
}
#endif /* defined(SO_PROTOCOL) || defined(SO_PROTOTYPE) */
optlen = sizeof(opttype);
Getsockopt(fd, SOL_SOCKET, SO_TYPE, &opttype, &optlen);
sockettype(opttype, typename, sizeof(typename));
optlen = sizeof(optacceptconn);
#ifdef SO_ACCEPTCONN
Getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &optacceptconn, &optlen);
#endif
#if defined(SO_PROTOCOL) || defined(SO_PROTOTYPE)
#if HAVE_GETPROTOBYNUMBER_R==1 /* Linux */
rc = getprotobynumber_r(proto, &protoent, protoname, sizeof(protoname), &protoentp);
if (protoentp == NULL) {
Warn2("sockname(): getprotobynumber_r(proto=%d, ...): %s",
proto, strerror(rc));
}
strncpy(protoname, protoentp->p_name, sizeof(protoname));
#elif HAVE_GETPROTOBYNUMBER_R==2 /* Solaris */
{
# define FILAN_GETPROTOBYNUMBER_R_BUFLEN 1024
char buffer[FILAN_GETPROTOBYNUMBER_R_BUFLEN];
protoentp = getprotobynumber_r(proto, &protoent, buffer, FILAN_GETPROTOBYNUMBER_R_BUFLEN);
strncpy(protoname, protoentp->p_name, sizeof(protoname));
}
#elif HAVE_GETPROTOBYNUMBER_R==3 /* AIX, OpenBSD */
{
struct protoent_data proto_data = { 0 }; /* OpenBSD might SIGSEGV */
rc = getprotobynumber_r(proto, &protoent, &proto_data);
if (rc == 0) {
strncpy(protoname, protoent.p_name, sizeof(protoname));
endprotoent_r(&proto_data);
}
}
#else
switch (proto) {
case IPPROTO_TCP: strcpy(protoname, "tcp"); break;
case IPPROTO_UDP: strcpy(protoname, "udp"); break;
case IPPROTO_SCTP: strcpy(protoname, "sctp"); break;
default: sprintf(protoname, "proto%d", proto); break;
}
#endif
#else /* ! (defined(SO_PROTOCOL) || defined(SO_PROTOTYPE)) */
if (opttype == SOCK_STREAM) {
strcpy(protoname, "(stream)");
} else if (opttype == SOCK_DGRAM) {
strcpy(protoname, "(dgram)");
#ifdef SOCK_RAW
} else if (opttype == SOCK_RAW) {
strcpy(protoname, "(raw)");
#endif
#ifdef SOCK_RDM
} else if (opttype == SOCK_RDM) {
strcpy(protoname, "(rdm)");
#endif
#ifdef SOCK_SEQPACKET
} else if (opttype == SOCK_SEQPACKET) {
strcpy(protoname, "(seqpacket)");
#endif
#ifdef SOCK_DCCP
} else if (opttype == SOCK_DCCP) {
strcpy(protoname, "(dccp)");
#endif
#ifdef SOCK_PACKET
} else if (opttype == SOCK_PACKET) {
strcpy(protoname, "(packet)");
#endif
} else {
strcpy(protoname, "socket");
}
#endif /* ! (defined(SO_PROTOCOL) || defined(SO_PROTOTYPE)) */
socknamelen = sizeof(sockname);
result = Getsockname(fd, &sockname.soa, &socknamelen);
if (result < 0) {
Error2("getsockname(%d): %s", fd, strerror(errno));
return -1;
}
peernamelen = sizeof(peername);
result = Getpeername(fd, (struct sockaddr *)&peername, &peernamelen);
if (result < 0) {
Warn2("getpeername(%d): %s", fd, strerror(errno));
}
switch (sockname.soa.sa_family) {
#if WITH_UNIX
case AF_UNIX:
switch (style) {
case 's':
fprintf(outfile, "unix%s%s %s",
opttype==SOCK_DGRAM?"datagram":"",
#ifdef SO_ACCEPTCONN
optacceptconn?"(listening)":
#endif
"",
sockaddr_unix_info(&sockname.un, socknamelen,
socknamebuff, sizeof(socknamebuff)));
break;
case 'S':
/* sockettype(opttype, typename, TYPENAMEMAX); */
fprintf(outfile, "unix %s-%s %s %s",
sockaddr_unix_info(&sockname.un, socknamelen,
socknamebuff, sizeof(socknamebuff)),
sockaddr_unix_info(&peername.un, peernamelen,
peernamebuff, sizeof(peernamebuff)),
typename,
#ifdef SO_ACCEPTCONN
optacceptconn?"(listening)":
#endif
"");
break;
}
break;
#endif /* WITH_UNIX */
#if WITH_IP4
case AF_INET:
switch (style) {
case 's':
switch (opttype) {
#if WITH_TCP
case SOCK_STREAM:
fprintf(outfile, "%s%s %s %s",
protoname,
#ifdef SO_ACCEPTCONN
optacceptconn?"(listening)":
#endif
"",
sockaddr_inet4_info(&sockname.ip4,
socknamebuff, sizeof(socknamebuff)),
sockaddr_inet4_info(&peername.ip4,
peernamebuff, sizeof(peernamebuff)));
break;
#endif
#if WITH_UDP
case SOCK_DGRAM:
fprintf(outfile, "%s%s %s %s",
protoname,
#ifdef SO_ACCEPTCONN
optacceptconn?"(listening)":
#endif
"",
sockaddr_inet4_info(&sockname.ip4,
socknamebuff, sizeof(socknamebuff)),
sockaddr_inet4_info(&peername.ip4,
peernamebuff, sizeof(peernamebuff)));
break;
#endif
default:
fprintf(outfile, "ip %s",
sockaddr_inet4_info(&sockname.ip4,
socknamebuff, sizeof(socknamebuff)));
break;
}
break;
case 'S':
fprintf(outfile, "%s %s-%s (%s) %s",
protoname,
sockaddr_inet4_info(&sockname.ip4,
socknamebuff, sizeof(socknamebuff)),
sockaddr_inet4_info(&peername.ip4,
peernamebuff, sizeof(peernamebuff)),
typename,
#ifdef SO_ACCEPTCONN
optacceptconn?"(listening)":
#endif
"");
break;
}
break;
#endif /* WITH_IP4 */
#if WITH_IP6
case AF_INET6:
switch (style) {
case 's':
switch (opttype) {
#if WITH_TCP
case SOCK_STREAM:
fprintf(outfile, "%s6%s %s %s",
protoname,
#ifdef SO_ACCEPTCONN
optacceptconn?"(listening)":
#endif
"",
sockaddr_inet6_info(&sockname.ip6,
socknamebuff, sizeof(socknamebuff)),
sockaddr_inet6_info(&peername.ip6,
peernamebuff, sizeof(peernamebuff)));
break;
#endif
#if WITH_UDP
case SOCK_DGRAM:
fprintf(outfile, "%s6%s %s %s",
protoname,
#ifdef SO_ACCEPTCONN
optacceptconn?"(listening)":
#endif
"",
sockaddr_inet6_info(&sockname.ip6,
socknamebuff, sizeof(socknamebuff)),
sockaddr_inet6_info(&peername.ip6,
peernamebuff, sizeof(peernamebuff)));
break;
#endif
default:
fprintf(outfile, "ip6 %s",
sockaddr_inet6_info(&sockname.ip6,
socknamebuff, sizeof(socknamebuff)));
break;
}
break;
case 'S':
fprintf(outfile, "%s6 %s-%s (%s) %s",
protoname,
sockaddr_inet6_info(&sockname.ip6,
socknamebuff, sizeof(socknamebuff)),
sockaddr_inet6_info(&peername.ip6,
peernamebuff, sizeof(peernamebuff)),
typename,
#ifdef SO_ACCEPTCONN
optacceptconn?"(listening)":
#endif
"");
break;
}
break;
#endif /* WITH_IP6 */
default:
fprintf(outfile, "socket(family/domain=%d)", sockname.soa.sa_family);
}
#if HAVE_GETPROTOENT
if (ipproto >= 0) {
endprotoent();
}
#endif
return result;
#undef FDNAME_OPTLEN
#undef FDNAME_NAMELEN
}
#endif /* _WITH_SOCKET */

1069
filan.c Normal file

File diff suppressed because it is too large Load Diff

42
filan.h Normal file
View File

@@ -0,0 +1,42 @@
/* source: filan.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __filan_h_included
#define __filan_h_included 1
struct sockaddr; /* prevent gcc from spitting silly warning */
struct sockaddr_un; /* prevent gcc from spitting silly warning */
struct sockaddr_in; /* prevent gcc from spitting silly warning */
struct sockaddr_in6; /* prevent gcc from spitting silly warning */
extern bool filan_followsymlinks;
extern bool filan_rawoutput;
extern int filan_file(const char *filename, FILE *outfile);
extern int filan_fd(int fd, FILE *outfile);
extern int filan_stat(
#if HAVE_STAT64
struct stat64 *buf
#else
struct stat *buf
#endif /* !HAVE_STAT64 */
, int statfd, int dynfd, FILE *outfile,
const char *filename);
extern int cdevan(int fd, FILE *outfile);
#if _WITH_SOCKET
extern int isasocket(int fd);
extern int sockettype(int socktype, char *typename, size_t typenamemax);
extern int sockan(int fd, FILE *outfile);
extern int ipan(int fd, FILE *outfile);
extern int ip6an(int fd, FILE *outfile);
#endif /* _WITH_SOCKET */
extern
int fdname(const char *file, int fd, FILE *outfile, const char *numform,
char style);
#endif /* !defined(__filan_h_included) */

263
filan_main.c Normal file
View File

@@ -0,0 +1,263 @@
/* source: filan_main.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
const char copyright[] = "filan by Gerhard Rieger and contributors - see http://www.dest-unreach.org/socat/";
#include "config.h"
#include "xioconfig.h"
#include "sysincludes.h"
#include "mytypes.h"
#include "compat.h"
#include "error.h"
#include "sycls.h"
#include "filan.h"
#define WITH_HELP 1
static void filan_usage(FILE *fd);
int main(int argc, const char *argv[]) {
const char **arg1, *a0, *a;
const char *filename = NULL, *waittimetxt;
unsigned int m = 0; /* first FD (default) */
unsigned int n = FD_SETSIZE; /* last excl. */
unsigned int i;
int style = 0;
struct timespec waittime = { 0, 0 };
FILE *fdout = stdout;
const char *outfname = NULL;
unsigned long fildes;
diag_set('I', NULL);
diag_set('p', strchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]);
arg1 = argv+1; --argc;
while (arg1[0] && (arg1[0][0] == '-')) {
switch (arg1[0][1]) {
#if WITH_HELP
case '?': case 'h':
filan_usage(stdout); exit(0);
#endif
#if LATER
case 'V': filan_version(stdout); exit(0);
#endif
case 'L': filan_followsymlinks = true; break;
case 'd': diag_set('d', NULL); break;
case 's': style = arg1[0][1]; break;
case 'S': style = arg1[0][1]; break;
case 'r': filan_rawoutput = true; break;
case 'i': if (arg1[0][2]) {
a = a0 = *arg1+2;
} else {
++arg1, --argc;
if ((a = a0 = *arg1) == NULL) {
Error("option -i requires an argument");
filan_usage(stderr); exit(1);
}
}
m = strtoul(a, (char **)&a, 0);
if (a == a0) {
Error1("not a numerical arg in \"-i %s\"", a0);
}
if (*a != '\0') {
Error1("trailing garbage in \"-i %s\"", a0);
}
n = m;
break;
case 'n': if (arg1[0][2]) {
a = a0 = *arg1+2;
} else {
++arg1, --argc;
if ((a = a0 = *arg1) == NULL) {
Error("option -n requires an argument");
filan_usage(stderr); exit(1);
}
}
n = strtoul(a, (char **)&a, 0);
if (a == a0) {
Error1("not a numerical arg in \"-n %s\"", a0);
}
if (*a != '\0') {
Error1("trailing garbage in \"-n %s\"", a0);
}
break;
case 'f': if (arg1[0][2]) {
filename = *arg1+2;
} else {
++arg1, --argc;
if ((filename = *arg1) == NULL) {
Error("option -f requires an argument");
filan_usage(stderr); exit(1);
}
}
break;
case 'T': if (arg1[0][2]) {
waittimetxt = *arg1+2;
} else {
++arg1, --argc;
if ((waittimetxt = *arg1) == NULL) {
Error("option -T requires an argument");
filan_usage(stderr); exit(1);
}
}
{
double waittimedbl;
waittimedbl = strtod(waittimetxt, NULL);
waittime.tv_sec = waittimedbl;
waittime.tv_nsec = (waittimedbl-waittime.tv_sec) * 1000000000;
}
break;
case 'o': if (arg1[0][2]) {
outfname = *arg1+2;
} else {
++arg1, --argc;
if ((outfname = *arg1) == NULL) {
Error("option -o requires an argument");
filan_usage(stderr); exit(1);
}
}
break;
case '\0': break;
default:
diag_set_int('e', E_FATAL);
Error1("unknown option %s", arg1[0]);
#if WITH_HELP
filan_usage(stderr);
#endif
exit(1);
}
#if 0
if (arg1[0][1] == '\0')
break;
#endif
++arg1; --argc;
}
if (argc != 0) {
Error1("%d superfluous arguments", argc);
filan_usage(stderr);
exit(1);
}
if (outfname) {
/* special cases */
if (!strcmp(outfname,"stdin")) { fdout=stdin; }
else if (!strcmp(outfname,"stdout")) { fdout=stdout; }
else if (!strcmp(outfname,"stderr")) { fdout=stderr; }
/* file descriptor */
else if (*outfname == '+') {
a = outfname+1;
fildes = strtoul(a, (char **)&a, 0);
if ((fdout = fdopen(fildes, "w")) == NULL) {
Error2("can't fdopen file descriptor %lu: %s\n", fildes, strerror(errno));
exit(1);
}
} else {
/* file name */
if ((fdout = fopen(outfname, "w")) == NULL) {
Error2("can't fopen '%s': %s\n",
outfname, strerror(errno));
exit(1);
}
}
}
Nanosleep(&waittime, NULL);
if (style == 0) {
/* this style gives detailled infos, but requires a file descriptor */
if (filename) {
#if LATER /* this is just in case that S_ISSOCK does not work */
struct stat buf;
int fd;
if (Stat(filename, &buf) < 0) {
Error3("stat(\"%s\", %p): %s", filename, &buf, strerror(errno));
}
/* note: when S_ISSOCK was undefined, it always gives 0 */
if (S_ISSOCK(buf.st_mode)) {
Error("cannot analyze UNIX domain socket");
}
#endif
filan_file(filename, fdout);
} else {
if (m == n) {
++n;
}
for (i = m; i < n; ++i) {
filan_fd(i, fdout);
}
}
} else {
/* this style gives only type and path / socket addresses, and works from
file descriptor or filename (with restrictions) */
if (filename) {
/* filename: NULL means yet unknown; "" means no name at all */
#if LATER
int fd;
if ((fd =
Open(filename, O_RDONLY|O_NOCTTY|O_NONBLOCK
#ifdef O_LARGEFILE
|O_LARGEFILE
#endif
, 0700))
< 0) {
Debug2("open(\"%s\", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE, 0700): %s",
filename, strerror(errno));
}
fdname(filename, fd, fdout, NULL, style);
#endif
fdname(filename, -1, fdout, NULL, style);
} else {
if (m == n) {
fdname("", m, fdout, NULL, style);
} else {
for (i = m; i < n; ++i) {
fdname("", i, fdout, "%5u ", style);
}
}
}
}
if (outfname && fdout != stdout && fdout != stderr) {
fclose(fdout);
}
return 0;
}
#if WITH_HELP
static void filan_usage(FILE *fd) {
fputs(copyright, fd); fputc('\n', fd);
fputs("Analyze file descriptors of the process\n", fd);
fputs("Usage:\n", fd);
fputs("filan [options]\n", fd);
fputs(" options:\n", fd);
#if LATER
fputs(" -V print version information to stdout, and exit\n", fd);
#endif
#if WITH_HELP
fputs(" -?|-h print this help text\n", fd);
fputs(" -d increase verbosity (use up to 4 times)\n", fd);
#endif
#if 0
fputs(" -ly[facility] log to syslog, using facility (default is daemon)\n", fd);
fputs(" -lf<logfile> log to file\n", fd);
fputs(" -ls log to stderr (default if no other log)\n", fd);
#endif
fputs(" -i<fdnum> only analyze this fd\n", fd);
fprintf(fd, " -n<fdnum> analyze all fds from 0 up to fdnum-1 (default: %u)\n", FD_SETSIZE);
fputs(" -s simple output with just type and socket address or path\n", fd);
fputs(" -S like -s but improved format and contents\n", fd);
/* fputs(" -c alternate device visualization\n", fd);*/
fputs(" -f<filename> analyze file system entry\n", fd);
fputs(" -T<seconds> wait before analyzing, useful to connect with debugger\n", fd);
fputs(" -r raw output for time stamps and rdev\n", fd);
fputs(" -L follow symbolic links instead of showing their properties\n", fd);
fputs(" -o<filename> output goes to filename, that can be:\n", fd);
fputs(" a regular file name, the output goes to that\n", fd);
fputs(" +<filedes> , output goes to the file descriptor (which must be open writable)\n", fd);
fputs(" the 3 special names stdin stdout and stderr\n", fd);
}
#endif /* WITH_HELP */

158
ftp.sh Executable file
View File

@@ -0,0 +1,158 @@
#! /bin/sh
# source: ftp.sh
# Copyright Gerhard Rieger and contributors (see file CHANGES)
# Published under the GNU General Public License V.2, see file COPYING
# example how to write a shell script that communicates with stdio on the front
# end and with a socat address on the back end
# usage:
# ftp.sh [opts] server directory/ # show directory contents on stdout
# ftp.sh [opts] server file # print file contents to stdout
# opts:
# -socks socksserver # use given socks server, port 1080
# -proxy proxyserver # use given proxy server, port 8080
# # must be http proxy that accepts CONNECT
# # method to ports 21 and >=1024
# -user username # default: "ftp"
# -passwd password # default: "anonymous@domain.org"
# -t # shell script trace+debug
# -d # debug on control connection (use up to 4 times)
# -D # debug on data connection (use up to 4 times)
# -b # block size for data connection
# -v # verbose
# -l* # socat logging options
# example:
# ftp.sh -v -d -d -D -D -D -b 65536 -proxy proxy ftp.ftp.org /README >README
user="ftp"
passwd="anonymous@domain.org"
#method="socks4:socks" # socks4 is address spec, socks is socks server name
method=tcp
addropts=
# socat options
SO1=
SO2=
while :; do
case "$1" in
-socks|-socks4) shift;
case "$1" in
*:*) method="socks4:${1%%:*}"; addropts="socksport=${1#*:}" ;;
*) method="socks4:$1" ;;
esac ;;
-socks4a) shift;
case "$1" in
*:*) method="socks4a:${1%%:*}"; addropts="socksport=${1#*:}" ;;
*) method="socks4a:$1" ;;
esac ;;
-proxy) shift;
case "$1" in
*:*) method="proxy:${1%%:*}"; addropts="proxyport=${1#*:}" ;;
*) method="proxy:$1" ;;
esac ;;
-user) shift; user="$1" ;;
-passwd) shift; passwd="$1" ;;
-t) set -vx ;;
-d) SO1="$SO1 -d" ;;
-D) SO2="$SO2 -d" ;;
-b) SO2="$SO2 -b $2"; shift ;;
-v) SO1="$SO1 -v" ;;
-l*) SO1="$SO1 $1"; SO2="$SO2 $1" ;;
-*) echo "unknown option \"$1\"" >&2; exit 1;;
*) break ;;
esac
shift
done
export SO2
server="$1"
dir="$2"
echo "addr=$method:$server:21,$addropts"; exit
### this is the central part to establish communication with socat ###
### copy these lines to make new communication shell scripts
TMPDIR=$(if [ -x /bin/mktemp ]; then
/bin/mktemp -d /tmp/$USER/FTPSH.XXXXXX
else
(umask 077; d=/tmp/$USER/FTPSH.$$; mkdir $d; echo $d)
fi)
TO="$TMPDIR/to"; FROM="$TMPDIR/from"
socat $SO1 fifo:$TO,nonblock,ignoreeof!!fifo:$FROM $method:$server:21,$addropts &
S1=$!
while ! [ -p "$TO" -a -p "$FROM" ]; do sleep 1; done
exec 4>$TMPDIR/to 3<$TMPDIR/from
trap "S1=" 17
#trap "echo cleaning up...>&2; rm -r $TMPDIR; [ -n "$S1" ] && kill $S1" 0 3
trap "rm -r $TMPDIR" 0 3
### here the central part ends
# this function waits for a complete server message, checks if its status
# is in the permitted range (terminates session if not), and returns.
ftp_chat () {
local cmd="$1"
local errlevel="$2"; [ -z "$errlevel" ] && errlevel=300
if [ -n "$cmd" ]; then echo "$cmd" >&4; fi
while read status message <&3;
( case "$status" in [0-9][0-9][0-9]-*) exit 0;; [0-9][0-9][0-9]*) exit 1;; *) exit 1;; esac )
do :; done
#echo "got \"$status $message\"" >&2
if [ -z "$status" ]; then echo ftp data connection failed >&2; exit; fi
if [ "$status" -ge "$errlevel" ]; then
echo $message >&2
echo "QUIT" >&4; exit 1
fi
set +vx
}
# wait for server greeting
ftp_chat
ftp_chat "USER $user" 400
ftp_chat "PASS $passwd"
#ftp_chat "CWD $dir"
case "$dir" in
*/) ftp_chat "TYPE A" ;;
*) ftp_chat "TYPE I" ;;
esac
echo "PASV" >&4; read status message <&3
info=$(expr "$message" : '.*[^0-9]\([0-9]*,[0-9]*,[0-9]*,[0-9]*,[0-9]*,[0-9]*\).*')
echo $info |tr ',' ' ' |(read i1 i2 i3 i4 p1 p2
addr=$i1.$i2.$i3.$i4
port=$(echo "256*$p1+$p2" |bc)
#echo $addr:$port
trap : 20
# open data connection and transfer data
socat -u $SO2 $method:$server:$port,$addropts -
) &
S2=$!
case "$dir" in
*/) ftp_chat "NLST $dir" ;;
#*/) ftp_chat "LIST $dir" ;;
*) ftp_chat "RETR $dir" ;;
esac
case "$status" in
[45]*) kill $S2;;
esac
#echo "waiting for process $S2 to terminate" >&2
wait $S2
ftp_chat
ftp_chat "QUIT"
#echo "waiting for process $S1 to terminate" >&2
wait $S1
exit

341
hostan.c Normal file
View File

@@ -0,0 +1,341 @@
/* source: hostan.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* the subroutine hostan makes a "HOST ANalysis". It gathers information
about the host environment it is running in without modifying its state
(almost).
*/
#include "xiosysincludes.h"
#include "mytypes.h"
#include "compat.h"
#include "error.h"
#include "sycls.h"
#include "sysutils.h"
#include "filan.h"
#include "hostan.h"
static int iffan(FILE *outfile);
static int vsockan(FILE *outfile);
int hostan(FILE *outfile) {
fprintf(outfile, "\nC TYPE SIZES\n");
fprintf(outfile, "sizeof(char) = %u\n", (unsigned int)sizeof(char));
fprintf(outfile, "sizeof(short) = %u\n", (unsigned int)sizeof(short));
fprintf(outfile, "sizeof(int) = %u\n", (unsigned int)sizeof(int));
fprintf(outfile, "sizeof(long) = %u\n", (unsigned int)sizeof(long));
#if HAVE_TYPE_LONGLONG
fprintf(outfile, "sizeof(long long) = %u\n", (unsigned int)sizeof(long long));
#endif
fprintf(outfile, "sizeof(size_t) = %u\n", (unsigned int)sizeof(size_t));
# if HAVE_BASIC_SIZE_T==2
fprintf(outfile, "typedef unsigned short size_t; /* sizeof(size_t) = %u */\n", (unsigned int)sizeof(size_t));
#elif HAVE_BASIC_SIZE_T==4
fprintf(outfile, "typedef unsigned int size_t; /* sizeof(size_t) = %u */\n", (unsigned int)sizeof(size_t));
#elif HAVE_BASIC_SIZE_T==6
fprintf(outfile, "typedef unsigned long size_t; /* sizeof(size_t) = %u */\n", (unsigned int)sizeof(size_t));
#elif HAVE_BASIC_SIZE_T==8
fprintf(outfile, "typedef unsigned long long size_t; /* sizeof(size_t) = %u */\n", (unsigned int)sizeof(size_t));
#endif
# if HAVE_BASIC_MODE_T==1
fprintf(outfile, "typedef short mode_t; /* sizeof(mode_t) = %u */\n", (unsigned int)sizeof(mode_t));
#elif HAVE_BASIC_MODE_T==2
fprintf(outfile, "typedef unsigned short mode_t; /* sizeof(mode_t) = %u */\n", (unsigned int)sizeof(mode_t));
#elif HAVE_BASIC_MODE_T==3
fprintf(outfile, "typedef int mode_t; /* sizeof(mode_t) = %u */\n", (unsigned int)sizeof(mode_t));
#elif HAVE_BASIC_MODE_T==4
fprintf(outfile, "typedef unsigned int mode_t; /* sizeof(mode_t) = %u */\n", (unsigned int)sizeof(mode_t));
#elif HAVE_BASIC_MODE_T==5
fprintf(outfile, "typedef long mode_t; /* sizeof(mode_t) = %u */\n", (unsigned int)sizeof(mode_t));
#elif HAVE_BASIC_MODE_T==6
fprintf(outfile, "typedef unsigned long mode_t; /* sizeof(mode_t) = %u */\n", (unsigned int)sizeof(mode_t));
#elif HAVE_BASIC_MODE_T==7
fprintf(outfile, "typedef long long mode_t; /* sizeof(mode_t) = %u */\n", (unsigned int)sizeof(mode_t));
#elif HAVE_BASIC_MODE_T==8
fprintf(outfile, "typedef unsigned long long mode_t; /* sizeof(mode_t) = %u */\n", (unsigned int)sizeof(mode_t));
#endif
# if HAVE_BASIC_PID_T==1
fprintf(outfile, "typedef short pid_t; /* sizeof(pid_t) = %u */\n", (unsigned int)sizeof(pid_t));
#elif HAVE_BASIC_PID_T==2
fprintf(outfile, "typedef unsigned short pid_t; /* sizeof(pid_t) = %u */\n", (unsigned int)sizeof(pid_t));
#elif HAVE_BASIC_PID_T==3
fprintf(outfile, "typedef int pid_t; /* sizeof(pid_t) = %u */\n", (unsigned int)sizeof(pid_t));
#elif HAVE_BASIC_PID_T==4
fprintf(outfile, "typedef unsigned int pid_t; /* sizeof(pid_t) = %u */\n", (unsigned int)sizeof(pid_t));
#elif HAVE_BASIC_PID_T==5
fprintf(outfile, "typedef long pid_t; /* sizeof(pid_t) = %u */\n", (unsigned int)sizeof(pid_t));
#elif HAVE_BASIC_PID_T==6
fprintf(outfile, "typedef unsigned long pid_t; /* sizeof(pid_t) = %u */\n", (unsigned int)sizeof(pid_t));
#elif HAVE_BASIC_PID_T==7
fprintf(outfile, "typedef long long pid_t; /* sizeof(pid_t) = %u */\n", (unsigned int)sizeof(pid_t));
#elif HAVE_BASIC_PID_T==8
fprintf(outfile, "typedef unsigned long long pid_t; /* sizeof(pid_t) = %u */\n", (unsigned int)sizeof(pid_t));
#endif
# if HAVE_BASIC_UID_T==1
fprintf(outfile, "typedef short uid_t; /* sizeof(uid_t) = %u */\n", (unsigned int)sizeof(uid_t));
#elif HAVE_BASIC_UID_T==2
fprintf(outfile, "typedef unsigned short uid_t; /* sizeof(uid_t) = %u */\n", (unsigned int)sizeof(uid_t));
#elif HAVE_BASIC_UID_T==3
fprintf(outfile, "typedef int uid_t; /* sizeof(uid_t) = %u */\n", (unsigned int)sizeof(uid_t));
#elif HAVE_BASIC_UID_T==4
fprintf(outfile, "typedef unsigned int uid_t; /* sizeof(uid_t) = %u */\n", (unsigned int)sizeof(uid_t));
#elif HAVE_BASIC_UID_T==5
fprintf(outfile, "typedef long uid_t; /* sizeof(uid_t) = %u */\n", (unsigned int)sizeof(uid_t));
#elif HAVE_BASIC_UID_T==6
fprintf(outfile, "typedef unsigned long uid_t; /* sizeof(uid_t) = %u */\n", (unsigned int)sizeof(uid_t));
#elif HAVE_BASIC_UID_T==7
fprintf(outfile, "typedef long long uid_t; /* sizeof(uid_t) = %u */\n", (unsigned int)sizeof(uid_t));
#elif HAVE_BASIC_UID_T==8
fprintf(outfile, "typedef unsigned long long uid_t; /* sizeof(uid_t) = %u */\n", (unsigned int)sizeof(uid_t));
#endif
# if HAVE_BASIC_GID_T==1
fprintf(outfile, "typedef short gid_t; /* sizeof(gid_t) = %u */\n", (unsigned int)sizeof(gid_t));
#elif HAVE_BASIC_GID_T==2
fprintf(outfile, "typedef unsigned short gid_t; /* sizeof(gid_t) = %u */\n", (unsigned int)sizeof(gid_t));
#elif HAVE_BASIC_GID_T==3
fprintf(outfile, "typedef int gid_t; /* sizeof(gid_t) = %u */\n", (unsigned int)sizeof(gid_t));
#elif HAVE_BASIC_GID_T==4
fprintf(outfile, "typedef unsigned int gid_t; /* sizeof(gid_t) = %u */\n", (unsigned int)sizeof(gid_t));
#elif HAVE_BASIC_GID_T==5
fprintf(outfile, "typedef long gid_t; /* sizeof(gid_t) = %u */\n", (unsigned int)sizeof(gid_t));
#elif HAVE_BASIC_GID_T==6
fprintf(outfile, "typedef unsigned long gid_t; /* sizeof(gid_t) = %u */\n", (unsigned int)sizeof(gid_t));
#elif HAVE_BASIC_GID_T==7
fprintf(outfile, "typedef long long gid_t; /* sizeof(gid_t) = %u */\n", (unsigned int)sizeof(gid_t));
#elif HAVE_BASIC_GID_T==8
fprintf(outfile, "typedef unsigned long long gid_t; /* sizeof(gid_t) = %u */\n", (unsigned int)sizeof(gid_t));
#endif
# if HAVE_BASIC_TIME_T==1
fprintf(outfile, "typedef short time_t; /* sizeof(time_t) = %u */\n", (unsigned int)sizeof(time_t));
#elif HAVE_BASIC_TIME_T==2
fprintf(outfile, "typedef unsigned short time_t; /* sizeof(time_t) = %u */\n", (unsigned int)sizeof(time_t));
#elif HAVE_BASIC_TIME_T==3
fprintf(outfile, "typedef int time_t; /* sizeof(time_t) = %u */\n", (unsigned int)sizeof(time_t));
#elif HAVE_BASIC_TIME_T==4
fprintf(outfile, "typedef unsigned int time_t; /* sizeof(time_t) = %u */\n", (unsigned int)sizeof(time_t));
#elif HAVE_BASIC_TIME_T==5
fprintf(outfile, "typedef long time_t; /* sizeof(time_t) = %u */\n", (unsigned int)sizeof(time_t));
#elif HAVE_BASIC_TIME_T==6
fprintf(outfile, "typedef unsigned long time_t; /* sizeof(time_t) = %u */\n", (unsigned int)sizeof(time_t));
#elif HAVE_BASIC_TIME_T==7
fprintf(outfile, "typedef long long time_t; /* sizeof(time_t) = %u */\n", (unsigned int)sizeof(time_t));
#elif HAVE_BASIC_TIME_T==8
fprintf(outfile, "typedef unsigned long long time_t; /* sizeof(time_t) = %u */\n", (unsigned int)sizeof(time_t));
#endif
# if HAVE_BASIC_SOCKLEN_T==1
fprintf(outfile, "typedef short socklen_t; /* sizeof(socklen_t) = %u */\n", (unsigned int)sizeof(socklen_t));
#elif HAVE_BASIC_SOCKLEN_T==2
fprintf(outfile, "typedef unsigned short socklen_t; /* sizeof(socklen_t) = %u */\n", (unsigned int)sizeof(socklen_t));
#elif HAVE_BASIC_SOCKLEN_T==3
fprintf(outfile, "typedef int socklen_t; /* sizeof(socklen_t) = %u */\n", (unsigned int)sizeof(socklen_t));
#elif HAVE_BASIC_SOCKLEN_T==4
fprintf(outfile, "typedef unsigned int socklen_t; /* sizeof(socklen_t) = %u */\n", (unsigned int)sizeof(socklen_t));
#elif HAVE_BASIC_SOCKLEN_T==5
fprintf(outfile, "typedef long socklen_t; /* sizeof(socklen_t) = %u */\n", (unsigned int)sizeof(socklen_t));
#elif HAVE_BASIC_SOCKLEN_T==6
fprintf(outfile, "typedef unsigned long socklen_t; /* sizeof(socklen_t) = %u */\n", (unsigned int)sizeof(socklen_t));
#elif HAVE_BASIC_SOCKLEN_T==7
fprintf(outfile, "typedef long long socklen_t; /* sizeof(socklen_t) = %u */\n", (unsigned int)sizeof(socklen_t));
#elif HAVE_BASIC_SOCKLEN_T==8
fprintf(outfile, "typedef unsigned long long socklen_t; /* sizeof(socklen_t) = %u */\n", (unsigned int)sizeof(socklen_t));
#endif
# if HAVE_BASIC_OFF_T==1
fprintf(outfile, "typedef short off_t; /* sizeof(off_t) = %u */\n", (unsigned int)sizeof(off_t));
#elif HAVE_BASIC_OFF_T==2
fprintf(outfile, "typedef unsigned short off_t; /* sizeof(off_t) = %u */\n", (unsigned int)sizeof(off_t));
#elif HAVE_BASIC_OFF_T==3
fprintf(outfile, "typedef int off_t; /* sizeof(off_t) = %u */\n", (unsigned int)sizeof(off_t));
#elif HAVE_BASIC_OFF_T==4
fprintf(outfile, "typedef unsigned int off_t; /* sizeof(off_t) = %u */\n", (unsigned int)sizeof(off_t));
#elif HAVE_BASIC_OFF_T==5
fprintf(outfile, "typedef long off_t; /* sizeof(off_t) = %u */\n", (unsigned int)sizeof(off_t));
#elif HAVE_BASIC_OFF_T==6
fprintf(outfile, "typedef unsigned long off_t; /* sizeof(off_t) = %u */\n", (unsigned int)sizeof(off_t));
#elif HAVE_BASIC_OFF_T==7
fprintf(outfile, "typedef long long off_t; /* sizeof(off_t) = %u */\n", (unsigned int)sizeof(off_t));
#elif HAVE_BASIC_OFF_T==8
fprintf(outfile, "typedef unsigned long long off_t; /* sizeof(off_t) = %u */\n", (unsigned int)sizeof(off_t));
#endif
#if HAVE_TYPE_OFF64 && defined(HAVE_BASIC_OFF64_T) && HAVE_BASIC_OFF64_T
# if HAVE_BASIC_OFF64_T==1
fprintf(outfile, "typedef short off64_t; /* sizeof(off64_t) = %u */\n", (unsigned int)sizeof(off64_t));
#elif HAVE_BASIC_OFF64_T==2
fprintf(outfile, "typedef unsigned short off64_t; /* sizeof(off64_t) = %u */\n", (unsigned int)sizeof(off64_t));
#elif HAVE_BASIC_OFF64_T==3
fprintf(outfile, "typedef int off64_t; /* sizeof(off64_t) = %u */\n", (unsigned int)sizeof(off64_t));
#elif HAVE_BASIC_OFF64_T==4
fprintf(outfile, "typedef unsigned int off64_t; /* sizeof(off64_t) = %u */\n", (unsigned int)sizeof(off64_t));
#elif HAVE_BASIC_OFF64_T==5
fprintf(outfile, "typedef long off64_t; /* sizeof(off64_t) = %u */\n", (unsigned int)sizeof(off64_t));
#elif HAVE_BASIC_OFF64_T==6
fprintf(outfile, "typedef unsigned long off64_t; /* sizeof(off64_t) = %u */\n", (unsigned int)sizeof(off64_t));
#elif HAVE_BASIC_OFF64_T==7
fprintf(outfile, "typedef long long off64_t; /* sizeof(off64_t) = %u */\n", (unsigned int)sizeof(off64_t));
#elif HAVE_BASIC_OFF64_T==8
fprintf(outfile, "typedef unsigned long long off64_t; /* sizeof(off64_t) = %u */\n", (unsigned int)sizeof(off64_t));
#endif
#endif /* defined(HAVE_BASIC_OFF64_T) && HAVE_BASIC_OFF64_T */
# if HAVE_BASIC_DEV_T==1
fprintf(outfile, "typedef short dev_t; /* sizeof(dev_t) = %u */\n", (unsigned int)sizeof(dev_t));
#elif HAVE_BASIC_DEV_T==2
fprintf(outfile, "typedef unsigned short dev_t; /* sizeof(dev_t) = %u */\n", (unsigned int)sizeof(dev_t));
#elif HAVE_BASIC_DEV_T==3
fprintf(outfile, "typedef int dev_t; /* sizeof(dev_t) = %u */\n", (unsigned int)sizeof(dev_t));
#elif HAVE_BASIC_DEV_T==4
fprintf(outfile, "typedef unsigned int dev_t; /* sizeof(dev_t) = %u */\n", (unsigned int)sizeof(dev_t));
#elif HAVE_BASIC_DEV_T==5
fprintf(outfile, "typedef long dev_t; /* sizeof(dev_t) = %u */\n", (unsigned int)sizeof(dev_t));
#elif HAVE_BASIC_DEV_T==6
fprintf(outfile, "typedef unsigned long dev_t; /* sizeof(dev_t) = %u */\n", (unsigned int)sizeof(dev_t));
#elif HAVE_BASIC_DEV_T==7
fprintf(outfile, "typedef long long dev_t; /* sizeof(dev_t) = %u */\n", (unsigned int)sizeof(dev_t));
#elif HAVE_BASIC_DEV_T==8
fprintf(outfile, "typedef unsigned long long dev_t; /* sizeof(dev_t) = %u */\n", (unsigned int)sizeof(dev_t));
#endif
{
struct stat x;
# if HAVE_TYPEOF_ST_INO==1
fprintf(outfile, "typedef short ino_t; /* sizeof(ino_t) = %u */\n", (unsigned int)sizeof(x.st_ino));
#elif HAVE_TYPEOF_ST_INO==2
fprintf(outfile, "typedef unsigned short ino_t; /* sizeof(ino_t) = %u */\n", (unsigned int)sizeof(x.st_ino));
#elif HAVE_TYPEOF_ST_INO==3
fprintf(outfile, "typedef int ino_t; /* sizeof(ino_t) = %u */\n", (unsigned int)sizeof(x.st_ino));
#elif HAVE_TYPEOF_ST_INO==4
fprintf(outfile, "typedef unsigned int ino_t; /* sizeof(ino_t) = %u */\n", (unsigned int)sizeof(x.st_ino));
#elif HAVE_TYPEOF_ST_INO==5
fprintf(outfile, "typedef long ino_t; /* sizeof(ino_t) = %u */\n", (unsigned int)sizeof(x.st_ino));
#elif HAVE_TYPEOF_ST_INO==6
fprintf(outfile, "typedef unsigned long ino_t; /* sizeof(ino_t) = %u */\n", (unsigned int)sizeof(x.st_ino));
#elif HAVE_TYPEOF_ST_INO==7
fprintf(outfile, "typedef long long ino_t; /* sizeof(ino_t) = %u */\n", (unsigned int)sizeof(x.st_ino));
#elif HAVE_TYPEOF_ST_INO==8
fprintf(outfile, "typedef unsigned long long ino_t; /* sizeof(ino_t) = %u */\n", (unsigned int)sizeof(x.st_ino));
#endif
}
{
unsigned short x = 0x100;
if (x == ntohs(0x100)) {
fprintf(outfile, "#define __BYTE_ORDER __BIG_ENDIAN\t/* Motorola ea.*/\n");
} else {
fprintf(outfile, "#define __BYTE_ORDER __LITTLE_ENDIAN\t/* Intel ea.*/\n");
}
}
#include <sys/time.h> /* select(); OpenBSD: struct timespec */
fprintf(outfile, "sizeof(struct timespec) = %u\n", (unsigned int)sizeof(struct timespec));
fprintf(outfile, "\n");
fprintf(outfile, "/* Socat types */\n");
fprintf(outfile, "sizeof(struct diag_dgram) = %u\n", (unsigned int)sizeof(struct diag_dgram));
fprintf(outfile, "((struct diag_dgram *)0)->op-((struct diag_dgram *)0) = %u\n", (unsigned int)((char *)(&((struct diag_dgram *)0)->op)-(char *)((struct diag_dgram *)0)));
fprintf(outfile, "((struct diag_dgram *)0)->now-((struct diag_dgram *)0) = %u\n", (unsigned int)((char *)(&((struct diag_dgram *)0)->now)-(char *)((struct diag_dgram *)0)));
fprintf(outfile, "((struct diag_dgram *)0)->exitcode-((struct diag_dgram *)0) = %u\n", (unsigned int)((char *)(&((struct diag_dgram *)0)->exitcode)-(char *)((struct diag_dgram *)0)));
fprintf(outfile, "((struct diag_dgram *)0)->text-((struct diag_dgram *)0) = %u\n", (unsigned int)((((struct diag_dgram *)0)->text)-(char *)((struct diag_dgram *)0)));
#if _WITH_SOCKET && (_WITH_IP4 || _WITH_IP6)
fprintf(outfile, "\nIP INTERFACES\n");
iffan(outfile);
#endif
#if WITH_VSOCK
vsockan(outfile);
#endif
return 0;
}
#if _WITH_SOCKET && (_WITH_IP4 || _WITH_IP6)
static int iffan(FILE *outfile) {
/* Linux: man 7 netdevice */
/* FreeBSD, NetBSD: man 4 networking */
/* Solaris: man 7 if_tcp */
/* currently we support Linux and a little FreeBSD */
#ifdef SIOCGIFCONF /* not Solaris */
#define IFBUFSIZ 32*sizeof(struct ifreq) /*1024*/
int s;
unsigned char buff[IFBUFSIZ];
struct ifconf ic;
int i;
if ((s = Socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
Warn1("socket(PF_INET, SOCK_DGRAM, IPPROTO_IP): %s", strerror(errno));
return -1;
}
for (i=0; i < IFBUFSIZ; ++i) {
buff[i] = 255;
}
ic.ifc_len = sizeof(buff);
ic.ifc_ifcu.ifcu_buf = (caddr_t)buff;
if (Ioctl(s, SIOCGIFCONF, &ic) < 0) {
Warn3("ioctl(%d, SIOCGIFCONF, %p): %s", s, &ic, strerror(errno));
return -1;
}
for (i = 0; i < ic.ifc_len; i += sizeof(struct ifreq)) {
struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i);
#if 0 || defined(SIOCGIFINDEX) /* not NetBSD, OpenBSD */
struct ifreq ifr;
#endif
#if 0 || defined(SIOCGIFINDEX) /* not NetBSD, OpenBSD */
strcpy(ifr.ifr_name, ifp->ifr_name);
if (Ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
Warn3("ioctl(%d, SIOCGIFINDEX, {\"%s\"}): %s",
s, ifr.ifr_name, strerror(errno));
return 1;
}
#if HAVE_STRUCT_IFREQ_IFR_INDEX
fprintf(outfile, "%2d: %s\n", ifr.ifr_index, ifp->ifr_name);
#elif HAVE_STRUCT_IFREQ_IFR_IFINDEX
fprintf(outfile, "%2d: %s\n", ifr.ifr_ifindex, ifp->ifr_name);
#endif /* HAVE_STRUCT_IFREQ_IFR_INDEX */
#else /* !defined(SIOCGIFINDEX) */
fprintf(outfile, "%2d: %s\n", i/(int)sizeof(struct ifreq), ifp->ifr_name);
#endif /* defined(SIOCGIFINDEX) */
}
Close(s);
#endif /* defined(SIOCGIFCONF) */
return 0;
}
#endif /* _WITH_SOCKET */
#if WITH_VSOCK
static int vsockan(FILE *outfile) {
unsigned int cid;
int vsock;
if (Getuid() != 0) {
return 1;
}
if ((vsock = Open("/dev/vsock", O_RDONLY, 0)) < 0 ) {
Warn1("open(\"/dev/vsock\", ...): %s", strerror(errno));
return -1;
} else if (Ioctl(vsock, IOCTL_VM_SOCKETS_GET_LOCAL_CID, &cid) < 0) {
Warn2("ioctl(%d, IOCTL_VM_SOCKETS_GET_LOCAL_CID, ...): %s",
vsock, strerror(errno));
return -1;
} else {
Notice1("VSOCK CID=%u", cid);
fprintf(outfile, "\nVSOCK_CID = %u\n", cid);
}
if (vsock >= 0) {
Close(vsock);
}
return 0;
}
#endif /* WITH_VSOCK */

10
hostan.h Normal file
View File

@@ -0,0 +1,10 @@
/* source: hostan.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __hostan_h_included
#define __hostan_h_included 1
extern int hostan(FILE *outfile);
#endif /* !defined(__hostan_h_included) */

250
install-sh Executable file
View File

@@ -0,0 +1,250 @@
#! /bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5 (mit/util/scripts/install.sh).
#
# Copyright 1991 by the Massachusetts Institute of Technology
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that
# the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation, and that the name of M.I.T. not be used in advertising or
# publicity pertaining to distribution of the software without specific,
# written prior permission. M.I.T. makes no representations about the
# suitability of this software for any purpose. It is provided "as is"
# without express or implied warranty.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch. It can only install one file at a time, a restriction
# shared with many OS's install programs.
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
transformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
while [ x"$1" != x ]; do
case $1 in
-c) instcmd="$cpprog"
shift
continue;;
-d) dir_arg=true
shift
continue;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
-s) stripcmd="$stripprog"
shift
continue;;
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
*) if [ x"$src" = x ]
then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
esac
done
if [ x"$src" = x ]
then
echo "install: no input file specified"
exit 1
else
true
fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d $dst ]; then
instcmd=:
else
instcmd=mkdir
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f $src -o -d $src ]
then
true
else
echo "install: $src does not exist"
exit 1
fi
if [ x"$dst" = x ]
then
echo "install: no destination specified"
exit 1
else
true
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d $dst ]
then
dst="$dst"/`basename $src`
else
true
fi
fi
## this sed command emulates the dirname command
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "${pathcomp}" ] ;
then
$mkdirprog "${pathcomp}"
else
true
fi
pathcomp="${pathcomp}/"
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd $dst &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
else
# If we're going to rename the final executable, determine the name now.
if [ x"$transformarg" = x ]
then
dstfile=`basename $dst`
else
dstfile=`basename $dst $transformbasename |
sed $transformarg`$transformbasename
fi
# don't allow the sed command to completely eliminate the filename
if [ x"$dstfile" = x ]
then
dstfile=`basename $dst`
else
true
fi
# Make a temp file name in the proper directory.
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$doit $instcmd $src $dsttmp &&
trap "rm -f ${dsttmp}" 0 &&
# and set any options; do chmod last to preserve setuid bits
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
# Now rename the file to the real destination.
$doit $rmcmd -f $dstdir/$dstfile &&
$doit $mvcmd $dsttmp $dstdir/$dstfile
fi &&
exit 0

73
mail.sh Executable file
View File

@@ -0,0 +1,73 @@
#! /bin/sh
# source: mail.sh
# Copyright Gerhard Rieger and contributors (see file CHANGES)
# Published under the GNU General Public License V.2, see file COPYING
#set -vx
# This is an example for a shell script that can be fed to socat with exec.
# Its clue is that it does not use stdin/stdout for communication with socat,
# so you may feed the mail message via stdin to the script. The message should
# contain appropriate mail headers without continuation lines.
# socat establishes the connection to the SMTP server; the script performs the
# SMTP dialog and afterwards transfers the message body to the server.
# Lines with only a dot are not permitted - use two dots as escape.
# This script supports multiline answers from server, but not much more yet.
# Usage: cat message.txt |socat exec:"mail.sh target@domain.com",fdin=3,fdout=4 tcp:mail.relay.org:25,crlf
while [ "$1" ]; do
case "$1" in
-f) shift; mailfrom="$1"; shift;;
*) break;;
esac
done
rcptto="$1"
[ -z "$1" ] && rcptto="root@loopback"
#server=$(expr "$rcptto" : '[^@]*@\(.*\)')
[ -z "$mailfrom" ] && mailfrom="$USER@$(hostname)"
# this function waits for a complete server message, checks if its status
# is in the permitted range (terminates session if not), and returns.
mail_chat () {
local cmd="$1"
local errlevel="$2"; [ -z "$errlevel" ] && errlevel=300
if [ "$cmd" ]; then echo "> $cmd" >&2; fi
if [ -n "$cmd" ]; then echo "$cmd" >&4; fi
while read status message <&3;
(
case "$status" in
[0-9][0-9][0-9]-*) exit 0;;
[0-9][0-9][0-9]*) exit 1;;
*) exit 1;;
esac
)
do :; done
if [ -z "$status" ]; then echo smtp connection failed >&2; exit; fi
echo "< $status $message" >&2
if [ "$status" -ge "$errlevel" ]; then
echo $message >&2
echo "QUIT" >&4; exit 1
fi
}
# expect server greeting
mail_chat
mail_chat "HELO $(hostname)"
mail_chat "MAIL FROM: $mailfrom"
mail_chat "RCPT TO: $rcptto"
mail_chat "DATA" 400
while read l; do echo "$l" >&4; done
mail_chat "."
mail_chat "QUIT"
exit 0

25
mytypes.h Normal file
View File

@@ -0,0 +1,25 @@
/* source: mytypes.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __mytypes_h_included
#define __mytypes_h_included 1
/* some types and macros I miss in C89 */
#ifndef HAVE_TYPE_BOOL
# undef bool
typedef enum { false, true } bool;
#endif
#ifndef Min
#define Min(x,y) ((x)<=(y)?(x):(y))
#endif
#ifndef Max
#define Max(x,y) ((x)>=(y)?(x):(y))
#endif
#define SOCKADDR_MAX UNIX_PATH_MAX
#endif /* __mytypes_h_included */

271
nestlex.c Normal file
View File

@@ -0,0 +1,271 @@
/* source: nestlex.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* a function for lexical scanning of nested character patterns */
#include "config.h"
#include "mytypes.h"
#include "sysincludes.h"
static int _nestlex(const char **addr,
char **token,
ptrdiff_t *len,
const char *ends[],
const char *hquotes[],
const char *squotes[],
const char *nests[],
bool dropquotes,
bool c_esc,
bool html_esc
);
/* sub: scan a string and copy its value to output string
end scanning when an unescaped, unnested string from ends array is found
does not copy the end pattern
does not write a trailing \0 to token
allows escaping with \ and quoting (\ and quotes are removed)
allows nesting with div. parens
returns -1 if out string was too small
returns 1 if addr ended unexpectedly
returns 0 if token could be extracted successfully
*/
int nestlex(const char **addr, /* input string; aft points to end token */
char **token, /* output token; aft points to first unwritten
char (caller might want to set it to \0) */
size_t *len, /* remaining bytes in token space (incl. \0) */
const char *ends[], /* list of end strings */
const char *hquotes[],/* list of strings that quote (hard qu.) */
const char *squotes[],/* list of strings that quote softly */
const char *nests[],/* list of strings that start nesting;
every second one is matching end */
bool dropquotes, /* drop the outermost quotes */
bool c_esc, /* solve C char escapes: \n \t \0 etc */
bool html_esc /* solve HTML char escapes: %0d %08 etc */
) {
return
_nestlex(addr, token, (ptrdiff_t *)len, ends, hquotes, squotes, nests,
dropquotes, c_esc, html_esc);
}
static int _nestlex(const char **addr,
char **token,
ptrdiff_t *len,
const char *ends[],
const char *hquotes[],
const char *squotes[],
const char *nests[],
bool dropquotes,
bool c_esc,
bool html_esc
) {
const char *in = *addr; /* pointer into input string */
const char **endx; /* loops over end patterns */
const char **quotx; /* loops over quote patterns */
const char **nestx; /* loops over nest patterns */
char *out = *token; /* pointer into output token */
char c;
int i;
int result;
while (true) {
/* is this end of input string? */
if (*in == 0) {
break; /* end of string */
}
/* first check the end patterns (e.g. for ']') */
endx = ends; i = 0;
while (*endx) {
if (!strncmp(in, *endx, strlen(*endx))) {
/* this end pattern matches */
*addr = in;
*token = out;
return 0;
}
++endx;
}
/* check for hard quoting pattern */
quotx = hquotes;
while (hquotes && *quotx) {
if (!strncmp(in, *quotx, strlen(*quotx))) {
/* this quote pattern matches */
const char *endnest[2];
if (dropquotes) {
/* we strip this quote */
in += strlen(*quotx);
} else {
for (i = strlen(*quotx); i > 0; --i) {
*out++ = *in++;
if (--*len <= 0) { *addr = in; *token = out; return -1; }
}
}
/* we call _nestlex recursively */
endnest[0] = *quotx;
endnest[1] = NULL;
result =
_nestlex(&in, &out, len, endnest, NULL/*hquotes*/,
NULL/*squotes*/, NULL/*nests*/,
false, c_esc, html_esc);
if (result == 0 && dropquotes) {
/* we strip this quote */
in += strlen(*quotx);
} else if (result < 0) {
*addr = in; *token = out; return result;
} else {
/* we copy the trailing quote */
for (i = strlen(*quotx); i > 0; --i) {
*out++ = *in++;
if (--*len <= 0) { *addr = in; *token = out; return -1; }
}
}
break;
}
++quotx;
}
if (hquotes && *quotx != NULL) {
/* there was a quote; string might continue with hard quote */
continue;
}
/* check for soft quoting pattern */
quotx = squotes;
while (squotes && *quotx) {
if (!strncmp(in, *quotx, strlen(*quotx))) {
/* this quote pattern matches */
/* we strip this quote */
/* we call _nestlex recursively */
const char *endnest[2];
if (dropquotes) {
/* we strip this quote */
in += strlen(*quotx);
} else {
for (i = strlen(*quotx); i > 0; --i) {
*out++ = *in++;
if (--*len <= 0) { *addr = in; *token = out; return -1; }
}
}
endnest[0] = *quotx;
endnest[1] = NULL;
result =
_nestlex(&in, &out, len, endnest, hquotes,
squotes, nests,
false, c_esc, html_esc);
if (result == 0 && dropquotes) {
/* we strip the trailing quote */
if (!in[0] || strncmp(in, *quotx, strlen(*quotx))) return 1;
in += strlen(*quotx);
} else if (result < 0) {
*addr = in; *token = out; return result;
} else {
/* we copy the trailing quote */
for (i = strlen(*quotx); i > 0; --i) {
*out++ = *in++;
if (--*len <= 0) { *addr = in; *token = out; return -1; }
}
}
break;
}
++quotx;
}
if (squotes && *quotx != NULL) {
/* there was a soft quote; string might continue with any quote */
continue;
}
/* check patterns that start a nested clause */
nestx = nests; i = 0;
while (nests && *nestx) {
if (!strncmp(in, *nestx, strlen(*nestx))) {
/* this nest pattern matches */
const char *endnest[2];
endnest[0] = nestx[1];
endnest[1] = NULL;
for (i = strlen(nestx[1]); i > 0; --i) {
*out++ = *in++;
if (--*len <= 0) { *addr = in; *token = out; return -1; }
}
result =
_nestlex(&in, &out, len, endnest, hquotes, squotes, nests,
false, c_esc, html_esc);
if (result == 0) {
/* copy endnest */
i = strlen(nestx[1]); while (i > 0) {
*out++ = *in++;
if (--*len <= 0) {
*addr = in;
*token = out;
return -1;
}
--i;
}
} else if (result < 0) {
*addr = in; *token = out; return result;
}
break;
}
nestx += 2; /* skip matching end pattern in table */
}
if (nests && *nestx) {
/* we handled a nested expression, continue loop */
continue;
}
/* "normal" data, possibly escaped */
c = *in++;
if (c == '\\') {
/* found a plain \ escaped part */
c = *in++;
if (c == 0) { /* Warn("trailing '\\'");*/ break; }
if (c_esc) { /* solve C char escapes: \n \t \0 etc */
switch (c) {
case '0': c = '\0'; break;
case 'a': c = '\a'; break;
case 'b': c = '\b'; break;
case 'f': c = '\f'; break;
case 'n': c = '\n'; break;
case 'r': c = '\r'; break;
case 't': c = '\t'; break;
case 'v': c = '\v'; break;
#if LATER
case 'x': !!! 1 to 2 hex digits; break;
case 'u': !!! 4 hex digits?; break;
case 'U': !!! 8 hex digits?; break;
#endif
default: break;
}
}
*out++ = c;
--*len;
if (*len <= 0) {
*addr = in;
*token = out;
return -1; /* output overflow */
}
continue;
}
/* just a simple char */
*out++ = c;
--*len;
if (*len <= 0) {
*addr = in;
*token = out;
return -1; /* output overflow */
}
}
/* never come here? */
*addr = in;
*token = out;
return 0; /* OK */
}

23
nestlex.h Normal file
View File

@@ -0,0 +1,23 @@
/* source: nestlex.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __nestlex_h_included
#define __nestlex_h_included 1
extern
int nestlex(const char **addr, /* input string; aft points to end token */
char **token, /* output token; aft points to first unwritten
char (caller might want to set it to \0) */
size_t *len, /* remaining bytes in token space (incl. \0) */
const char *ends[], /* list of end strings */
const char *hquotes[],/* list of strings that quote (hard qu.) */
const char *squotes[],/* list of strings that quote softly */
const char *nests[],/* list of strings that start nesting;
every second one is matching end */
bool dropquotes, /* drop the outermost quotes */
bool c_esc, /* solve C char escapes: \n \t \0 etc */
bool html_esc /* solve HTML char escapes: %0d %08 etc */
);
#endif /* !defined(__nestlex_h_included) */

192
procan-cdefs.c Normal file
View File

@@ -0,0 +1,192 @@
/* source: procan-cdefs.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* a function that prints compile time parameters */
/* the set of parameters is only a small subset of the available defines and
will be extended on demand */
#include "xiosysincludes.h"
#include "mytypes.h"
#include "compat.h"
#include "error.h"
#include "procan.h"
int procan_cdefs(FILE *outfile) {
/* basic C/system constants */
#ifdef FD_SETSIZE
fprintf(outfile, "#define FD_SETSIZE %u\n", FD_SETSIZE);
#endif
#ifdef NFDBITS
fprintf(outfile, "#define NFDBITS %d\n", (int)NFDBITS);
#endif
#ifdef O_RDONLY
fprintf(outfile, "#define O_RDONLY %u\n", O_RDONLY);
#endif
#ifdef O_WRONLY
fprintf(outfile, "#define O_WRONLY %u\n", O_WRONLY);
#endif
#ifdef O_RDWR
fprintf(outfile, "#define O_RDWR %u\n", O_RDWR);
#endif
#ifdef SHUT_RD
fprintf(outfile, "#define SHUT_RD %u\n", SHUT_RD);
#endif
#ifdef SHUT_WR
fprintf(outfile, "#define SHUT_WR %u\n", SHUT_WR);
#endif
#ifdef SHUT_RDWR
fprintf(outfile, "#define SHUT_RDWR %u\n", SHUT_RDWR);
#endif
/* Compile time controls */
#ifdef _FILE_OFFSET_BITS
fprintf(outfile, "#define _FILE_OFFSET_BITS %u\n", _FILE_OFFSET_BITS);
#endif
#ifdef _LARGE_FILES
fprintf(outfile, "#define _LARGE_FILES %u\n", _LARGE_FILES);
#endif
/* termios constants */
#ifdef CRDLY
fprintf(outfile, "#define CRDLY 0%011o\n", CRDLY);
#endif
#ifdef CR0
fprintf(outfile, "#define CR0 0%011o\n", CR0);
#endif
#ifdef CR1
fprintf(outfile, "#define CR1 0%011o\n", CR1);
#endif
#ifdef CR2
fprintf(outfile, "#define CR2 0%011o\n", CR2);
#endif
#ifdef CR3
fprintf(outfile, "#define CR3 0%011o\n", CR3);
#endif
#ifdef TABDLY
fprintf(outfile, "#define TABDLY 0%011o\n", TABDLY);
#endif
#ifdef TAB0
fprintf(outfile, "#define TAB0 0%011o\n", TAB0);
#endif
#ifdef TAB1
fprintf(outfile, "#define TAB1 0%011o\n", TAB1);
#endif
#ifdef TAB2
fprintf(outfile, "#define TAB2 0%011o\n", TAB2);
#endif
#ifdef TAB3
fprintf(outfile, "#define TAB3 0%011o\n", TAB3);
#endif
#ifdef CSIZE
fprintf(outfile, "#define CSIZE 0%011o\n", CSIZE);
#endif
#ifdef TIOCEXCL
fprintf(outfile, "#define TIOCEXCL 0x%lx\n", (unsigned long)TIOCEXCL);
#endif
/* stdio constants */
#ifdef FOPEN_MAX
fprintf(outfile, "#define FOPEN_MAX %u\n", FOPEN_MAX);
#endif
/* socket constants */
#ifdef PF_UNSPEC
fprintf(outfile, "#define PF_UNSPEC %d\n", PF_UNSPEC);
#endif
#ifdef PF_UNIX
fprintf(outfile, "#define PF_UNIX %d\n", PF_UNIX);
#elif defined(PF_LOCAL)
fprintf(outfile, "#define PF_LOCAL %d\n", PF_LOCAL);
#endif
#ifdef PF_INET
fprintf(outfile, "#define PF_INET %d\n", PF_INET);
#endif
#ifdef PF_INET6
fprintf(outfile, "#define PF_INET6 %d\n", PF_INET6);
#endif
#ifdef PF_APPLETALK
fprintf(outfile, "#define PF_APPLETALK %d\n", PF_APPLETALK);
#endif
#ifdef PF_PACKET
fprintf(outfile, "#define PF_PACKET %d\n", PF_PACKET);
#endif
#ifdef PF_VSOCK
fprintf(outfile, "#define PF_VSOCK %d\n", PF_VSOCK);
#endif
#ifdef SOCK_STREAM
fprintf(outfile, "#define SOCK_STREAM %d\n", SOCK_STREAM);
#endif
#ifdef SOCK_DGRAM
fprintf(outfile, "#define SOCK_DGRAM %d\n", SOCK_DGRAM);
#endif
#ifdef SOCK_RAW
fprintf(outfile, "#define SOCK_RAW %d\n", SOCK_RAW);
#endif
#ifdef SOCK_SEQPACKET
fprintf(outfile, "#define SOCK_SEQPACKET %d\n", SOCK_SEQPACKET);
#endif
#ifdef SOCK_PACKET
fprintf(outfile, "#define SOCK_PACKET %d\n", SOCK_PACKET);
#endif
#ifdef IPPROTO_IP
fprintf(outfile, "#define IPPROTO_IP %d\n", IPPROTO_IP);
#endif
#ifdef IPPROTO_TCP
fprintf(outfile, "#define IPPROTO_TCP %d\n", IPPROTO_TCP);
#endif
#ifdef IPPROTO_UDP
fprintf(outfile, "#define IPPROTO_UDP %d\n", IPPROTO_UDP);
#endif
#ifdef IPPROTO_DCCP
fprintf(outfile, "#define IPPROTO_DCCP %d\n", IPPROTO_DCCP);
#endif
#ifdef IPPROTO_SCTP
fprintf(outfile, "#define IPPROTO_SCTP %d\n", IPPROTO_SCTP);
#endif
#ifdef IPPROTO_UDPLITE
fprintf(outfile, "#define IPPROTO_UDPLITE %d\n", IPPROTO_UDPLITE);
#endif
#ifdef IPPROTO_RAW
fprintf(outfile, "#define IPPROTO_RAW %d\n", IPPROTO_RAW);
#endif
#ifdef SOL_SOCKET
fprintf(outfile, "#define SOL_SOCKET 0x%x\n", SOL_SOCKET);
#endif
#ifdef SOL_PACKET
fprintf(outfile, "#define SOL_PACKET 0x%x\n", SOL_PACKET);
#endif
#ifdef SOL_IP
fprintf(outfile, "#define SOL_IP 0x%x\n", SOL_IP);
#endif
#ifdef SOL_IPV6
fprintf(outfile, "#define SOL_IPV6 0x%x\n", SOL_IPV6);
#endif
#ifdef SOL_TCP
fprintf(outfile, "#define SOL_TCP 0x%x\n", SOL_TCP);
#endif
#ifdef SOL_UDP
fprintf(outfile, "#define SOL_UDP 0x%x\n", SOL_UDP);
#endif
#ifdef SOL_SCTP
fprintf(outfile, "#define SOL_SCTP 0x%x\n", SOL_SCTP);
#endif
#ifdef SOL_DCCP
fprintf(outfile, "#define SOL_DCCP 0x%x\n", SOL_DCCP);
#endif
#ifdef SO_PROTOCOL
fprintf(outfile, "#define SO_PROTOCOL %d\n", SO_PROTOCOL);
#endif
#ifdef SO_PROTOTYPE
fprintf(outfile, "#define SO_PROTOTYPE %d\n", SO_PROTOTYPE);
#endif
#ifdef SO_REUSEADDR
fprintf(outfile, "#define SO_REUSEADDR %d\n", SO_REUSEADDR);
#endif
#ifdef TCP_MAXSEG
fprintf(outfile, "#define TCP_MAXSEG %d\n", TCP_MAXSEG);
#endif
return 0;
}

342
procan.c Normal file
View File

@@ -0,0 +1,342 @@
/* source: procan.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* the subroutine procan makes a "PROCess ANalysis". It gathers information
about the process environment it is running in without modifying its state
(almost).
*/
#include "xiosysincludes.h"
#include "mytypes.h"
#include "compat.h"
#include "error.h"
#include "sycls.h"
#include "sysutils.h"
#include "sched.h"
#include "filan.h"
#include <sys/resource.h> /* RLIMIT_CPU ... */
#include <dirent.h> /* opendir() readdir() closedir() */
#include "procan.h"
/* Search dir recursively for matching device file.
Returns 0 on success;
returns -1 when it failed to find the device file. */
int find_devpath(
char *dirname,
unsigned int major,
unsigned int minor,
char *devname)
{
DIR *dirp;
struct dirent *dirent;
char devpath[PATH_MAX];
int rc;
/* Pass 1: search dir flatly for this device entry */
dirp = opendir(dirname);
if (dirp == NULL) {
Warn2("failed to open dir \"%s\": %s", dirname, strerror(errno));
return -1;
}
while ((errno = 0) || (dirent = readdir(dirp))) {
struct stat statbuf;
#if HAVE_DIRENT_D_TYPE
if (dirent->d_type != DT_CHR && dirent->d_type != DT_UNKNOWN)
continue;
#endif
snprintf(devpath, PATH_MAX, "%s/%s", dirname, dirent->d_name);
if (Stat(devpath, &statbuf) < 0) {
Warn2("failed to stat entry \"%s\": %s", devpath, strerror(errno));
continue;
}
if ((statbuf.st_mode & S_IFMT) != S_IFCHR)
continue;
if ((statbuf.st_rdev >> 8) == major &&
(statbuf.st_rdev & 0xff) == minor) {
strcpy(devname, devpath);
return 0;
}
continue;
}
closedir(dirp);
if (errno != 0) {
Warn2("failed to read dir \"%s\": %s", dirname, strerror(errno));
snprintf(devname, PATH_MAX, "device %u, %u", major, minor);
}
/* Pass 2: search sub dirs */
dirp = opendir(dirname);
if (dirp == NULL) {
Warn2("failed to open dir \"%s\": %s", dirname, strerror(errno));
return -1;
}
while ((errno = 0) || (dirent = readdir(dirp))) {
char dirpath[PATH_MAX];
#if HAVE_DIRENT_D_TYPE
if (dirent->d_type != DT_DIR)
continue;
#else /* Solaris */
{
struct stat statbuf;
if (Stat(dirent->d_name, &statbuf) < 0)
continue;
if ((statbuf.st_mode & S_IFMT) != S_IFDIR)
continue;
}
#endif
if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, ".."))
continue;
snprintf(dirpath, PATH_MAX, "%s/%s", dirname, dirent->d_name);
rc = find_devpath(dirpath, major, minor, devname);
if (rc == 0) {
return 0;
}
}
closedir(dirp);
if (dirent == NULL) {
return 1;
}
return 0;
}
/* Tries to determine the name of the controlling terminal.
Returns 0 on success, the name in cttyname;
returns 1 when only the device numbers are in cttyname;
returns -1 when it failed to determine ctty. */
static int controlling_term(
FILE *outfile)
{
char cttypath[PATH_MAX+1];
int rc;
{ /* On Linux this just gives "/dev/tty" */
char s[L_ctermid+1];
fprintf(outfile, "controlling terminal by ctermid(): \"%s\"\n", ctermid(s));
}
{ /* Check if there is a controlling terminal */
int fd;
if ((fd = Open("/dev/tty", O_NOCTTY, 0)) >= 0)
/* On Linux this just gives "/dev/tty" */
fprintf(outfile, "controlling terminal by /dev/tty, ttyname(): \"%s\"\n", Ttyname(fd));
else
fprintf(outfile, "controlling terminal by /dev/tty, ttyname(): (none)\n");
}
#if HAVE_PROC_DIR
do { /* Linux: derive ctty from info in /proc */
const char procpath[] = "/proc/self/stat";
FILE *procstat;
unsigned int dev;
int n = 0;
unsigned int maj, min;
/* Linux: get device ids from /proc */
if ((procstat = fopen(procpath, "r")) == NULL) {
Warn1("failed to open \"%s\" for process info", procpath);
rc = -1;
break;
}
n = fscanf(procstat, "%*s %*s %*s %*s %*s %*s %u", &dev);
if (n != 1) {
Warn1("failed to read ctty info from \"%s\"", procpath);
rc = -1;
break;
}
maj = (dev>>8)&0xff;
min = ((dev>>12)&0xfff00)|(dev&0xff);
rc = find_devpath("/dev" /* _PATH_DEV has trailing "/" */, maj, min, cttypath);
if (rc < 0) {
snprintf(cttypath, PATH_MAX, "device %u, %u", maj, min);
rc = 1;
break;
}
rc = 0;
} while (false);
#else /* !HAVE_PROC_DIR */
rc = -1;
#endif /* !HAVE_PROC_DIR */
if (rc >= 0)
fprintf(outfile, "controlling terminal by /proc/<pid>/: \"%s\"\n", cttypath);
else
fprintf(outfile, "controlling terminal by /proc/<pid>/: (none)\n");
return 0;
}
int procan(FILE *outfile) {
/*filan(0, outfile);*/
fprintf(outfile, "process id = "F_pid"\n", Getpid());
fprintf(outfile, "process parent id = "F_pid"\n", Getppid());
controlling_term(outfile);
fprintf(outfile, "process group id = "F_pid"\n", Getpgrp());
#if HAVE_GETSID
fprintf(outfile, "process session id = "F_pid"\n", Getsid(0));
#endif
fprintf(outfile, "process group id if fg process / stdin = "F_pid"\n", Tcgetpgrp(0));
fprintf(outfile, "process group id if fg process / stdout = "F_pid"\n", Tcgetpgrp(1));
fprintf(outfile, "process group id if fg process / stderr = "F_pid"\n", Tcgetpgrp(2));
/* process owner, groups */
fprintf(outfile, "user id = "F_uid"\n", Getuid());
fprintf(outfile, "effective user id = "F_uid"\n", Geteuid());
fprintf(outfile, "group id = "F_gid"\n", Getgid());
fprintf(outfile, "effective group id = "F_gid"\n", Getegid());
/* Simple process features */
fprintf(outfile, "\n");
{
mode_t mask;
#if LATER
char procpath[PATH_MAX];
sprintf(procpath, "/proc/"F_pid"/status", Getpid());
if (Stat()) {
} else
#endif
{
mask = Umask(0066);
Umask(mask);
}
fprintf(outfile, "umask = "F_mode"\n", mask);
}
{
struct rlimit rlim;
fprintf(outfile, "\n/* Resource limits */\n");
fprintf(outfile, "resource current maximum\n");
if (getrlimit(RLIMIT_CPU, &rlim) < 0) {
Warn2("getrlimit(RLIMIT_CPU, %p): %s", &rlim, strerror(errno));
} else {
fprintf(outfile,
"cpu time (seconds) %24"F_rlim_max"%24"F_rlim_max"\n",
rlim.rlim_cur, rlim.rlim_max);
}
if (getrlimit(RLIMIT_FSIZE, &rlim) < 0) {
Warn2("getrlimit(RLIMIT_FSIZE, %p): %s", &rlim, strerror(errno));
} else {
fprintf(outfile,
"file size (blocks) %24"F_rlim_max"%24"F_rlim_max"\n",
rlim.rlim_cur, rlim.rlim_max);
}
if (getrlimit(RLIMIT_DATA, &rlim) < 0) {
Warn2("getrlimit(RLIMIT_DATA, %p): %s", &rlim, strerror(errno));
} else {
fprintf(outfile,
"data seg size (kbytes) %24"F_rlim_max"%24"F_rlim_max"\n",
rlim.rlim_cur, rlim.rlim_max);
}
if (getrlimit(RLIMIT_STACK, &rlim) < 0) {
Warn2("getrlimit(RLIMIT_STACK, %p): %s", &rlim, strerror(errno));
} else {
fprintf(outfile,
"stack size (blocks) %24"F_rlim_max"%24"F_rlim_max"\n",
rlim.rlim_cur, rlim.rlim_max);
}
if (getrlimit(RLIMIT_CORE, &rlim) < 0) {
Warn2("getrlimit(RLIMIT_CORE, %p): %s", &rlim, strerror(errno));
} else {
fprintf(outfile,
"core file size (blocks) %24"F_rlim_max"%24"F_rlim_max"\n",
rlim.rlim_cur, rlim.rlim_max);
}
#ifdef RLIMIT_RSS /* Linux, AIX; not Cygwin */
if (getrlimit(RLIMIT_RSS, &rlim) < 0) {
Warn2("getrlimit(RLIMIT_RSS, %p): %s", &rlim, strerror(errno));
} else {
fprintf(outfile,
"max resident set size %24"F_rlim_max"%24"F_rlim_max"\n",
rlim.rlim_cur, rlim.rlim_max);
}
#endif
#ifdef RLIMIT_NPROC /* Linux, not AIX, Cygwin */
if (getrlimit(RLIMIT_NPROC, &rlim) < 0) {
Warn2("getrlimit(RLIMIT_NPROC, %p): %s", &rlim, strerror(errno));
} else {
fprintf(outfile,
"max user processes %24"F_rlim_max"%24"F_rlim_max"\n",
rlim.rlim_cur, rlim.rlim_max);
}
#endif
#ifdef RLIMIT_NOFILE /* not AIX 4.1 */
if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
Warn2("getrlimit(RLIMIT_NOFILE, %p): %s", &rlim, strerror(errno));
} else {
fprintf(outfile,
"open files %24"F_rlim_max"%24"F_rlim_max"\n",
rlim.rlim_cur, rlim.rlim_max);
}
#endif
#ifdef RLIMIT_MEMLOCK /* Linux, not AIX, Cygwin */
if (getrlimit(RLIMIT_MEMLOCK, &rlim) < 0) {
Warn2("getrlimit(RLIMIT_MEMLOCK, %p): %s", &rlim, strerror(errno));
} else {
fprintf(outfile,
"max locked-in-memory\n address space %24"F_rlim_max"%24"F_rlim_max"\n",
rlim.rlim_cur, rlim.rlim_max);
}
#endif
#ifdef RLIMIT_AS
if (getrlimit(RLIMIT_AS, &rlim) < 0) {
Warn2("getrlimit(RLIMIT_AS, %p): %s", &rlim, strerror(errno));
} else {
fprintf(outfile,
"virtual memory (kbytes) %24"F_rlim_max"%24"F_rlim_max"\n",
rlim.rlim_cur, rlim.rlim_max);
}
#endif
fputc('\n', outfile);
}
#ifdef CC
fprintf(outfile, "// CC: "CC"\n");
#endif
#ifdef __STDC_VERSION__
fprintf(outfile, "#define __STDC_VERSION__ %ld\n", __STDC_VERSION__);
#endif
#ifdef SIZE_MAX
fprintf(outfile, "SIZE_MAX = "F_Zu" /* maximum value of size_t */\n", SIZE_MAX);
#endif
#ifdef P_tmpdir
fprintf(outfile, "P_tmpdir = \"%s\"\n", P_tmpdir);
#endif
#ifdef L_tmpnam
fprintf(outfile, "L_tmpnam = %u\n", L_tmpnam);
#endif
#ifdef TMP_MAX
fprintf(outfile, "TMP_MAX = %d\n", TMP_MAX);
#endif
#ifdef FD_SETSIZE
fprintf(outfile, "FD_SETSIZE = %d /* maximum number of FDs for select() */\n", FD_SETSIZE);
#endif
#ifdef PIPE_BUF
fprintf(outfile, "PIPE_BUF = %-24d\n", PIPE_BUF);
#endif
/* Name spaces */
{
char path[PATH_MAX];
char link[PATH_MAX];
snprintf(path, sizeof(path)-1, "/proc/"F_pid"/ns/net", getpid());
if (readlink(path, link, sizeof(link)-1) >= 0) {
fprintf(outfile, "Network namespace: %s", link);
}
}
/* file descriptors */
/* what was this for?? */
/*Sleep(1);*/
return 0;
}

11
procan.h Normal file
View File

@@ -0,0 +1,11 @@
/* source: procan.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __procan_h_included
#define __procan_h_included 1
extern int procan(FILE *outfile);
extern int procan_cdefs(FILE *outfile);
#endif /* !defined(__procan_h_included) */

102
procan_main.c Normal file
View File

@@ -0,0 +1,102 @@
/* source: procan_main.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
const char copyright[] = "procan by Gerhard Rieger and contributors - send bug reports to socat@dest-unreach.org";
#include <signal.h> /* sig_atomic_t for error.h */
#include <time.h> /* struct timespec for error.h */
#include <stdlib.h> /* strtoul() */
#include <string.h>
#include <stdio.h>
#include "config.h"
#if HAVE_SYS_SELECT_H
#include <sys/select.h> /* select(), fdset on FreeBSD */
#endif
#include "mytypes.h"
#include "error.h"
#include "procan.h"
#include "hostan.h"
#define WITH_HELP 1
static void procan_usage(FILE *fd);
int main(int argc, const char *argv[]) {
const char **arg1;
#if 0
unsigned int n = 1024; /* this is default on my Linux */
#endif
diag_set('p', strchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]);
arg1 = argv+1; --argc;
while (arg1[0] && (arg1[0][0] == '-')) {
switch (arg1[0][1]) {
#if WITH_HELP
case '?': case 'h': procan_usage(stdout); exit(0);
#endif /* WITH_HELP */
case 'c': procan_cdefs(stdout); exit(0);
#if LATER
case 'V': procan_version(stdout); exit(0);
case 'l': diag_set(arg1[0][2], &arg1[0][3]); break;
case 'd': diag_set('d', NULL); break;
#endif
#if 0
case 'n': n = strtoul(&arg1[0][2], NULL, 0); break;
#endif
case '\0': break;
default:
diag_set_int('e', E_FATAL);
Error1("unknown option \"%s\"", arg1[0]);
#if WITH_HELP
procan_usage(stderr);
#endif
exit(1);
}
if (arg1[0][1] == '\0')
break;
++arg1; --argc;
}
if (argc != 0) {
Error1("%d superfluous arguments", argc);
#if WITH_HELP
procan_usage(stderr);
#endif
exit(1);
}
procan(stdout);
hostan(stdout);
return 0;
}
#if WITH_HELP
static void procan_usage(FILE *fd) {
fputs(copyright, fd); fputc('\n', fd);
fputs("Analyze system parameters of process\n", fd);
fputs("Usage:\n", fd);
fputs("procan [options]\n", fd);
fputs(" options:\n", fd);
#if LATER
fputs(" -V print version information to stdout, and exit\n", fd);
#endif
#if WITH_HELP
fputs(" -?|-h print a help text describing command line options\n", fd);
#endif
fputs(" -c print values of compile time C defines\n", fd);
#if LATER
fputs(" -d increase verbosity (use up to 4 times; 2 are recommended)\n", fd);
#endif
#if 0
fputs(" -ly[facility] log to syslog, using facility (default is daemon)\n", fd);
fputs(" -lf<logfile> log to file\n", fd);
fputs(" -ls log to stderr (default if no other log)\n", fd);
#endif
#if 0
fputs(" -n<fdnum> first file descriptor number not analyzed\n", fd);
#endif
}
#endif /* WITH_HELP */

93
proxy.sh Executable file
View File

@@ -0,0 +1,93 @@
#! /usr/bin/env bash
# source: proxy.sh
# Copyright Gerhard Rieger and contributors (see file CHANGES)
# Published under the GNU General Public License V.2, see file COPYING
# perform primitive simulation of a proxy server.
# accepts and answers correct HTTP CONNECT requests on stdio, and tries to
# establish the connection to the given server.
# it is required for socats test.sh
# for TCP, use this script like:
# socat TCP-L:8080,reuseaddr,fork EXEC:"proxy.sh",nofork
# 20130622 GR allow hostnames, not only IP addresses
if [ -z "$SOCAT" ]; then
if type socat >/dev/null 2>&1; then
SOCAT=socat
else
SOCAT="./socat"
fi
fi
if [ $(echo "x\c") = "x" ]; then E=""
elif [ $(echo -e "x\c") = "x" ]; then E="-e"
else
echo "cannot suppress trailing newline on echo" >&2
exit 1
fi
ECHO="echo $E"
CR=$($ECHO "\r")
#echo "CR=$($ECHO "$CR\c" |od -c)" >&2
case `uname` in
HP-UX|OSF1)
# their cats are too stupid to work with unix domain sockets
CAT="$SOCAT -u stdin stdout"
;;
*)
CAT=cat
;;
esac
SPACES=" "
while [ -n "$1" ]; do
case "$1" in
-w) n="$2"; while [ "$n" -gt 0 ]; do SPACES="$SPACES "; n=$((n-1)); done
shift ;;
#-s) STAT="$2"; shift ;;
esac
shift
done
badrequest () {
$ECHO "HTTP/1.0${SPACES}500 Bad Request$CR"
$ECHO "$CR"
}
# read and parse HTTP request
read m a h
#echo "\"$m\" \"$a\" \"$h\"" >&2
if [ "$m" != 'CONNECT' ]; then
badrequest; exit 1
fi
if [[ "$a" == [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+ ]]; then
: go on below
elif [[ "$a" == [0-9a-zA-Z-.][0-9a-zA-Z-.]*:[0-9][0-9]* ]]; then
: go on below
else
badrequest; exit 1
fi
if [[ "$h" == HTTP/1.[01][[:space:]]* ]]; then
: go on below
else
badrequest; exit 1
fi
# read more headers until empty line
while [ "$l" != "$CR" ]; do
read l
done
# send status
$ECHO "HTTP/1.0${SPACES}200 OK$CR"
# send empty line
$ECHO "$CR"
# perform proxy (relay) function
$SOCAT $SOCAT_OPTS - tcp:$a || {
$ECHO "HTTP/1.0${SPACES}500 Failed to connect to $a$CR"
$ECHO $CR
}

66
proxyecho.sh Executable file
View File

@@ -0,0 +1,66 @@
#! /usr/bin/env bash
# source: proxyecho.sh
# Copyright Gerhard Rieger and contributors (see file CHANGES)
# Published under the GNU General Public License V.2, see file COPYING
# perform primitive simulation of a proxy server with echo function via stdio.
# accepts and answers correct HTTP CONNECT requests, but then just echoes data.
# it is required for test.sh
# for TCP, use this script as:
# socat TCP-L:8080,reuseaddr,crlf SYSTEM:"proxyecho.sh"
# 20230423 GR Added option -V to require particular HTTP version
if type socat >/dev/null 2>&1; then
SOCAT=socat
else
SOCAT=./socat
fi
case `uname` in
HP-UX|OSF1)
CAT="$SOCAT -u stdin stdout"
;;
*)
CAT=cat
;;
esac
SPACES=" " REQVER=1.0
while [ -n "$1" ]; do
case "$1" in
-w) n="$2"; while [ "$n" -gt 0 ]; do SPACES="$SPACES "; n=$((n-1)); done
shift ;;
-V) shift; REQVER="$1" ;;
#-s) STAT="$2"; shift ;;
esac
shift
done
# read and parse HTTP request
read l
if ! echo "$l" |egrep '^CONNECT +[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+ +HTTP/[1-3].[0-9]$' >/dev/null
then
echo "HTTP/1.0${SPACES}500 Bad Request"
echo
exit
fi
if ! echo "$l" |egrep '^CONNECT +[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+ +HTTP/'"$REQVER"'$' >/dev/null
then
echo "HTTP/1.0${SPACES}426 Upgrade Required"
echo
exit
fi
# read more headers until empty line
while [ -n "$l" ]; do
read l
done
# send status
echo "HTTP/$REQVER${SPACES}200 OK"
# send empty line
echo
# perform echo function
exec $CAT

47
readline-test.sh Executable file
View File

@@ -0,0 +1,47 @@
#! /usr/bin/env bash
# source: readline-test.sh
# Copyright Gerhard Rieger and contributors (see file CHANGES)
# Published under the GNU General Public License V.2, see file COPYING
# script that simulates a simple program with authentication.
# is just for testing the readline features
# perform the test with something like:
# ./socat readline,history=$HOME/.history,noecho='^Password: ' system:./readline-test.sh,pty,setsid,ctty,stderr,sigint,sigquit,echo=0,raw
BANNER='readline feature test program'
USERPROMPT='Authentication required\nUsername: '
PWDPROMPT='Password: '
PROMPT='prog> '
# degenerated user database
CREDUSER="user"
CREDPASS="password"
if [ $(echo "x\c") = "x" ]; then ECHO="echo"
elif [ $(echo -e "x\c") = "x" ]; then ECHO="echo -e"
fi
#trap "$ECHO $0 got SIGINT" INT
trap "$ECHO $0 got SIGINT" INT
trap "$ECHO $0 got SIGQUIT" QUIT
# print banner
$ECHO "$BANNER"
# on (some) ksh read -p does not mean prompt
$ECHO "$USERPROMPT\c"; read -r USERNAME
$ECHO "$PWDPROMPT\c"; read -rs PASSWORD
$ECHO
if [ "$USERNAME" != "$CREDUSER" -o "$PASSWORD" != "$CREDPASS" ]; then
$ECHO "Authentication failed" >&2
exit -1
fi
while $ECHO "$PROMPT\c"; read -r COMMAND; do
if [ "$COMMAND" = "exit" ]; then
break;
fi
$ECHO "executing $COMMAND"
done

30
readline.sh Executable file
View File

@@ -0,0 +1,30 @@
#! /usr/bin/env bash
# source: readline.sh
# Copyright Gerhard Rieger and contributors (see file CHANGES)
# Published under the GNU General Public License V.2, see file COPYING
# this is an attempt for a socat based readline wrapper
# usage: readline.sh <command>
withhistfile=1
while true; do
case "X$1" in
X-nh|X-nohist*) withhistfile=; shift; continue ;;
*) break;;
esac
done
PROGRAM="$@"
if [ "$withhistfile" ]; then
HISTFILE="$HOME/.$1_history"
HISTOPT=",history=$HISTFILE"
else
HISTOPT=
fi
mkdir -p /tmp/$USER || exit 1
#
#
exec socat -d readline"$HISTOPT",noecho='[Pp]assword:' exec:"$PROGRAM",sigint,pty,setsid,ctty,raw,echo=0,stderr 2>/tmp/$USER/stderr2

85
snprinterr.c Normal file
View File

@@ -0,0 +1,85 @@
/* snprinterr.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* a function similar to vsnprintf() but it just handles %m */
#include "config.h"
#include <stddef.h> /* ptrdiff_t */
#include <ctype.h> /* isdigit() */
#include <stdarg.h>
#include <stdlib.h>
#include <errno.h>
#if HAVE_SYSLOG_H
#include <syslog.h>
#endif
#include <sys/utsname.h>
#include <time.h> /* time_t, strftime() */
#include <sys/time.h> /* gettimeofday() */
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "snprinterr.h"
#define HAVE_STRERROR_R 0
/* replace %m in format with actual strerror() message, write result to *str.
keep other % formats unchanged!
writes at most size chars including the terminating \0 to *str
returns the number of bytes in the output without terminating \0
result is always \0 terminated except when size==0
*/
int snprinterr(char *str, size_t size, const char *format) {
char c;
int full = 0; /* 1 means: there is no space left in * str for more data or \0 */
int count = 0;
if (size == 0) return 0;
if (count >= size) full = 1;
while (c = *format++) {
if (c == '%') {
c = *format++;
switch (c) {
case '\0':
++count; if (!full) { (*str++ = '%'); if (count+1 >= size) full = 1; }
break;
default:
++count; if (!full) { (*str++ = '%'); if (count+1 >= size) full = 1; }
++count; if (!full) { (*str++ = c); if (count+1 >= size) full = 1; }
break;
case 'm':
{
#if HAVE_STRERROR_R
# define BUFLEN 64
char buf[BUFLEN] = "";
#endif /* HAVE_STRERROR_R */
char *bufp;
#if !HAVE_STRERROR_R
bufp = strerror(errno);
#else
/* there are two versions floating around... */
# if 1 /* GNU version */
bufp = strerror_r(errno, buf, BUFLEN);
# else /* standard version */
strerror_r(errno, buf, BUFLEN);
bufp = buf;
# endif
#endif /* HAVE_STRERROR_R */
while ((c = *bufp++) != '\0') {
++count; if (!full) { (*str++ = c); if (count+1 >= size) full = 1; }
}
}
c = ' '; /* not \0 ! */
break;
}
if (c == '\0') break;
} else {
++count; if (!full) { (*str++ = c); if (count+1 >= size) full = 1; }
}
}
*str++ = '\0'; /* always write terminating \0 */
return count;
#undef BUFLEN
}

10
snprinterr.h Normal file
View File

@@ -0,0 +1,10 @@
/* source: snprinterr.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __snprinterr_h_included
#define __snprinterr_h_included 1
int snprinterr(char *str, size_t size, const char *format);
#endif /* !defined(__snprinterr_h_included) */

83
socat-broker.sh Executable file
View File

@@ -0,0 +1,83 @@
#! /usr/bin/env bash
# Copyright Gerhard Rieger and contributors (see file CHANGES)
# Published under the GNU General Public License V.2, see file COPYING
# Shell script to perform group communications, sometimes called brokering.
# It starts a Socat instance that forks a child process for each
# connected client; the clients communicate via IPv4 broadcast
# Examples:
# socat-broker.sh TCP-L:1234
# Now connect with an arbitrary number of clients like TCP:<server>:1234
# socat-broker.sh SSL-L:1234,cert=server.pem,cafile=clients.crt
# Now connect with an arbitrary number of clients like SSL:<server>:1234,cafile=server.cert=clients.pem
ECHO="echo -e"
usage () {
$ECHO "Usage: $0 <options> <listener>"
$ECHO " <listener> is a passive address like TCP4-L or SSL-L"
$ECHO " <options>:"
$ECHO " -d* -S -t <timeout> -T <timeout> are passed to socat"
$ECHO " -V prints the socat command before starting it"
$ECHO "For example:"
$ECHO " $0 \\"
$ECHO " TCP4-L:1234"
$ECHO "Then connect with clients to port 1234"
$ECHO "Data sent by any client is forwarded to all other clients"
}
VERBOSE= QUIET= OPTS=
while [ "$1" ]; do
case "X$1" in
X-h) usage; exit ;;
X-V) VERBOSE=1 ;;
X-q) QUIET=1; OPTS="-d0" ;;
X-d*|X-l?*) OPTS="$OPTS $1" ;;
X-b|X-S|X-t|X-T|X-l) OPT=$1; shift; OPTS="$OPTS $OPT $1" ;;
X-) break ;;
X-*) echo "Unknown option \"$1\"" >&2
usage >&2
exit 1 ;;
*) break ;;
esac
shift
done
LISTENER="$1"
if [ -z "$LISTENER" ]; then
echo "$0: Missing parameter" >&2
usage >&2
exit 1
fi
shopt -s nocasematch
if ! [[ "$LISTENER" =~ .*,fork ]] || [[ "$LISTENER" =~ .*,fork, ]]; then
LISTENER="$LISTENER,fork"
fi
case "$0" in
*/*) SOCAT=${0%/*}/socat ;;
*) SOCAT=socat ;;
esac
PORT=$($SOCAT -d -d -T 0.000001 UDP4-RECV:0 /dev/null 2>&1 |grep bound |sed 's/.*:\([1-9][0-9]*\)$/\1/')
if [ -z "$PORT" ]; then
echo "$0: Failed to determine free UDP port" >&2
exit 1
fi
BCADDR=127.255.255.255
if [ "$VERBOSE" ]; then
echo -e "$SOCAT -lp socat-broker $OPTS \\
$LISTENER \
UDP4-DATAGRAM:$BCADDR:$PORT,bind=:$PORT,so-broadcast,so-reuseaddr"
fi
$SOCAT -lp socat-broker $OPTS \
"$LISTENER" \
"UDP4-DATAGRAM:$BCADDR:$PORT,bind=:$PORT,so-broadcast,so-reuseaddr"

264
socat-chain.sh Executable file
View File

@@ -0,0 +1,264 @@
#! /usr/bin/env bash
# Copyright Gerhard Rieger and contributors (see file CHANGES)
# Published under the GNU General Public License V.2, see file COPYING
# Shell script to build a chain of Socat instances connected via TCP sockets.
# This allows to drive, e.g., PROXY-CONNECT over SSL, or SSL over serial.
# Currently only a chain made from 3 addresses, resulting in two instances, is
# implemented.
# The 2nd address must be one of OPENSSL (SSL), PROXY-CONNECT (PROXY),
# SOCKS4, SOCKS4A, SOCKS5
# This is beta!
# Examples:
# Drive HTTP CONNECT (PROXY) over SSL
# (establish an SSL tunnel to a proxy server, request being forwarded to a
# telnet server):
# socat-chain.sh \
# STDIO \
# PROXY::<telnet-server>:23 \
# OPENSSL:<proxy-server>:8443
# Accept connections that arrive on port 7777, encrypt the data, and send it
# via socks server to final target:
# socat-chain.sh \
# TCP-L:7777,reuseaddr,fork \
# OPENSSL,verify=0 \
# SOCKS4:<socks-server>:<ssl-server>:8443
# Receive SSL coming from a serial lie
# socat-chain.sh \
# /dev/ttyS0,cfmakeraw \
# SSL-L,cafile=server.pem,verify=0 \
# TCP4:localhost:80
# Formally, this is what happens:
# socat-chain.sh addr1 addr2 addr3
# results in something like:
# socat TCP-L:RANDOM addr3 &
# socat addr1 addr2:localhost:RANDOM
# or on passive/listening addr2:
# socat addr2:RANDOM addr3 &
# socat addr1 TCP:localhost:RANDOM
ECHO="echo -e"
usage () {
$ECHO "Usage: $0 <options> <address1> <address2> <address3>"
$ECHO " <address1> is typically a passive (listening) address like"
$ECHO " TCP-L:1234"
$ECHO " <address2> must be one of OPENSSL, PROXY, SOCK4, SOCKS4A, or SOCKS5,"
$ECHO " or SSL-L (passive/listening)"
$ECHO " Given server hostname and port are ignored and replaced by internal"
$ECHO " communication point"
$ECHO " <address3> is typically a client address with protocol like OPENSSL"
$ECHO " <options>:"
$ECHO " -d* -S <sigmask> -t <timeout> -T <timeout> are passed to socat"
$ECHO " -V prints the socat commands before starting them"
$ECHO "Example to drive SOCKS over TLS:"
$ECHO " $0 \\"
$ECHO " TCP4-L:1234,reuseaddr,fork \\"
$ECHO " SOCKS::<server>:<port> \\"
$ECHO " OPENSSL:10.2.3.4:12345,cafile=..."
$ECHO " Clients that connect to port 1234 will be forwarded to <server>:<port> using socks"
$ECHO " over TLS"
}
LOCALHOST=127.0.0.1
VERBOSE= QUIET= OPTS=
while [ "$1" ]; do
case "X$1" in
X-h) usage; exit ;;
X-V) VERBOSE=1 ;;
X-q) QUIET=1; OPTS="-d0" ;;
X-d*|X-l?*) OPTS="$OPTS $1" ;;
X-b|X-S|X-t|X-T|X-l) OPT=$1; shift; OPTS="$OPTS $OPT $1" ;;
X-) break ;;
X-*) echo "$0: Unknown option \"$1\"" >&2
usage >&2
exit 1 ;;
*) break ;;
esac
shift
done
ARG0="$1"
ARG1="$2"
ARG2="$3"
if [ -z "$ARG0" -o -z "$ARG1" -o -z "$ARG2" ]; then
echo "$0: Three addresses required" >&2
usage >&2
exit 1
fi
mkprogname () {
ARG="$1"
if [[ "$ARG" =~ .*[:].* ]]; then
NAME="${ARG%%:*}"
elif [[ "$ARG" =~ .*[,].* ]]; then
NAME="${ARG%%,*}"
elif [ "X$ARG" = X- ]; then
NAME=stdio
else
NAME="$ARG"
fi
NAME="${NAME,,*}"
echo $NAME
}
# You may place a fork option in the first address
# in which case the following internal listeners do fork too
FORK=
case "$ARG0" in
*,fork,*|*,fork) FORK=fork ;;
esac
# Split middle address for insertion of additional parts
if [[ "$ARG1" =~ .*,.* ]]; then
ARG1A="${ARG1%%,*}"
ARG1B="${ARG1#*,}"
else
ARG1A="$ARG1"
ARG1B=
fi
case "$0" in
*/*) SOCAT=${0%/*}/socat ;;
*) SOCAT=socat ;;
esac
PORT=$($SOCAT -d -d TCP4-L:0,accept-timeout=0.000001 /dev/null 2>&1 |grep listening |sed 's/.*:\([1-9][0-9]*\)$/\1/')
if [ -z "$PORT" ]; then
echo "$0: Failed to determine free TCP port" >&2
exit 1
fi
PASSIVE= # is the second address passive/listening/server?
case "${ARG1A^^*}" in
OPENSSL|OPENSSL:*|SSL|SSL:.*)
OPTS1A=
#if [[ $ARG1A =~ ^\([^:]*\):\([^:]*\):\([^,]*\)\(.*\) ]]; then # bash 3
if [[ $ARG1A =~ ^([^:]*):([^:]*):([^,]*)(.*) ]]; then
OPTS1A="${BASH_REMATCH[4]}"
#elif [[ $ARG1A =~ ^\([^,]*\)\(.*\) ]]; then # bash 3
elif [[ $ARG1A =~ ^([^,]*)(.*) ]]; then
OPTS1A="${BASH_REMATCH[2]}"
else
echo "$0: \"$ARG1A\": invalid arguments" >&2
exit 1
fi
PROG1="${BASH_REMATCH[1]}"
NAME1=$(mkprogname "${BASH_REMATCH[1]}")
NAME2=$(mkprogname "$ARG2")
ARG1A=$PROG1:$LOCALHOST:$PORT$OPTS1A ;;
PROXY-CONNECT:*|PROXY:*)
#if ! [[ $ARG1A =~ ^\([^:]*\):\([^:]*\):\([^:]*\):\([^,]*\)\(.*\) ]]; then # bash 3
if ! [[ $ARG1A =~ ^([^:]*):([^:]*):([^:]*):([^,]*)(.*) ]]; then
echo "$0: \"$ARG1A\": invalid arguments" >&2
exit 1
fi
#echo "0:\"${BASH_REMATCH[0]}\" 1:\"${BASH_REMATCH[1]}\" 2:\"${BASH_REMATCH[2]}\" 3:\"${BASH_REMATCH[3]}\" 4:\"${BASH_REMATCH[4]}\""
PROG1="${BASH_REMATCH[1]}"
NAME1=$(mkprogname "${PROG1,,*}")
NAME2=$(mkprogname "$ARG2")
OPTS1A="${BASH_REMATCH[5]}"
ARG1A="$PROG1:$LOCALHOST:${BASH_REMATCH[3]}:${BASH_REMATCH[4]},proxyport=$PORT,$OPTS1A" ;;
SOCKS:*|SOCKS4:*|SOCKS4A*)
#if ! [[ $ARG1A =~ ^\([^:]*\):\([^:]*\):\([^:]*\):\([^:,]*\),* ]]; then # bash 3
if ! [[ $ARG1A =~ ^([^:]*):([^:]*):([^:]*):([^:,]*),* ]]; then
echo "$0: \"$ARG1A\": invalid arguments" >&2
exit 1
fi
PROG1="${BASH_REMATCH[1]}"
NAME1=$(mkprogname "${PROG1,,*}")
NAME2=$(mkprogname "$ARG2")
OPTS1A="${BASH_REMATCH[5]}"
ARG1A="$PROG1:$LOCALHOST:${BASH_REMATCH[3]}:${BASH_REMATCH[4]},socksport=$PORT,$OPTS1A" ;;
SOCKS5:*|SOCKS5-CONNECT*)
#if ! [[ $ARG1A =~ ^\([^:]*\):\([^:]*\):\([^:]*\):\([^:,]*\):\([^:,]*\),* ]]; then # bash 3
if ! [[ $ARG1A =~ ^([^:]*):([^:]*):([^:]*):([^:,]*):([^:,]*),* ]]; then
echo "$0: \"$ARG1A\": invalid arguments" >&2
exit 1
fi
PROG1="${BASH_REMATCH[1]}"
NAME1=$(mkprogname "${PROG1,,*}")
NAME2=$(mkprogname "$ARG2")
OPTS1A="${BASH_REMATCH[6]}"
ARG1A="$PROG1:$LOCALHOST:$PORT:${BASH_REMATCH[4]}:${BASH_REMATCH[5]},$OPTS1A" ;;
# Passive (server) addresses
OPENSSL-LISTEN|OPENSSL-LISTEN:*|SSL-L|SSL-L:.*)
PASSIVE=1
OPTS1A=
#if [[ $ARG1A =~ ^\([^:]*\):\([^,]*\)\(.*\) ]]; then # bash 3
if [[ $ARG1A =~ ^([^:]*):([^,]*)(.*) ]]; then
OPTS1A="${BASH_REMATCH[3]}"
#elif [[ $ARG1A =~ ^\([^,]*\)\(.*\) ]]; then # bash 3
elif [[ $ARG1A =~ ^([^,]*)(.*) ]]; then
OPTS1A="${BASH_REMATCH[2]}"
else
echo "$0: \"$ARG1A\": invalid arguments" >&2
exit 1
fi
PROG1="${BASH_REMATCH[1]}"
NAME1=$(mkprogname "$ARG0")
NAME2=$(mkprogname "${BASH_REMATCH[1]}")
ARG1A=$PROG1:$PORT$OPTS1A ;;
*) echo "$0: Unsupported address \"$ARG1A\"" >&2
usage >&2
exit 1 ;;
esac
ADDR1A="$ARG0"
if [ -z "$PASSIVE" ]; then
ADDR1B="$ARG1A,bind=$LOCALHOST,$ARG1B"
ADDR2A="TCP4-L:$PORT,reuseaddr,$FORK,bind=$LOCALHOST,range=$LOCALHOST/32"
else
ADDR1B="TCP4:$LOCALHOST:$PORT,bind=$LOCALHOST"
ADDR2A="$ARG1A,reuseaddr,$FORK,bind=$LOCALHOST,range=$LOCALHOST/32,$ARG1B"
fi
ADDR2B="$ARG2"
pid1= pid2=
trap '[ "$pid1" ] && kill $pid1 2>/dev/null; [ "$pid2" ] && kill $pid2 2>/dev/null' EXIT
set -bm
trap 'rc=$?; if ! kill -n 0 $pid2 2>/dev/null; then [ -z "$QUIET" -a $rc -ne 0 ] && echo "$0: socat-$NAME2 exited with rc=$rc" >&2; exit $rc; fi' SIGCHLD
# Start instance 2 first, because instance 1 ("left") connects to 2
if [ "$VERBOSE" ]; then
$ECHO "$SOCAT $OPTS -lp socat-$NAME2 \\
\"$ADDR2A\" \\
\"$ADDR2B\" &"
fi
$SOCAT $OPTS -lp socat-$NAME2 \
"$ADDR2A" \
"$ADDR2B" &
pid2=$!
sleep 0.1
#trap 'if ! kill -n 0 $pid1 2>/dev/null; then [ -z "$QUIET" ] && echo "$0: socat-$NAME1 exited with rc=$?" >&2; kill $pid2 2>/dev/null; exit 1; elif ! kill -n 0 $pid2 2>/dev/null; then [ -z "$QUIET" ] && echo "$0: socat-$NAME2 exited with rc=$?" >&2; kill $pid1 2>/dev/null; exit 1; fi' SIGCHLD
if [ "$VERBOSE" ]; then
$ECHO "$SOCAT $OPTS -lp socat-$NAME1 \\
\"$ADDR1A\" \\
\"$ADDR1B\""
fi
$SOCAT $OPTS -lp socat-$NAME1 \
"$ADDR1A" \
"$ADDR1B"
#pid1=$!
rc1=$?
kill $pid2 2>/dev/null
wait 2>/dev/null
#wait -f
exit $rc1

115
socat-mux.sh Executable file
View File

@@ -0,0 +1,115 @@
#! /usr/bin/env bash
# Copyright Gerhard Rieger and contributors (see file CHANGES)
# Published under the GNU General Public License V.2, see file COPYING
# Shell script to build a many-to-one, one-to-all communication
# It starts two Socat instances that communicate via IPv4 broadcast,
# the first of which forks a child process for each connected client.
# Example:
# Consider a serial device connected to the Internet on TCP port 1234, it
# accepts only one connection at a time.
# On a proxy/relay server run this script:
# socat-mux.sh \
# TCP-L:1234,reuseaddr,fork \
# TCP:<addr-of-device>:1234
# Now connect with an arbitrary number of clients to TCP:<proxy>:1234;
# data sent by the device goes to all clients, data from any client is sent to
# the device.
ECHO="echo -e"
usage () {
$ECHO "Usage: $0 <options> <listener> <target>"
$ECHO "Example:"
$ECHO " $0 TCP4-L:1234,reuseaddr,fork TCP:10.2.3.4:12345"
$ECHO "Clients may connect to port 1234; data sent by any client is forwarded to 10.2.3.4,"
$ECHO "data provided by 10.2.3.4 is sent to ALL clients"
$ECHO " <options>:"
$ECHO "\t-h\tShow this help text and exit"
$ECHO "\t-V\tShow Socat commands"
$ECHO "\t-q\tSuppress most messages"
$ECHO "\t-d*\tOptions beginning with -d are passed to Socat processes"
$ECHO "\t-l*\tOptions beginning with -l are passed to Socat processes"
$ECHO "\t-b|-S|-t|-T|-l <arg>\tThese options are passed to Socat processes"
}
VERBOSE= QUIET= OPTS=
while [ "$1" ]; do
case "X$1" in
X-h) usage; exit ;;
X-V) VERBOSE=1 ;;
X-q) QUIET=1; OPTS="-d0" ;;
X-d*|X-l?*) OPTS="$OPTS $1" ;;
X-b|X-S|X-t|X-T|X-l) OPT=$1; shift; OPTS="$OPTS $OPT $1" ;;
X-) break ;;
X-*) echo "$0: Unknown option \"$1\"" >&2
usage >&2
exit 1 ;;
*) break ;;
esac
shift
done
LISTENER="$1"
TARGET="$2"
if [ -z "$LISTENER" -o -z "$TARGET" ]; then
echo "$0: Missing parameter(s)" >&2
usage >&2
exit 1
fi
shopt -s nocasematch
if ! [[ "$LISTENER" =~ .*,fork ]] || [[ "$LISTENER" =~ .*,fork, ]]; then
LISTENER="$LISTENER,fork"
fi
case "$0" in
*/*) SOCAT=${0%/*}/socat ;;
*) SOCAT=socat ;;
esac
PORT1=$($SOCAT -d -d -T 0.000001 UDP4-RECV:0 /dev/null 2>&1 |grep bound |sed 's/.*:\([1-9][0-9]*\)$/\1/')
PORT2=$($SOCAT -d -d -T 0.000001 UDP4-RECV:0 /dev/null 2>&1 |grep bound |sed 's/.*:\([1-9][0-9]*\)$/\1/')
if [ -z "$PORT1" -o -z "$PORT2" ]; then
echo "$0: Failed to determine free UDP ports" >&2
exit 1
fi
if [ "$PORT1" = "$PORT2" ]; then # seen on etch
PORT2=$((PORT1+1))
fi
IFADDR=127.0.0.1
BCADDR=127.255.255.255
pid1= pid2=
trap '[ "$pid1" ] && kill $pid1 2>/dev/null; [ "$pid2" ] && kill $pid2 2>/dev/null' EXIT
set -bm
trap 'if kill -n 0 $pid1 2>/dev/null; then [ -z "$QUIET" ] && echo "$0: socat-listener exited with rc=$?" >&2; kill $pid1; else [ -z "$QUIET" ] && echo "$0: socat-multiplexer exited with rc=$?" >&2; kill $pid2 2>/dev/null; fi; exit 1' SIGCHLD
if [ "$VERBOSE" ]; then
$ECHO "$SOCAT -lp muxfwd $OPTS \\
\"$TARGET\" \\
\"UDP4-DATAGRAM:$BCADDR:$PORT2,bind=$IFADDR:$PORT1,so-broadcast\" &"
fi
$SOCAT -lp muxfwd $OPTS \
"$TARGET" \
"UDP4-DATAGRAM:$BCADDR:$PORT2,bind=$IFADDR:$PORT1,so-broadcast" &
pid1=$!
if [ "$VERBOSE" ]; then
$ECHO "$SOCAT -lp muxlst $OPTS \\
\"$LISTENER\" \\
\"UDP4-DATAGRAM:$IFADDR:$PORT1,bind=:$PORT2,so-broadcast,so-reuseaddr\" &"
fi
$SOCAT -lp muxlst $OPTS \
"$LISTENER" \
"UDP4-DATAGRAM:$IFADDR:$PORT1,bind=:$PORT2,so-broadcast,so-reuseaddr" &
pid2=$!
wait
#wait -f

1825
socat.c Normal file

File diff suppressed because it is too large Load Diff

63
socat.spec Normal file
View File

@@ -0,0 +1,63 @@
%define majorver 1.8
%define minorver 0.0
Summary: socat - multipurpose relay
Name: socat
Version: %{majorver}.%{minorver}
Release: 1
License: GPL
Group: Applications/Communications
Source0: http://www.dest-unreach.org/socat/download/socat-%{version}.tar.bz2
Requires: readline
Requires: openssl
BuildRoot: /var/tmp/%{name}-buildroot
%description
socat is a relay for bidirectional data transfer between two independent data
channels. Each of these data channels may be a file, pipe, device (terminal or
modem etc.), socket (UNIX, IP4, IP6 - raw, UDP, TCP), a file descriptor (stdin
etc.), a program, or an arbitrary combination of two of these.
%prep
%setup -n %{name}-%{version}
%build
# the CPPFLAGS setting is required for RedHat Linux
if [ -d /usr/kerberos/include ]; then
CPPFLAGS="-I/usr/kerberos/include" ./configure --prefix=%{_prefix} --mandir=%{_mandir}
else
./configure --prefix=%{_prefix} --mandir=%{_mandir}
fi
make
%install
rm -rf $RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT%{_bindir}
mkdir -p $RPM_BUILD_ROOT%{_mandir}/man1
make install DESTDIR=$RPM_BUILD_ROOT
mv $RPM_BUILD_ROOT%{_bindir}/socat $RPM_BUILD_ROOT%{_bindir}/socat1
mv $RPM_BUILD_ROOT%{_mandir}/man1/socat.1 $RPM_BUILD_ROOT%{_mandir}/man1/socat1.1
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
%doc README CHANGES EXAMPLES SECURITY doc/socat.html FAQ BUGREPORTS
%doc COPYING COPYING.OpenSSL FILES PORTING DEVELOPMENT
%{_bindir}/socat1
%{_bindir}/socat
%{_bindir}/procan
%{_bindir}/filan
%{_mandir}/man1/socat1.1
%post
ln -s -f socat1 %{_binddir}/socat
ln -s -f socat1.1 %{_mandir}/man1/socat.1
%postun
rm -f %{_bindir}/socat
rm -f %{_mandir}/man1/socat.1

137
socat_buildscript_for_android.sh Executable file
View File

@@ -0,0 +1,137 @@
#!/bin/sh
# Customize these parameters according to your environment
ANDROID_NDK="${HOME}/bin/android-ndk-r6b"
# Check for parameters
if [ ! -d "${ANDROID_NDK}" ]; then
echo "Android NDK not found in ${ANDROID_NDK}, please edit $0 to fix it."
exit 1
fi
if [ ! -e "${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh" ]; then
echo "Your Android NDK is not compatible (make-standalone-toolchain.sh not found)."
echo "Android NDK r6b is known to work."
exit 1
fi
# Extract the Android toolchain from NDK
ANDROID_PLATFORM="android-3"
ROOT="`pwd`"
OUT="${ROOT}/out"
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
--ndk-dir="${ANDROID_NDK}" \
--platform="${ANDROID_PLATFORM}" \
--install-dir="${OUT}/toolchain" \
|| exit 1
# Remove resolv.h because it is quite unusable as is
rm ${OUT}/toolchain/sysroot/usr/include/resolv.h
# Create configure script
cd ${ROOT}
autoconf || exit 1
# Create config.h and Makefile
cd ${OUT}
${ROOT}/configure \
--host \
--disable-openssl \
--disable-unix \
CC="${OUT}/toolchain/bin/arm-linux-androideabi-gcc" \
|| exit 1
# Replace misconfigured values in config.h and enable PTY functions
mv config.h config.old
cat config.old \
| sed 's/CRDLY_SHIFT.*/CRDLY_SHIFT 9/' \
| sed 's/TABDLY_SHIFT.*/TABDLY_SHIFT 11/' \
| sed 's/CSIZE_SHIFT.*/CSIZE_SHIFT 4/' \
| sed 's/\/\* #undef HAVE_OPENPTY \*\//#define HAVE_OPENPTY 1/' \
| sed 's/\/\* #undef HAVE_GRANTPT \*\//#define HAVE_GRANTPT 1/' \
> config.h
# Enable openpty() in Makefile
mv Makefile Makefile.old
cat Makefile.old | sed 's/error.c/error.c openpty.c/' > Makefile
# Provide openpty.c
cat >openpty.c <<EOF
/* Copyright (C) 1998, 1999, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#define _PATH_DEVPTMX "/dev/ptmx"
int openpty (int *amaster, int *aslave, char *name, struct termios *termp,
struct winsize *winp)
{
char buf[PATH_MAX];
int master, slave;
master = open(_PATH_DEVPTMX, O_RDWR);
if (master == -1)
return -1;
if (grantpt(master))
goto fail;
if (unlockpt(master))
goto fail;
if (ptsname_r(master, buf, sizeof buf))
goto fail;
slave = open(buf, O_RDWR | O_NOCTTY);
if (slave == -1)
goto fail;
/* XXX Should we ignore errors here? */
if (termp)
tcsetattr(slave, TCSAFLUSH, termp);
if (winp)
ioctl(slave, TIOCSWINSZ, winp);
*amaster = master;
*aslave = slave;
if (name != NULL)
strcpy(name, buf);
return 0;
fail:
close(master);
return -1;
}
EOF
# Compile
make socat || exit 1
# Done
echo "Build finished, socat has been generated successfuly in out/socat"

115
socks4a-echo.sh Executable file
View File

@@ -0,0 +1,115 @@
#! /usr/bin/env bash
# source: socks4a-echo.sh
#set -vx
# Copyright Gerhard Rieger and contributors (see file CHANGES)
# Published under the GNU General Public License V.2, see file COPYING
# perform primitive simulation of a socks4a server with echo function via stdio.
# accepts and answers correct SOCKS4a requests, but then just echoes data.
# it is required for test.sh
# for TCP, use this script as:
# socat tcp-l:1080,reuseaddr,crlf system:"socks4a-echo.sh"
# older bash and ksh do not have -n option to read command; we try dd then
#if echo a |read -n 1 null >/dev/null 2>&1; then
# HAVE_READ_N=1
#else
# and newer bash (4.3) has some other problem with read -n
HAVE_READ_N=
#fi
if type socat >/dev/null 2>&1; then
SOCAT=socat
else
SOCAT=./socat
fi
case `uname` in
HP-UX|OSF1)
CAT="$SOCAT -u stdin stdout"
;;
*)
CAT=cat
;;
esac
if [ $(echo "x\c") = "x" ]; then E=""
elif [ $(echo -e "x\c") = "x" ]; then E="-e"
else
echo "cannot suppress trailing newline on echo" >&2
exit 1
fi
ECHO="echo $E"
if [ $($ECHO "\0101") = "A" ]; then
SOCKSREPLY_FAILED="\0\0133\0\0\0\0\0\0\c"
SOCKSREPLY_OK="\0\0132\0\0\0\0\0\0\c"
else
SOCKSREPLY_FAILED="\0\133\0\0\0\0\0\0\c"
SOCKSREPLY_OK="\0\132\0\0\0\0\0\0\c"
fi
# read and parse SOCKS4a header
if [ "$HAVE_READ_N" ]; then
read -r -n 1 vn # bash 2.0.3 does not support -n
else
vn=$(dd bs=1 count=1 2>/dev/null)
fi
if [ "$vn" != $($ECHO "\04") ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "invalid socks version requested" >&2
exit
fi
if [ "$HAVE_READ_N" ]; then
read -r -n 1 cd
else
cd=$(dd bs=1 count=1 2>/dev/null)
fi
if [ "$cd" != $($ECHO "\01") ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "invalid socks operation requested" >&2
exit
fi
a=$(dd bs=1 count=6 2>/dev/null)
#echo a a a >/dev/tty
#echo "$a" |od -c >/dev/tty
#$ECHO "$a" |od -c >/dev/tty
#echo>/dev/tty
#echo a a a >/dev/tty
if [ "$a" != "$($ECHO "}m\0\0\0\01")" ]; then
sleep 1
$ECHO "$SOCKSREPLY_FAILED"
echo "wrong socks address or port requested" >&2
exit
fi
if [ "$HAVE_READ_N" ]; then
read -r -n 7 u
else
u=$(dd bs=1 count=7 2>/dev/null)
fi
if [ "$u" != "nobody" ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "wrong socks user requested" >&2
exit
fi
if [ "$HAVE_READ_N" ]; then
read -r -n 10 h
else
h=$(dd bs=1 count=10 2>/dev/null)
fi
if [ "$h" != "localhost" ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "wrong socks address requested" >&2
exit
fi
# send ok status
$ECHO "$SOCKSREPLY_OK"
# perform echo function
$CAT

102
socks4echo.sh Executable file
View File

@@ -0,0 +1,102 @@
#! /usr/bin/env bash
# source: socks4echo.sh
# Copyright Gerhard Rieger and contributors (see file CHANGES)
# Published under the GNU General Public License V.2, see file COPYING
# perform primitive simulation of a socks4 server with echo function via stdio.
# accepts and answers correct SOCKS4 requests, but then just echoes data.
# it is required for test.sh
# for TCP, use this script as:
# socat tcp-l:1080,reuseaddr,crlf system:"socks4echo.sh"
# older bash and ksh do not have -n option to read command; we try dd then
#if echo a |read -n 1 null >/dev/null 2>&1; then
# HAVE_READ_N=1
#else
# and newer bash (4.3) has some other problem with read -n
HAVE_READ_N=
#fi
if type socat >/dev/null 2>&1; then
SOCAT=socat
else
SOCAT=./socat
fi
case `uname` in
HP-UX|OSF1)
CAT="$SOCAT -u stdin stdout"
;;
*)
CAT=cat
;;
esac
if [ $(echo "x\c") = "x" ]; then E=""
elif [ $(echo -e "x\c") = "x" ]; then E="-e"
else
echo "cannot suppress trailing newline on echo" >&2
exit 1
fi
ECHO="echo $E"
if [ $($ECHO "\0101") = "A" ]; then
SOCKSREPLY_FAILED="\0\0133\0\0\0\0\0\0\c"
SOCKSREPLY_OK="\0\0132\0\0\0\0\0\0\c"
else
SOCKSREPLY_FAILED="\0\133\0\0\0\0\0\0\c"
SOCKSREPLY_OK="\0\132\0\0\0\0\0\0\c"
fi
# read and parse SOCKS4 header
if [ "$HAVE_READ_N" ]; then
read -r -n 1 vn # bash 2.0.3 does not support -n
else
vn=$(dd bs=1 count=1 2>/dev/null)
fi
if [ "$vn" != $($ECHO "\04") ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "invalid socks version requested" >&2
exit
fi
if [ "$HAVE_READ_N" ]; then
read -r -n 1 cd
else
cd=$(dd bs=1 count=1 2>/dev/null)
fi
if [ "$cd" != $($ECHO "\01") ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "invalid socks operation requested" >&2
exit
fi
if [ "$HAVE_READ_N" ]; then
read -r -n 6 a
else
a=$(dd bs=1 count=6 2>/dev/null)
fi
if [ "$a" != "$($ECHO "}m bL6")" ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "$0: wrong socks address or port requested" >&2
echo "$0: expected $($ECHO "}m bL6"|od -t x1), received $($ECHO "$a"|od -t x1)" >&2
exit
fi
if [ "$HAVE_READ_N" ]; then
read -r -n 7 u
else
u=$(dd bs=1 count=7 2>/dev/null)
fi
if [ "$u" != "nobody" ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "wrong socks user requested (expected \"nobody\")" >&2
exit
fi
# send ok status
$ECHO "$SOCKSREPLY_OK"
# perform echo function
$CAT

525
sslcls.c Normal file
View File

@@ -0,0 +1,525 @@
/* source: sslcls.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* explicit system call and C library trace function, for those who miss strace
*/
#include "config.h"
#include "xioconfig.h" /* what features are enabled */
#if WITH_SYCLS && WITH_OPENSSL
#include "sysincludes.h"
#include "mytypes.h"
#include "compat.h"
#include "errno.h"
#include "error.h"
#include "filan.h"
#include "sysutils.h"
#include "sycls.h"
#if HAVE_OPENSSL_INIT_SSL
/* OpenBSD 7.2 does not know OPENSSL_INIT_SETTING */
int sycOPENSSL_init_ssl(uint64_t opts, const void *settings) {
int result;
Debug2("OPENSSL_init_ssl("F_uint64_t", %p)", opts, settings);
result = OPENSSL_init_ssl(opts, settings);
Debug1("OPENSSL_init_ssl() -> %d", result);
return result;
}
#endif
#if !(defined(HAVE_OPENSSL_INIT_SSL) && defined(HAVE_OPENSSL_INIT_new))
void sycSSL_load_error_strings(void) {
Debug("SSL_load_error_strings()");
SSL_load_error_strings();
Debug("SSL_load_error_strings() ->");
}
#endif
#if HAVE_SSL_library_init
int sycSSL_library_init(void) {
int result;
Debug("SSL_library_init()");
result = SSL_library_init();
Debug1("SSL_library_init() -> %d", result);
return result;
}
#endif
#if HAVE_TLS_client_method
const SSL_METHOD *sycTLS_client_method(void) {
const SSL_METHOD *result;
Debug("TLS_client_method()");
result = TLS_client_method();
Debug1("TLS_client_method() -> %p", result);
return result;
}
#endif
#if HAVE_TLS_server_method
const SSL_METHOD *sycTLS_server_method(void) {
const SSL_METHOD *result;
Debug("TLS_server_method()");
result = TLS_server_method();
Debug1("TLS_server_method() -> %p", result);
return result;
}
#endif
#if HAVE_SSLv2_client_method
const SSL_METHOD *sycSSLv2_client_method(void) {
const SSL_METHOD *result;
Debug("SSLv2_client_method()");
result = SSLv2_client_method();
Debug1("SSLv2_client_method() -> %p", result);
return result;
}
#endif
#if HAVE_SSLv2_server_method
const SSL_METHOD *sycSSLv2_server_method(void) {
const SSL_METHOD *result;
Debug("SSLv2_server_method()");
result = SSLv2_server_method();
Debug1("SSLv2_server_method() -> %p", result);
return result;
}
#endif
#if HAVE_SSLv3_client_method
const SSL_METHOD *sycSSLv3_client_method(void) {
const SSL_METHOD *result;
Debug("SSLv3_client_method()");
result = SSLv3_client_method();
Debug1("SSLv3_client_method() -> %p", result);
return result;
}
#endif
#if HAVE_SSLv3_server_method
const SSL_METHOD *sycSSLv3_server_method(void) {
const SSL_METHOD *result;
Debug("SSLv3_server_method()");
result = SSLv3_server_method();
Debug1("SSLv3_server_method() -> %p", result);
return result;
}
#endif
const SSL_METHOD *sycSSLv23_client_method(void) {
const SSL_METHOD *result;
Debug("SSLv23_client_method()");
result = SSLv23_client_method();
Debug1("SSLv23_client_method() -> %p", result);
return result;
}
const SSL_METHOD *sycSSLv23_server_method(void) {
const SSL_METHOD *result;
Debug("SSLv23_server_method()");
result = SSLv23_server_method();
Debug1("SSLv23_server_method() -> %p", result);
return result;
}
#if HAVE_TLSv1_client_method
const SSL_METHOD *sycTLSv1_client_method(void) {
const SSL_METHOD *result;
Debug("TLSv1_client_method()");
result = TLSv1_client_method();
Debug1("TLSv1_client_method() -> %p", result);
return result;
}
#endif
#if HAVE_TLSv1_server_method
const SSL_METHOD *sycTLSv1_server_method(void) {
const SSL_METHOD *result;
Debug("TLSv1_server_method()");
result = TLSv1_server_method();
Debug1("TLSv1_server_method() -> %p", result);
return result;
}
#endif
#if HAVE_TLSv1_1_client_method
const SSL_METHOD *sycTLSv1_1_client_method(void) {
const SSL_METHOD *result;
Debug("TLSv1_1_client_method()");
result = TLSv1_1_client_method();
Debug1("TLSv1_1_client_method() -> %p", result);
return result;
}
#endif
#if HAVE_TLSv1_1_server_method
const SSL_METHOD *sycTLSv1_1_server_method(void) {
const SSL_METHOD *result;
Debug("TLSv1_1_server_method()");
result = TLSv1_1_server_method();
Debug1("TLSv1_1_server_method() -> %p", result);
return result;
}
#endif
#if HAVE_TLSv1_2_client_method
const SSL_METHOD *sycTLSv1_2_client_method(void) {
const SSL_METHOD *result;
Debug("TLSv1_2_client_method()");
result = TLSv1_2_client_method();
Debug1("TLSv1_2_client_method() -> %p", result);
return result;
}
#endif
#if HAVE_TLSv1_2_server_method
const SSL_METHOD *sycTLSv1_2_server_method(void) {
const SSL_METHOD *result;
Debug("TLSv1_2_server_method()");
result = TLSv1_2_server_method();
Debug1("TLSv1_2_server_method() -> %p", result);
return result;
}
#endif
#if HAVE_DTLS_client_method
const SSL_METHOD *sycDTLS_client_method(void) {
const SSL_METHOD *result;
Debug("DTLS_client_method()");
result = DTLS_client_method();
Debug1("DTLS_client_method() -> %p", result);
return result;
}
#endif
#if HAVE_DTLS_server_method
const SSL_METHOD *sycDTLS_server_method(void) {
const SSL_METHOD *result;
Debug("DTLS_server_method()");
result = DTLS_server_method();
Debug1("DTLS_server_method() -> %p", result);
return result;
}
#endif
#if HAVE_DTLSv1_client_method
const SSL_METHOD *sycDTLSv1_client_method(void) {
const SSL_METHOD *result;
Debug("DTLSv1_client_method()");
result = DTLSv1_client_method();
Debug1("DTLSv1_client_method() -> %p", result);
return result;
}
#endif
#if HAVE_DTLSv1_server_method
const SSL_METHOD *sycDTLSv1_server_method(void) {
const SSL_METHOD *result;
Debug("DTLSv1_server_method()");
result = DTLSv1_server_method();
Debug1("DTLSv1_server_method() -> %p", result);
return result;
}
#endif
#if HAVE_DTLSv1_2_client_method
const SSL_METHOD *sycDTLSv1_2_client_method(void) {
const SSL_METHOD *result;
Debug("DTLSv1_2_client_method()");
result = DTLSv1_2_client_method();
Debug1("DTLSv1_2_client_method() -> %p", result);
return result;
}
#endif
#if HAVE_DTLSv1_2_server_method
const SSL_METHOD *sycDTLSv1_2_server_method(void) {
const SSL_METHOD *result;
Debug("DTLSv1_2_server_method()");
result = DTLSv1_2_server_method();
Debug1("DTLSv1_2_server_method() -> %p", result);
return result;
}
#endif
SSL_CTX *sycSSL_CTX_new(const SSL_METHOD *method) {
SSL_CTX *result;
Debug1("SSL_CTX_new(%p)", method);
result = SSL_CTX_new(method);
Debug1("SSL_CTX_new() -> %p", result);
return result;
}
SSL *sycSSL_new(SSL_CTX *ctx) {
SSL *result;
Debug1("SSL_new(%p)", ctx);
result = SSL_new(ctx);
Debug1("SSL_new() -> %p", result);
return result;
}
int sycSSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
const char *CApath) {
int result;
Debug7("SSL_CTX_load_verify_locations(%p, %s%s%s, %s%s%s)", ctx,
CAfile?"\"":"", CAfile?CAfile:"", CAfile?"\"":"",
CApath?"\"":"", CApath?CApath:"", CApath?"\"":"");
result = SSL_CTX_load_verify_locations(ctx, CAfile, CApath);
Debug1("SSL_CTX_load_verify_locations() -> %d", result);
return result;
}
int sycSSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type) {
int result;
Debug3("SSL_CTX_use_certificate_file(%p, \"%s\", %d)", ctx, file, type);
result = SSL_CTX_use_certificate_file(ctx, file, type);
Debug1("SSL_CTX_use_certificate_file() -> %d", result);
return result;
}
int sycSSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) {
int result;
Debug2("SSL_CTX_use_certificate_chain_file(%p, \"%s\")", ctx, file);
result = SSL_CTX_use_certificate_chain_file(ctx, file);
Debug1("SSL_CTX_use_certificate_chain_file() -> %d", result);
return result;
}
int sycSSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) {
int result;
Debug3("SSL_CTX_use_PrivateKey_file(%p, \"%s\", %d)", ctx, file, type);
result = SSL_CTX_use_PrivateKey_file(ctx, file, type);
Debug1("SSL_CTX_use_PrivateKey_file() -> %d", result);
return result;
}
void sycSSL_CTX_set_verify(SSL_CTX *ctx, int mode,
int (*verify_callback)(int, X509_STORE_CTX *)) {
Debug3("SSL_CTX_set_verify(%p, %u, %p)", ctx, mode, verify_callback);
SSL_CTX_set_verify(ctx, mode, verify_callback);
Debug("SSL_CTX_set_verify() -> ");
}
int sycSSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) {
int result;
Debug2("SSL_CTX_set_cipher_list(%p, \"%s\")", ctx, str);
result = SSL_CTX_set_cipher_list(ctx, str);
Debug1("SSL_CTX_set_cipher_list() -> %d", result);
return result;
}
int sycSSL_CTX_set_tmp_dh(SSL_CTX *ctx, DH *dh) {
int result;
Debug2("SSL_CTX_set_tmp_dh(%p, %p)", ctx, dh);
result = SSL_CTX_set_tmp_dh(ctx, dh);
Debug1("SSL_CTX_set_tmp_dh() -> %d", result);
return result;
}
#if HAVE_SSL_CTX_set_tlsext_max_fragment_length || defined(SSL_CTX_set_tlsext_max_fragment_length)
int sycSSL_CTX_set_tlsext_max_fragment_length(SSL_CTX *ctx, uint8_t mode) {
int result;
Debug2("SSL_CTX_set_tlsext_max_fragment_length(%p, %u)", ctx, mode);
result = SSL_CTX_set_tlsext_max_fragment_length(ctx, mode);
Debug1("SSL_CTX_set_tlsext_max_fragment_length() -> %d", result);
return result;
}
#endif
#if HAVE_SSL_CTX_set_max_send_fragment || defined(SSL_CTX_set_max_send_fragment)
int sycSSL_CTX_set_max_send_fragment(SSL_CTX *ctx, long msf) {
int result;
Debug2("SSL_CTX_set_max_send_fragment(%p, %ld)", ctx, msf);
result = SSL_CTX_set_max_send_fragment(ctx, msf);
Debug1("SSL_CTX_set_max_send_fragment() -> %d", result);
return result;
}
#endif
int sycSSL_set_cipher_list(SSL *ssl, const char *str) {
int result;
Debug2("SSL_set_cipher_list(%p, \"%s\")", ssl, str);
result = SSL_set_cipher_list(ssl, str);
Debug1("SSL_set_cipher_list() -> %d", result);
return result;
}
long sycSSL_get_verify_result(SSL *ssl) {
long result;
Debug1("SSL_get_verify_result(%p)", ssl);
result = SSL_get_verify_result(ssl);
Debug1("SSL_get_verify_result() -> %lx", result);
return result;
}
int sycSSL_set_fd(SSL *ssl, int fd) {
int result;
Debug2("SSL_set_fd(%p, %d)", ssl, fd);
result = SSL_set_fd(ssl, fd);
Debug1("SSL_set_fd() -> %d", result);
return result;
}
int sycSSL_connect(SSL *ssl) {
int result;
Debug1("SSL_connect(%p)", ssl);
result = SSL_connect(ssl);
Debug1("SSL_connect() -> %d", result);
return result;
}
int sycSSL_accept(SSL *ssl) {
int result;
Debug1("SSL_accept(%p)", ssl);
result = SSL_accept(ssl);
Debug1("SSL_accept() -> %d", result);
return result;
}
int sycSSL_read(SSL *ssl, void *buf, int num) {
int result;
Debug3("SSL_read(%p, %p, %d)", ssl, buf, num);
result = SSL_read(ssl, buf, num);
Debug1("SSL_read() -> %d", result);
return result;
}
int sycSSL_pending(SSL *ssl) {
int result;
Debug1("SSL_pending(%p)", ssl);
result = SSL_pending(ssl);
Debug1("SSL_pending() -> %d", result);
return result;
}
int sycSSL_write(SSL *ssl, const void *buf, int num) {
int result;
Debug3("SSL_write(%p, %p, %d)", ssl, buf, num);
result = SSL_write(ssl, buf, num);
Debug1("SSL_write() -> %d", result);
return result;
}
X509 *sycSSL_get_peer_certificate(SSL *ssl) {
X509 *result;
Debug1("SSL_get_peer_certificate(%p)", ssl);
result = SSL_get_peer_certificate(ssl);
if (result) {
Debug1("SSL_get_peer_certificate() -> %p", result);
} else {
Debug("SSL_get_peer_certificate() -> NULL");
}
return result;
}
int sycSSL_shutdown(SSL *ssl) {
int result;
Debug1("SSL_shutdown(%p)", ssl);
result = SSL_shutdown(ssl);
Debug1("SSL_shutdown() -> %d", result);
return result;
}
void sycSSL_CTX_free(SSL_CTX *ctx) {
Debug1("SSL_CTX_free(%p)", ctx);
SSL_CTX_free(ctx);
Debug("SSL_CTX_free() -> void");
return;
}
void sycSSL_free(SSL *ssl) {
Debug1("SSL_free(%p)", ssl);
SSL_free(ssl);
Debug("SSL_free() -> void");
return;
}
#if !defined(OPENSSL_NO_EGD) && HAVE_RAND_egd
int sycRAND_egd(const char *path) {
int result;
Debug1("RAND_egd(\"%s\")", path);
result = RAND_egd(path);
Debug1("RAND_egd() -> %d", result);
return result;
}
#endif
DH *sycPEM_read_bio_DHparams(BIO *bp, DH **x, pem_password_cb *cb, void *u) {
DH *result;
Debug4("PEM_read_bio_DHparams(%p, %p, %p, %p)",
bp, x, cb, u);
result = PEM_read_bio_DHparams(bp, x, cb, u);
if (result) {
/*Debug2("PEM_read_bio_DHparams(, {%p},,) -> %p", *x, result);*/
Debug1("PEM_read_bio_DHparams() -> %p", result);
} else {
Debug("PEM_read_bio_DHparams() -> NULL");
}
return result;
}
BIO *sycBIO_new_file(const char *filename, const char *mode) {
BIO *result;
Debug2("BIO_new_file(\"%s\", \"%s\")", filename, mode);
result = BIO_new_file(filename, mode);
if (result) {
Debug1("BIO_new_file() -> %p", result);
} else {
Debug("BIO_new_file() -> NULL");
}
return result;
}
#if WITH_FIPS
int sycFIPS_mode_set(int onoff) {
int result;
Debug1("FIPS_mode_set(%d)", onoff);
result = FIPS_mode_set(onoff);
Debug1("FIPS_mode_set() -> %d", result);
return result;
}
#endif /* WITH_FIPS */
#if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_COMP)
const COMP_METHOD *sycSSL_get_current_compression(SSL *ssl) {
const COMP_METHOD *result;
Debug1("SSL_get_current_compression(%p)", ssl);
result = SSL_get_current_compression(ssl);
if (result) {
Debug1("SSL_get_current_compression() -> %p", result);
} else {
Debug("SSL_get_current_compression() -> NULL");
}
return result;
}
const COMP_METHOD *sycSSL_get_current_expansion(SSL *ssl) {
const COMP_METHOD *result;
Debug1("SSL_get_current_expansion(%p)", ssl);
result = SSL_get_current_expansion(ssl);
if (result) {
Debug1("SSL_get_current_expansion() -> %p", result);
} else {
Debug("SSL_get_current_expansion() -> NULL");
}
return result;
}
const char *sycSSL_COMP_get_name(const COMP_METHOD *comp) {
const char *result;
Debug1("SSL_COMP_get_name(%p)", comp);
result = SSL_COMP_get_name(comp);
if (result) {
Debug1("SSL_COMP_get_name() -> \"%s\"", result);
} else {
Debug("SSL_COMP_get_name() -> NULL");
}
return result;
}
#endif
#endif /* WITH_SYCLS && WITH_OPENSSL */

152
sslcls.h Normal file
View File

@@ -0,0 +1,152 @@
/* source: sslcls.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __sslcls_h_included
#define __sslcls_h_included 1
#if WITH_SYCLS
#if WITH_OPENSSL
#if HAVE_OPENSSL_INIT_SSL
int sycOPENSSL_init_ssl(uint64_t opts, const void *settings);
#endif
void sycSSL_load_error_strings(void);
int sycSSL_library_init(void);
const SSL_METHOD *sycTLS_client_method(void);
const SSL_METHOD *sycTLS_server_method(void);
const SSL_METHOD *sycSSLv2_client_method(void);
const SSL_METHOD *sycSSLv2_server_method(void);
const SSL_METHOD *sycSSLv3_client_method(void);
const SSL_METHOD *sycSSLv3_server_method(void);
const SSL_METHOD *sycSSLv23_client_method(void);
const SSL_METHOD *sycSSLv23_server_method(void);
const SSL_METHOD *sycTLSv1_client_method(void);
const SSL_METHOD *sycTLSv1_server_method(void);
const SSL_METHOD *sycTLSv1_1_client_method(void);
const SSL_METHOD *sycTLSv1_1_server_method(void);
const SSL_METHOD *sycTLSv1_2_client_method(void);
const SSL_METHOD *sycTLSv1_2_server_method(void);
const SSL_METHOD *sycDTLS_client_method(void);
const SSL_METHOD *sycDTLS_server_method(void);
const SSL_METHOD *sycDTLSv1_client_method(void);
const SSL_METHOD *sycDTLSv1_server_method(void);
const SSL_METHOD *sycDTLSv1_2_client_method(void);
const SSL_METHOD *sycDTLSv1_2_server_method(void);
SSL_CTX *sycSSL_CTX_new(const SSL_METHOD *method);
SSL *sycSSL_new(SSL_CTX *ctx);
int sycSSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
const char *CApath);
int sycSSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type);
int sycSSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file);
int sycSSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type);
void sycSSL_CTX_set_verify(SSL_CTX *ctx, int mode,
int (*verify_callback)(int, X509_STORE_CTX *));
int sycSSL_CTX_set_tmp_dh(SSL_CTX *ctx, DH *dh);
int sycSSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str);
#if HAVE_SSL_CTX_set_tlsext_max_fragment_length || defined(SSL_CTX_set_tlsext_max_fragment_length)
int sycSSL_CTX_set_tlsext_max_fragment_length(SSL_CTX *ctx, uint8_t mode);
#endif
#if HAVE_SSL_CTX_set_max_send_fragment || defined(SSL_CTX_set_max_send_fragment)
int sycSSL_CTX_set_max_send_fragment(SSL_CTX *ctx, long msf);
#endif
int sycSSL_set_cipher_list(SSL *ssl, const char *str);
long sycSSL_get_verify_result(SSL *ssl);
int sycSSL_set_fd(SSL *ssl, int fd);
int sycSSL_connect(SSL *ssl);
int sycSSL_accept(SSL *ssl);
int sycSSL_read(SSL *ssl, void *buf, int num);
int sycSSL_pending(SSL *ssl);
int sycSSL_write(SSL *ssl, const void *buf, int num);
X509 *sycSSL_get_peer_certificate(SSL *ssl);
int sycSSL_shutdown(SSL *ssl);
void sycSSL_CTX_free(SSL_CTX *ctx);
void sycSSL_free(SSL *ssl);
int sycRAND_egd(const char *path);
DH *sycPEM_read_bio_DHparams(BIO *bp, DH **x, pem_password_cb *cb, void *u);
BIO *sycBIO_new_file(const char *filename, const char *mode);
int sycFIPS_mode_set(int onoff);
#if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_COMP)
const COMP_METHOD *sycSSL_get_current_compression(SSL *ssl);
const COMP_METHOD *sycSSL_get_current_expansion(SSL *ssl);
const char *sycSSL_COMP_get_name(const COMP_METHOD *comp);
#endif
#endif /* WITH_OPENSSL */
#else /* !WITH_SYCLS */
#if WITH_OPENSSL
#define sycOPENSSL_init_ssl(o,s) OPENSSL_init_ssl(o,s)
#define sycSSL_load_error_strings() SSL_load_error_strings()
#define sycSSL_library_init() SSL_library_init()
#define sycTLS_client_method() TLS_client_method()
#define sycTLS_server_method() TLS_server_method()
#define sycSSLv2_client_method() SSLv2_client_method()
#define sycSSLv2_server_method() SSLv2_server_method()
#define sycSSLv3_client_method() SSLv3_client_method()
#define sycSSLv3_server_method() SSLv3_server_method()
#define sycSSLv23_client_method() SSLv23_client_method()
#define sycSSLv23_server_method() SSLv23_server_method()
#define sycTLSv1_client_method() TLSv1_client_method()
#define sycTLSv1_server_method() TLSv1_server_method()
#define sycTLSv1_1_client_method() TLSv1_1_client_method()
#define sycTLSv1_1_server_method() TLSv1_1_server_method()
#define sycTLSv1_2_client_method() TLSv1_2_client_method()
#define sycTLSv1_2_server_method() TLSv1_2_server_method()
#define sycDTLS_client_method() DTLS_client_method()
#define sycDTLS_server_method() DTLS_server_method()
#define sycDTLSv1_client_method() DTLSv1_client_method()
#define sycDTLSv1_server_method() DTLSv1_server_method()
#define sycDTLSv1_2_client_method() DTLSv1_2_client_method()
#define sycDTLSv1_2_server_method() DTLSv1_2_server_method()
#define sycSSL_CTX_new(m) SSL_CTX_new(m)
#define sycSSL_new(c) SSL_new(c)
#define sycSSL_CTX_load_verify_locations(c,f,p) SSL_CTX_load_verify_locations(c,f,p)
#define sycSSL_CTX_use_certificate_file(c,f,t) SSL_CTX_use_certificate_file(c,f,t)
#define sycSSL_CTX_use_certificate_chain_file(c,f) SSL_CTX_use_certificate_chain_file(c,f)
#define sycSSL_CTX_use_PrivateKey_file(c,f,t) SSL_CTX_use_PrivateKey_file(c,f,t)
#define sycSSL_CTX_set_verify(c,m,v) SSL_CTX_set_verify(c,m,v)
#define sycSSL_CTX_set_tmp_dh(c,d) SSL_CTX_set_tmp_dh(c,d)
#define sycSSL_CTX_set_cipher_list(c,s) SSL_CTX_set_cipher_list(c,s)
#if HAVE_SSL_CTX_set_tlsext_max_fragment_length || defined(SSL_CTX_set_tlsext_max_fragment_length)
#define sycSSL_CTX_set_tlsext_max_fragment_length(c,m) SSL_CTX_set_tlsext_max_fragment_length(c, m)
#endif
#if HAVE_SSL_CTX_set_max_send_fragment || defined(SSL_CTX_set_max_send_fragment)
#define sycSSL_CTX_set_max_send_fragment(c,m) SSL_CTX_set_max_send_fragment(c, m)
#endif
#define sycSSL_set_cipher_list(s,t) SSL_set_cipher_list(s,t)
#define sycSSL_get_verify_result(s) SSL_get_verify_result(s)
#define sycSSL_set_fd(s,f) SSL_set_fd(s,f)
#define sycSSL_connect(s) SSL_connect(s)
#define sycSSL_accept(s) SSL_accept(s)
#define sycSSL_read(s,b,n) SSL_read(s,b,n)
#define sycSSL_pending(s) SSL_pending(s)
#define sycSSL_write(s,b,n) SSL_write(s,b,n)
#define sycSSL_get_peer_certificate(s) SSL_get_peer_certificate(s)
#define sycSSL_shutdown(s) SSL_shutdown(s)
#define sycSSL_CTX_free(c) SSL_CTX_free(c)
#define sycSSL_free(s) SSL_free(s)
#define sycRAND_egd(p) RAND_egd(p)
#define sycPEM_read_bio_DHparams(b,x,p,u) PEM_read_bio_DHparams(b,x,p,u)
#define sycBIO_new_file(f,m) BIO_new_file(f,m)
#define sycSSL_get_current_compression(s) SSL_get_current_compression(s)
#define sycSSL_get_current_expansion(s) SSL_get_current_expansion(s)
#define sycSSL_COMP_get_name(c) SSL_COMP_get_name(c)
#endif /* WITH_OPENSSL */
#define sycFIPS_mode_set(o) FIPS_mode_set(o)
#endif /* !WITH_SYCLS */
#endif /* !defined(__sslcls_h_included) */

1883
sycls.c Normal file

File diff suppressed because it is too large Load Diff

288
sycls.h Normal file
View File

@@ -0,0 +1,288 @@
/* source: sycls.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __sycls_h_included
#define __sycls_h_included 1
#if WITH_SYCLS
struct termios; /* prevent gcc from spitting silly warning */
struct utsname;
struct flock;
struct addrinfo;
int Posix_memalign(void **memptr, size_t alignment, size_t size);
mode_t Umask(mode_t mask);
#endif /* WITH_SYCLS */
int Open(const char *pathname, int flags, mode_t mode);
#if WITH_SYCLS
int Creat(const char *pathname, mode_t mode);
off_t Lseek(int fildes, off_t offset, int whence);
#if HAVE_LSEEK64
off64_t Lseek64(int fildes, off64_t offset, int whence);
#endif
pid_t Getpid(void);
pid_t Getppid(void);
pid_t Getpgrp(void);
int Getpgid(pid_t pid);
int Setpgid(pid_t pid, pid_t pgid);
int Setpgrp(void);
pid_t Tcgetpgrp(int fd);
int Tcsetpgrp(int fd, pid_t pgrpid);
pid_t Getsid(pid_t pid);
pid_t Setsid(void);
uid_t Getuid(void);
uid_t Geteuid(void);
int Setuid(uid_t uid);
gid_t Getgid(void);
gid_t Getegid(void);
int Setgid(gid_t gid);
int Initgroups(const char *user, gid_t group);
int Getgroups(int size, gid_t list[]);
int Setgroups(size_t size, const gid_t *list);
int Getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups);
int Chdir(const char *path);
int Chroot(const char *path);
int Gettimeofday(struct timeval *tv, struct timezone *tz);
int Mknod(const char *pathname, mode_t mode, dev_t dev);
int Mkfifo(const char *pathname, mode_t mode);
int Stat(const char *file_name, struct stat *buf);
int Fstat(int filedes, struct stat *buf);
int Lstat(const char *file_name, struct stat *buf);
#if HAVE_STAT64
int Stat64(const char *file_name, struct stat64 *buf);
int Fstat64(int filedes, struct stat64 *buf);
int Lstat64(const char *file_name, struct stat64 *buf);
#endif /* HAVE_STAT64 */
int Dup(int oldfd);
int Dup2(int oldfd, int newfd);
int Pipe(int filedes[2]);
#endif /* WITH_SYCLS */
ssize_t Read(int fd, void *buf, size_t count);
ssize_t Write(int fd, const void *buf, size_t count);
int Fcntl(int fd, int cmd);
int Fcntl_i(int fd, int cmd, int arg);
int Fcntl_l(int fd, int cmd, long arg);
int Fcntl_lock(int fd, int cmd, struct flock *l);
#if WITH_SYCLS
int Ftruncate(int fd, off_t length);
#if HAVE_FTRUNCATE64
int Ftruncate64(int fd, off64_t length);
#endif /* HAVE_FTRUNCATE64 */
#endif /* WITH_SYCLS */
int Flock(int fd, int operation);
int Ioctl(int d, int request, void *argp);
int Ioctl_int(int d, int request, int arg);
#if WITH_SYCLS
int Close(int fd);
int Fchown(int fd, uid_t owner, gid_t group);
int Fchmod(int fd, mode_t mode);
int Unlink(const char *pathname);
int Symlink(const char *oldpath, const char *newpath);
int Readlink(const char *path, char *buf, size_t bufsiz);
int Chown(const char *path, uid_t owner, gid_t group);
int Chmod(const char *path, mode_t mode);
#endif /* WITH_SYCLS */
int Poll(struct pollfd *ufds, unsigned int nfds, int timeout);
int Select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout);
int Pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
const struct timespec *timeout, const sigset_t *sigmask);
#if WITH_SYCLS
pid_t Fork(void);
#endif /* WITH_SYCLS */
pid_t Waitpid(pid_t pid, int *status, int options);
#if WITH_SYCLS
#ifndef HAVE_TYPE_SIGHANDLER
typedef RETSIGTYPE (*sighandler_t)(int);
#endif
sighandler_t Signal(int signum, sighandler_t handler);
int Sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
int Sigprocmask(int how, const sigset_t *set, sigset_t *oset);
unsigned int Alarm(unsigned int seconds);
int Kill(pid_t pid, int sig);
int Link(const char *oldpath, const char *newpath);
int Execvp(const char *file, char *const argv[]);
#endif /* WITH_SYCLS */
int System(const char *string);
#if WITH_SYCLS
int Socketpair(int d, int type, int protocol, int sv[2]);
#endif /* WITH_SYCLS */
#if _WITH_SOCKET
#if WITH_SYCLS
int Socket(int domain, int type, int protocol);
int Bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
#endif /* WITH_SYCLS */
int Connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
#if WITH_SYCLS
int Listen(int s, int backlog);
#endif /* WITH_SYCLS */
int Accept(int s, struct sockaddr *addr, socklen_t *addrlen);
#if WITH_SYCLS
int Getsockname(int s, struct sockaddr *name, socklen_t *namelen);
int Getpeername(int s, struct sockaddr *name, socklen_t *namelen);
int Getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen);
int Setsockopt(int s, int level, int optname, const void *optval, int optlen);
#endif /* WITH_SYCLS */
int Recv(int s, void *buf, size_t len, int flags);
int Recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from,
socklen_t *fromlen);
int Recvmsg(int s, struct msghdr *msg, int flags);
int Send(int s, const void *mesg, size_t len, int flags);
int Sendto(int s, const void *msg, size_t len, int flags,
const struct sockaddr *to, socklen_t tolen);
#if WITH_SYCLS
int Shutdown(int fd, int how);
#endif /* WITH_SYCLS */
#endif /* _WITH_SOCKET */
#if WITH_SYCLS
unsigned int Sleep(unsigned int seconds);
unsigned int Nanosleep(const struct timespec *req, struct timespec *rem);
int Pause(void);
struct hostent *Gethostbyname(const char *name);
int Getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints, struct addrinfo **res);
struct hostent *Getipnodebyname(const char *name, int af, int flags,
int *error_num);
void *Malloc(size_t size);
void *Calloc(size_t nmemb, size_t size);
void *Realloc(void *ptr, size_t size);
int Tcgetattr(int fd, struct termios *termios_p);
int Tcsetattr(int fd, int optional_actions, struct termios *termios_p);
char *Ttyname(int fd);
int Isatty(int fd);
struct winsize; /* avoid warnings */
int Openpty(int *ptyfd, int *ttyfd, char *ptyname, struct termios *termp,
struct winsize *winp);
char *Ptsname(int fd);
int Grantpt(int fd);
int Unlockpt(int fd);
int Gethostname(char *name, size_t len);
int Uname(struct utsname *buf);
int Atexit(void (*func)(void));
#endif /* WITH_SYCLS */
void Exit(int status);
#if WITH_SYCLS
void Abort(void);
int Mkstemp(char *template);
int Setenv(const char *name, const char *value, int overwrite);
void Unsetenv(const char *name);
int Setns(int fd, int nstype);
#endif /* WITH_SYCLS */
#if WITH_SYCLS
char *Readline(const char *prompt);
void Using_history(void);
int Read_history(const char *filename);
int Write_history(const char *filename);
int Append_history(int nelements, const char *filename);
int Read_history(const char *filename);
void Add_history(const char *string);
#else /* !WITH_SYCLS */
#define Posix_memalign(m,a,s) posix_memalign(m,a,s)
#define Umask(m) umask(m)
#define Creat(p,m) creat(p,m)
#define Lseek(f,o,w) lseek(f,o,w)
#define Lseek64(f,o,w) lseek64(f,o,w)
#define Getpid() getpid()
#define Getppid() getppid()
#define Getpgrp() getpgrp()
#define Getpgid(p) getpgid(p)
#define Setpgid(p,g) setpgid(p,g)
#define Setpgrp() setpgrp()
#define Tcgetpgrp(f) tcgetpgrp(f)
#define Tcsetpgrp(f,p) tcsetpgrp(f,p)
#define Getsid(p) getsid(p)
#define Setsid() setsid()
#define Getuid() getuid()
#define Geteuid() geteuid()
#define Setuid(u) setuid(u)
#define Getgid() getgid()
#define Getegid() getegid()
#define Setgid(g) setgid(g)
#define Initgroups(u,g) initgroups(u,g)
#define Getgroups(s,l) getgroups(s,l)
#define Setgroups(s,l) setgroups(s,l)
#define Getgrouplist(u,g,gs,n) getgrouplist(u,g,gs,n)
#define Chdir(p) chdir(p)
#define Chroot(p) chroot(p)
#define Gettimeofday(tv,tz) gettimeofday(tv,tz)
#define Mknod(p,m,d) mknod(p,m,d)
#define Mkfifo(p,m) mkfifo(p,m)
#define Stat(f,b) stat(f,b)
#define Stat64(f,b) stat64(f,b)
#define Fstat(f,b) fstat(f,b)
#define Fstat64(f,b) fstat64(f,b)
#define Lstat(f,b) lstat(f,b)
#define Lstat64(f,b) lstat64(f,b)
#define Dup(o) dup(o)
#define Dup2(o,n) dup2(o,n)
#define Pipe(f) pipe(f)
#define Ftruncate(f,l) ftruncate(f,l)
#define Ftruncate64(f,l) ftruncate64(f,l)
#define Close(f) close(f)
#define Fchown(f,o,g) fchown(f,o,g)
#define Fchmod(f,m) fchmod(f,m)
#define Unlink(p) unlink(p)
#define Symlink(op,np) symlink(op,np)
#define Readlink(p,b,s) readlink(p,b,s)
#define Chown(p,o,g) chown(p,o,g)
#define Chmod(p,m) chmod(p,m)
#define Fork() fork()
#define Signal(s,h) signal(s,h)
#define Sigaction(s,a,o) sigaction(s,a,o)
#define Sigprocmask(h,s,o) sigprocmask(h,s,o)
#define Alarm(s) alarm(s)
#define Kill(p,s) kill(p,s)
#define Link(o,n) link(o,n)
#define Execvp(f,a) execvp(f,a)
#define Socketpair(d,t,p,s) socketpair(d,t,p,s)
#define Socket(d,t,p) socket(d,t,p)
#define Bind(s,m,a) bind(s,m,a)
#define Listen(s,b) listen(s,b)
#define Getsockname(s,n,l) getsockname(s,n,l)
#define Getpeername(s,n,l) getpeername(s,n,l)
#define Getsockopt(s,d,n,v,l) getsockopt(s,d,n,v,l)
#define Setsockopt(s,d,n,v,l) setsockopt(s,d,n,v,l)
#define Shutdown(f,h) shutdown(f,h)
#define Sleep(s) sleep(s)
#define Nanosleep(req,rem) nanosleep(req,rem)
#define Pause() pause()
#define Gethostbyname(n) gethostbyname(n)
#define Getaddrinfo(n,s,h,r) getaddrinfo(n,s,h,r)
#define Getipnodebyname(n,a,f,e) getipnodebyname(n,a,f,e)
#define Malloc(s) malloc(s)
#define Calloc(n,s) calloc(n,s)
#define Realloc(p,s) realloc(p,s)
#define Tcgetattr(f,t) tcgetattr(f,t)
#define Tcsetattr(f,o,t) tcsetattr(f,o,t)
#define Ttyname(f) ttyname(f)
#define Isatty(f) isatty(f)
#define Openpty(p,t,n,i,f) openpty(p,t,n,i,f)
#define Ptsname(f) ptsname(f)
#define Grantpt(f) grantpt(f)
#define Unlockpt(f) unlockpt(f)
#define Getpgid(p) getpgid(p)
#define Gethostname(n,l) gethostname(n,l)
#define Uname(b) uname(b)
#define Atexit(f) atexit(f)
#define Abort() abort()
#define Mkstemp(t) mkstemp(t)
#define Setenv(n,v,o) setenv(n,v,o)
#define Unsetenv(n) unsetenv(n)
#define Setns(f,n) setns(f,n)
#define Readline(p) readline(p)
#define Using_history() using_history()
#define Read_history(f) read_history(f)
#define Write_history(f) write_history(f)
#define Append_history(n,f) append_history(n,f)
#define Read_history(f) read_history(f)
#define Add_history(s) add_history(s)
#endif /* !WITH_SYCLS */
#endif /* !defined(__sycls_h_included) */

207
sysincludes.h Normal file
View File

@@ -0,0 +1,207 @@
/* source: sysincludes.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __sysincludes_h_included
#define __sysincludes_h_included 1
/* Sorry for this... */
#if defined(__sun) || defined(__sun__) || defined(__SunOS)
# define BSD_COMP 1 /* for SIOCGIFFLAGS */
#endif
#include <stddef.h> /* ptrdiff_t */
#if HAVE_STDBOOL_H
#include <stdbool.h> /* bool, true, false */
#endif
#if HAVE_INTTYPES_H
#include <inttypes.h> /* uint16_t */
#endif
#if HAVE_LIMITS_H
#include <limits.h> /* USHRT_MAX */
#endif
#include <math.h> /* HUGE_VAL */
#include <assert.h>
#include <stdarg.h> /* for msg() */
#include <string.h> /* strerror(), strchr() */
#if HAVE_STRINGS_H
#include <strings.h> /* strcasecmp(), bzero() for FD_ZERO */
#endif
#include <stdlib.h> /* malloc(), free() */
#include <ctype.h> /* isdigit() */
#include <stdio.h> /* FILE */
#include <errno.h> /* errno */
#if HAVE_SYSLOG_H
#include <syslog.h> /* openlog(), syslog(), closelog() */
#endif
#include <signal.h> /* signal(), SIGPIPE, SIG_IGN */
#include <time.h> /* struct timeval, strftime(), clock_gettime() */
#if 0
#include <sys/timeb.h> /* struct timeb */
#endif
#if HAVE_UNISTD_H
#include <unistd.h> /* select(), read(), write(), stat(), fork() */
#endif
#if HAVE_PWD_H
#include <pwd.h> /* getpwnam() */
#endif
#if HAVE_GRP_H
#include <grp.h> /* getgrnam() */
#endif
#if HAVE_PTY_H && (_WITH_TERMIOS || HAVE_OPENPTY)
#include <pty.h>
#endif
#if HAVE_SYS_PARAM_H
#include <sys/param.h> /* Linux 2.4 NGROUPS */
#endif
#if HAVE_SYS_TIME_H
#include <sys/time.h> /* select(); OpenBSD: struct timespec */
#endif
#if HAVE_STDINT_H
#include <stdint.h> /* uint8_t */
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h> /* pid_t, select(), socket(), connect(), open(), u_short */
#endif
#if HAVE_POLL_H
#include <poll.h> /* poll() */
#elif HAVE_SYS_POLL_H
#include <sys/poll.h> /* poll() */
#endif
#if HAVE_SYS_SOCKET_H
#include <sys/socket.h> /* struct sockaddr, struct linger, socket(), connect() */
#endif
#if HAVE_SYS_UIO_H
#include <sys/uio.h> /* struct iovec */
#endif
#if HAVE_SYS_STAT_H
#include <sys/stat.h> /* struct stat, stat(), open() */
#endif
#if HAVE_SYS_WAIT_H
#include <sys/wait.h> /* WNOHANG */
#endif
#if HAVE_FCNTL_H
#include <fcntl.h> /* open(), O_RDWR */
#endif
#if HAVE_NETDB_H && (_WITH_IP4 || _WITH_IP6)
#include <netdb.h> /* struct hostent, gethostbyname() */
#endif
#if HAVE_SYS_UN_H && WITH_UNIX
#include <sys/un.h> /* struct sockaddr_un, unix domain sockets */
#endif
#if HAVE_SYS_IOCTL_H
#include <sys/ioctl.h> /* ioctl() */
#endif
#if HAVE_SYS_SELECT_H
#include <sys/select.h> /* select(), fdset on AIX 4.1 */
#endif
#if HAVE_SYS_FILE_H
#include <sys/file.h> /* LOCK_EX, on AIX directly included */
#endif
#if WITH_IP4 || WITH_IP6
# if HAVE_NETINET_IN_H
#include <netinet/in.h> /* struct sockaddr_in, htonl() */
# endif
#endif /* _WITH_SOCKET */
#if _WITH_SOCKET && (_WITH_IP4 || _WITH_IP6)
# if HAVE_NETINET_IN_SYSTM_H
#include <netinet/in_systm.h> /* Solaris, FreeBSD: n_long */
# endif
# if HAVE_NETINET_IP_H
#include <netinet/ip.h> /* struct ip - past netinet/in.h on AIX! */
# endif
# if HAVE_NETINET_TCP_H
#include <netinet/tcp.h> /* TCP_RFC1323 */
# endif
# if HAVE_NETINET_IP6_H && _WITH_IP6
#include <netinet/ip6.h>
# endif
# if HAVE_NETINET6_IN6_H && _WITH_IP6
#include <netinet6/in6.h>
# endif
#include <arpa/inet.h> /* Linux: inet_aton() */
#if HAVE_ARPA_NAMESER_H
#include <arpa/nameser.h> /* req for resolv.h (esp. on MacOSX) */
#endif
#include <net/if.h>
#if HAVE_NET_IF_DL_H
#include <net/if_dl.h> /* FreeBSD: struct sockaddr_dl */
#endif
#if HAVE_RESOLV_H
#include <resolv.h> /* _res */
#endif
#endif /* _WITH_IP4 || _WITH_IP6 */
/*#include <linux/sockios.h>*/
#if HAVE_NET_IF_H
#include <net/if.h>
#endif /* HAVE_NET_IF_H */
#if HAVE_LINUX_TYPES_H
#include <linux/types.h> /* __u32 for linux/errqueue.h */
#endif
#if HAVE_LINUX_ERRQUEUE_H
#include <linux/errqueue.h> /* struct sock_extended_err */
#endif
#if HAVE_LINUX_IF_PACKET_H
#include <linux/if_packet.h>
#endif
#if HAVE_NETINET_IF_ETHER_H
#include <netinet/if_ether.h>
#endif
#if HAVE_LINUX_IF_TUN_H
#include <linux/if_tun.h>
#endif
#if HAVE_LINUX_DCCP_H
#include <linux/dccp.h>
#endif
#if HAVE_TERMIOS_H && _WITH_TERMIOS
#include <termios.h>
#endif
#if HAVE_SYS_UTSNAME_H
#include <sys/utsname.h> /* uname(), struct utsname */
#endif
#if HAVE_UTIL_H
#include <util.h> /* NetBSD, OpenBSD openpty() */
#endif
#if HAVE_BSD_LIBUTIL_H
#include <bsd/libutil.h> /* FreeBSD openpty() */
#elif HAVE_LIBUTIL_H
#include <libutil.h> /* FreeBSD openpty() */
#endif
#if HAVE_SYS_STROPTS_H
#include <sys/stropts.h> /* SunOS I_PUSH ... */
#endif
#if HAVE_REGEX_H
#include <regex.h>
#endif
#if HAVE_LINUX_FS_H
#include <linux/fs.h> /* Linux filesystem definitions */
#endif
#if HAVE_LINUX_EXT2_FS_H
#include <linux/ext2_fs.h> /* Linux ext2 filesystem definitions */
#endif
#if WITH_NAMESPACES && HAVE_SCHED_H
#include <sched.h>
#endif
#if WITH_POSIXMQ
#include <mqueue.h> /* POSIX MQ */
#endif
#if WITH_READLINE
# if HAVE_READLINE_READLINE_H
#include <readline/readline.h>
# endif
# if HAVE_READLINE_HISTORY_H
#include <readline/history.h>
# endif
#endif /* WITH_READLINE */
#if WITH_OPENSSL
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/dh.h>
#include <openssl/bn.h>
#endif
#if HAVE_LINUX_VM_SOCKETS_H
#include <linux/vm_sockets.h>
#endif
#endif /* !defined(__sysincludes_h_included) */

1153
sysutils.c Normal file

File diff suppressed because it is too large Load Diff

122
sysutils.h Normal file
View File

@@ -0,0 +1,122 @@
/* source: sysutils.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __sysutils_h_included
#define __sysutils_h_included 1
#if WITH_IP6
/* not all OSes provide in6_addr that allows splitting to 16 or 32 bit junks of
the host address part of sockaddr_in6; here we help ourselves */
union xioin6_u {
uint8_t u6_addr8[16];
uint16_t u6_addr16[8];
uint32_t u6_addr32[4];
} ;
#endif /* WITH_IP6 */
#if _WITH_SOCKET
union sockaddr_union {
struct sockaddr soa;
#if WITH_UNIX
struct sockaddr_un un;
#endif /* WITH_UNIX */
#if _WITH_IP4
struct sockaddr_in ip4;
#endif /* _WITH_IP4 */
#if WITH_IP6
struct sockaddr_in6 ip6;
#endif /* WITH_IP6 */
#if WITH_VSOCK
struct sockaddr_vm vm;
#endif /* WITH_IP6 */
#if _WITH_INTERFACE
struct sockaddr_ll ll;
#endif
} ;
#endif /* _WITH_SOCKET */
#if _WITH_SOCKET
struct xiorange {
union sockaddr_union netaddr;
union sockaddr_union netmask;
} ;
#endif /* _WITH_SOCKET */
#if _WITH_INTERFACE
extern const int one;
#endif
extern ssize_t writefull(int fd, const void *buff, size_t bytes);
#if _WITH_SOCKET
extern socklen_t socket_init(int af, union sockaddr_union *sa);
#endif
#if WITH_UNIX
extern void socket_un_init(struct sockaddr_un *sa);
#endif /* WITH_UNIX */
#if _WITH_IP4
extern void socket_in_init(struct sockaddr_in *sa);
#endif /* _WITH_IP4 */
#if _WITH_IP6
extern void socket_in6_init(struct sockaddr_in6 *sa);
#endif /* _WITH_IP4 */
#if _WITH_SOCKET
extern char *sockaddr_info(const struct sockaddr *sa, socklen_t salen, char *buff, size_t blen);
#endif
#if WITH_UNIX
extern char *sockaddr_unix_info(const struct sockaddr_un *sa, socklen_t salen, char *buff, size_t blen);
#endif /* WITH_UNIX */
#if WITH_IP4
extern char *inet4addr_info(uint32_t addr, char *buff, size_t blen);
extern char *sockaddr_inet4_info(const struct sockaddr_in *sa, char *buff, size_t blen);
#endif /* WITH_IP4 */
#if WITH_IP6
extern char *sockaddr_inet6_info(const struct sockaddr_in6 *sa, char *buff, size_t blen);
#endif /* WITH_IP6 */
#if WITH_VSOCK
extern char *sockaddr_vm_info(const struct sockaddr_vm *sa, char *buff, size_t blen);
extern int sockaddr_vm_parse(struct sockaddr_vm *sa, const char *cid_str,
const char *port_str);
#endif /* WITH_VSOCK */
#if !HAVE_INET_NTOP
extern const char *inet_ntop(int pf, const void *binaddr,
char *addrtext, socklen_t textlen);
#endif
extern int check_ip4addr(const char *address);
extern int check_ip6addr(const char *address);
extern int check_ipaddr(const char *address);
#if defined(HAVE_SETGRENT) && defined(HAVE_GETGRENT) && defined(HAVE_ENDGRENT)
extern int getusergroups(const char *user, gid_t *list, int *ngroups);
#endif
#if !HAVE_HSTRERROR
extern const char *hstrerror(int err);
#endif
extern int xiopoll(struct pollfd fds[], unsigned long nfds, struct timeval *timeout);
extern int parseport(const char *portname, int proto);
extern int ifindexbyname(const char *ifname, int anysock);
extern int ifindex(const char *ifname, unsigned int *ifindex, int anysock);
extern int xiosetenv(const char *varname, const char *value, int overwrite, const char *sep);
extern int
xiosetenv2(const char *varname, const char *varname2, const char *value,
int overwrite, const char *sep);
extern int
xiosetenv3(const char *varname, const char *varname2, const char *varname3,
const char *value, int overwrite, const char *sep);
extern int xiosetenvulong(const char *varname, unsigned long value,
int overwrite);
extern int xiosetenvushort(const char *varname, unsigned short value,
int overwrite);
extern unsigned long int Strtoul(const char *nptr, char **endptr, int base, const char *txt);
extern long long int Strtoll(const char *nptr, char **endptr, int base, const char *txt);
extern double Strtod(const char *nptr, char **endptr, const char *txt);
extern int xio_opensnifffile(const char *a, struct timeval *tv);
#endif /* !defined(__sysutils_h_included) */

19365
test.sh Executable file

File diff suppressed because it is too large Load Diff

181
utils.c Normal file
View File

@@ -0,0 +1,181 @@
/* source: utils.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* useful additions to C library */
#include "config.h"
#include "sysincludes.h"
#include "compat.h" /* socklen_t */
#include "mytypes.h"
#include "sycls.h"
#include "utils.h"
#if !HAVE_PROTOTYPE_LIB_memrchr
/* GNU extension, available since glibc 2.1.91 */
void *memrchr(const void *s, int c, size_t n) {
const unsigned char *t = ((unsigned char *)s)+n;
while (--t >= (unsigned char *)s) {
if (*t == c) break;
}
if (t < (unsigned char *)s)
return NULL;
return (void *)t;
}
#endif /* !HAVE_PROTOTYPE_LIB_memrchr */
void *memdup(const void *src, size_t n) {
void *dest;
if ((dest = Malloc(n)) == NULL) {
return NULL;
}
memcpy(dest, src, n);
return dest;
}
/* search the keyword-table for a match of the leading part of name. */
/* returns the pointer to the matching field of the keyword or NULL if no
keyword was found. */
const struct wordent *keyw(const struct wordent *keywds, const char *name, unsigned int nkeys) {
unsigned int lower, upper, mid;
int r;
lower = 0;
upper = nkeys;
while (upper - lower > 1)
{
mid = (upper + lower) >> 1;
if (!(r = strcasecmp(keywds[mid].name, name)))
{
return &keywds[mid];
}
if (r < 0)
lower = mid;
else
upper = mid;
}
if (nkeys > 0 && !(strcasecmp(keywds[lower].name, name)))
{
return &keywds[lower];
}
return NULL;
}
/* Linux: setenv(), AIX (4.3?): putenv() */
#if !HAVE_SETENV
int setenv(const char *name, const char *value, int overwrite) {
int result;
char *env;
if (!overwrite) {
if (getenv(name)) return 0; /* already exists */
}
if ((env = Malloc(strlen(name)+strlen(value)+2)) == NULL) {
return -1;
}
sprintf(env, "%s=%s", name, value);
if ((result = putenv(env)) != 0) { /* AIX docu says "... nonzero ..." */
free(env);
result = -1;
}
/* linux "man putenv" says: ...this string becomes part of the environment*/
return result;
}
#endif /* !HAVE_SETENV */
/* sanitizes an "untrusted" character. output buffer must provide at least 4
characters space.
Does not append \0. returns length of output (currently: max 4) */
static size_t sanitize_char(char c, char *o, int style) {
int hn; /* high nibble */
int ln; /* low nibble */
int n; /* written chars */
if (isprint((unsigned char)c)) {
*o = c;
return 1;
}
*o++ = '\\';
n = 2;
switch (c) {
case '\0': *o++ = '0'; break;
case '\a': *o++ = 'a'; break;
case '\b': *o++ = 'b'; break;
case '\t': *o++ = 't'; break;
case '\n': *o++ = 'n'; break;
case '\v': *o++ = 'v'; break;
case '\f': *o++ = 'f'; break;
case '\r': *o++ = 'r'; break;
case '\'': *o++ = '\''; break;
case '\"': *o++ = '"'; break;
case '\\': *o++ = '\\'; break;
default:
*o++ = 'x';
hn = (c>>4)&0x0f;
ln = c&0x0f;
*o++ = (hn>=10 ? (('A'-1)+(hn-10)) : ('0'+hn));
*o++ = (ln>=10 ? (('A'-1)+(ln-10)) : ('0'+ln));
n = 4;
}
return n;
}
/* sanitizes "untrusted" text, replacing special control characters with the C
string version (eg."\n"), and replacing unprintable chars with hex
representation ("\xAB").
text can grow to four times of input, so keep output buffer long enough!
returns a pointer to the first untouched byte of the output buffer.
Output is not \0 terminated.
*/
char *sanitize_string(const char *data, /* input data */
size_t bytes, /* length of input data, >=0 */
char *coded, /* output buffer, must be long enough */
int style
) {
int c;
while (bytes > 0) {
c = *(unsigned char *)data++;
coded += sanitize_char(c, coded, style);
--bytes;
}
return coded;
}
/* copies a substring out of a given buff
returns scratch, \0 terminated; scratch must provide len+1 bytes
*/
char *xiosubstr(char *scratch, const char *str, size_t from, size_t len) {
char *scratch0 = scratch;
str += from;
while (len--) {
*scratch++ = *str++;
}
*scratch = '\0';
return scratch0;
}
/* since version 1.7.2.4 socat supports C-99 behaviour of snprintf but still
can handle the old glibc case with -1 return on truncation.
Do not rely on exact return value in case of truncation
*/
int xio_snprintf(char *str, size_t size, const char *format, ...) {
va_list ap;
int result;
va_start(ap, format);
result = vsnprintf(str, size, format, ap);
#if ! HAVE_C99_SNPRINTF
if (result < 0) {
result = size+63; /* indicate truncation with just some guess */
}
#endif /* !HAVE_C99_SNPRINTF */
va_end(ap);
return result;
}

72
utils.h Normal file
View File

@@ -0,0 +1,72 @@
/* source: utils.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __utils_h_included
#define __utils_h_included 1
/* a generic name table entry */
struct wordent {
const char *name;
void *desc;
} ;
#if !HAVE_PROTOTYPE_LIB_memrchr
extern void *memrchr(const void *s, int c, size_t n);
#endif
extern void *memdup(const void *src, size_t n);
#if !HAVE_SETENV
extern int setenv(const char *name, const char *value, int overwrite);
#endif /* !HAVE_SETENV */
extern const struct wordent *keyw(const struct wordent *keywds, const char *name, unsigned int nkeys);
#define XIOSAN_ZERO_MASK 0x000f
#define XIOSAN_ZERO_DEFAULT 0x0000
#define XIOSAN_ZERO_DOT 0x0001
#define XIOSAN_ZERO_BACKSLASH_OCT_3 0x0002
#define XIOSAN_ZERO_BACKSLASH_OCT_4 0x0003
#define XIOSAN_ZERO_BACKSLASHX_HEX_UP 0x0004
#define XIOSAN_ZERO_BACKSLASHX_HEX_LOW 0x0005
#define XIOSAN_ZERO_PERCENT_HEX_UP 0x0006
#define XIOSAN_ZERO_PERCENT_HEX_LOW 0x0007
#define XIOSAN_CONTROL_MASK 0x00f0
#define XIOSAN_CONTROL_DEFAULT 0x0000
#define XIOSAN_CONTROL_DOT 0x0010
#define XIOSAN_CONTROL_BACKSLASH_OCT_3 0x0020
#define XIOSAN_CONTROL_BACKSLASH_OCT_4 0x0030
#define XIOSAN_CONTROL_BACKSLASHX_HEX_UP 0x0040
#define XIOSAN_CONTROL_BACKSLASHX_HEX_LOW 0x0050
#define XIOSAN_CONTROL_PERCENT_HEX_UP 0x0060
#define XIOSAN_CONTROL_PERCENT_HEX_LOW 0x0070
#define XIOSAN_UNPRINT_MASK 0x0f00
#define XIOSAN_UNPRINT_DEFAULT 0x0000
#define XIOSAN_UNPRINT_DOT 0x0100
#define XIOSAN_UNPRINT_BACKSLASH_OCT_3 0x0200
#define XIOSAN_UNPRINT_BACKSLASH_OCT_4 0x0300
#define XIOSAN_UNPRINT_BACKSLASHX_HEX_UP 0x0400
#define XIOSAN_UNPRINT_BACKSLASHX_HEX_LOW 0x0500
#define XIOSAN_UNPRINT_PERCENT_HEX_UP 0x0600
#define XIOSAN_UNPRINT_PERCENT_HEX_LOW 0x0700
#define XIOSAN_DEFAULT_MASK 0xf000
#define XIOSAN_DEFAULT_BACKSLASH_DOT 0x1000
#define XIOSAN_DEFAULT_BACKSLASH_OCT_3 0x2000
#define XIOSAN_DEFAULT_BACKSLASH_OCT_4 0x3000
#define XIOSAN_DEFAULT_BACKSLASHX_HEX_UP 0x4000
#define XIOSAN_DEFAULT_BACKSLASHX_HEX_LOW 0x5000
#define XIOSAN_DEFAULT_PERCENT_HEX_UP 0x6000
#define XIOSAN_DEFAULT_PERCENT_HEX_LOW 0x7000
extern
char *sanitize_string(const char *data, /* input data */
size_t bytes, /* length of input data, >=0 */
char *coded, /* output buffer, must be long enough */
int style);
extern
char *xiosubstr(char *scratch, const char *str, size_t from, size_t len);
extern
int xio_snprintf(char *str, size_t size, const char *format, ...);
#endif /* !defined(__utils_h_included) */

569
vsnprintf_r.c Normal file
View File

@@ -0,0 +1,569 @@
/* vsnprintf_r.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* a reduced but async-signal-safe and thread-safe version of vsnprintf */
#include "config.h"
#include <stddef.h> /* ptrdiff_t */
#include <ctype.h> /* isdigit() */
#include <stdarg.h>
#include <stdlib.h>
#include <errno.h>
#if HAVE_SYSLOG_H
#include <syslog.h>
#endif
#include <sys/utsname.h>
#include <time.h> /* time_t, strftime() */
#include <sys/time.h> /* gettimeofday() */
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "vsnprintf_r.h"
/* helper functions for vsnprintf_r():
e.g. convert an unsigned long to decimal string.
in: field (must be long enough for all digits and \0
n: length of field in bytes
ulo: the value
returns: the pointer to the result string (need not be ==field)
*/
/* this function converts an unsigned long number to decimal ASCII
it is async signal safe and thread safe
it returns NULL if n==0
it returns NULL if field is too short to hold the result
it returns a pointer to the result string (somewhere within field)
it terminates result with \0
*/
static char *_diag_ulong_to_dec(char *field, size_t n, unsigned long ulo) {
char *np = field+n; /* point to the end */
if (n == 0) return NULL;
*--np = '\0'; /* \0 in last char of string */
/* this is not optimal - uses much CPU, but simple to implement */
/* calculate the result from right to left */
do { if (np==field) return NULL; *--np = '0'+(ulo%10); } while (ulo/=10);
return np;
}
/* this function converts an unsigned long number to decimal ASCII
and pads it with space or '0' when size and leading0 are set appropriately
it is async signal safe and thread safe
it returns NULL if n==0
it returns NULL if field is too short to hold the result
it returns a pointer to the result string (somewhere within field)
it reduces size to n-1 if it is greater or equal
it terminates result with \0
*/
static char *diag_ulong_to_dec(char *field, size_t n, unsigned long ulo, int leading0, int size) {
char *np;
char c;
int i;
if (n == 0) return NULL;
np = _diag_ulong_to_dec(field, n, ulo);
if (np == NULL) return np;
if (size) {
if (size >= n) size = n-1;
if (leading0) {
c = '0';
} else {
c = ' ';
}
i = size - strlen(np);
while (--i >= 0) {
*--np = c;
}
}
return np;
}
/* this function converts a signed long number to decimal ASCII
and pads it with space or '0' when size and leading0 are set appropriately
it is async signal safe and thread safe
it returns NULL if n==0
it returns NULL if field is too short to hold the result
it returns a pointer to the result string (somewhere within field)
it reduces size to n-1 if it is greater or equal
it terminates result with \0
*/
/* like diag_ulong_to_dec but signed; fields need also space for '-' */
static char *diag_long_to_dec(char *field, size_t n, long lo, int leading0, int size) {
char *np;
int minus;
unsigned long ulo;
int i;
if ((minus = (lo < 0))) {
ulo = (~lo)+1;
} else {
ulo = lo;
}
np = _diag_ulong_to_dec(field, n, ulo);
if (np == NULL) return np;
if (size) {
if (size >= n) size = n-1;
i = size - strlen(np);
if (leading0) {
if (minus) --i;
while (--i >= 0) {
*--np = '0';
}
if (minus) *--np = '-';
} else {
if (minus) { *--np = '-'; --i; }
while (--i >= 0) {
*--np = ' ';
}
}
} else {
if (minus) *--np = '-';
}
return np;
}
/* this function converts an unsigned long number to hexadecimal ASCII
it is async signal safe and thread safe
it returns NULL if n==0
it returns NULL if field is too short to hold the result
it returns a pointer to the result string (somewhere within field)
it terminates result with \0
*/
static char *diag_ulong_to_hex(char *field, size_t n, unsigned long ulo, int leading0, size_t size) {
char *np = field+n; /* point to the end */
int i;
char c;
if (n == 0) return NULL;
*--np = '\0'; /* \0 in last char of string */
/* calculate the result from right to left */
do { if (np==field) return NULL; i = (ulo&0x0f);
*--np = (i<10?'0':('a'-10))+i; }
while (ulo>>=4);
if (size) {
if (size >= n) size = n-1;
if (leading0) {
c = '0';
} else {
c = ' ';
}
i = size - strlen(np);
while (--i >= 0) {
*--np = c;
}
}
return np;
}
/* this function converts an unsigned long number to octal ASCII
it is async signal safe and thread safe
it returns NULL if n==0
it returns NULL if field is too short to hold the result
it returns a pointer to the result string (somewhere within field)
it terminates result with \0
*/
static char *diag_ulong_to_oct(char *field, size_t n, unsigned long ulo, int leading0, size_t size) {
char *np = field+n; /* point to the end */
int i;
char c;
if (n == 0) return NULL;
*--np = '\0'; /* \0 in last char of string */
/* calculate the result from right to left */
do { if (np==field) return NULL; i = (ulo&0x07); *--np = '0'+i; }
while (ulo>>=3);
if (size) {
if (size >= n) size = n-1;
if (leading0) {
c = '0';
} else {
c = ' ';
}
i = size - strlen(np);
while (--i >= 0) {
*--np = c;
}
}
return np;
}
#if HAVE_TYPE_LONGLONG
/* this function converts an unsigned long long number to decimal ASCII
it is async signal safe and thread safe
it returns NULL if n==0
it returns NULL if field is too short to hold the result
it returns a pointer to the result string (somewhere within field)
it terminates result with \0
*/
static char *_diag_ulonglong_to_dec(char *field, size_t n, unsigned long long ull) {
char *np = field+n; /* point to the end */
if (n == 0) return NULL;
*--np = '\0'; /* \0 in last char of string */
/* this is not optimal - uses much CPU, but simple to implement */
/* calculate the result from right to left */
do { if (np==field) return NULL; *--np = '0'+(ull%10); } while (ull/=10);
return np;
}
/* this function converts an unsigned long long number to decimal ASCII
and pads it with space or '0' when size and leading0 are set appropriately
it is async signal safe and thread safe
it returns NULL if n==0
it returns NULL if field is too short to hold the result
it returns a pointer to the result string (somewhere within field)
it reduces size to n-1 if it is greater or equal
it terminates result with \0
*/
static char *diag_ulonglong_to_dec(char *field, size_t n, unsigned long long ull, int leading0, int size) {
char *np;
char c;
int i;
if (n == 0) return NULL;
np = _diag_ulonglong_to_dec(field, n, ull);
if (size) {
if (size >= n) size = n-1;
if (leading0) {
c = '0';
} else {
c = ' ';
}
i = size - strlen(np);
while (i-- > 0) {
*--np = c;
}
}
return np;
}
/* this function converts a signed long long number to decimal ASCII
and pads it with space or '0' when size and leading0 are set appropriately
it is async signal safe and thread safe
it returns NULL if n==0
it returns NULL if field is too short to hold the result
it returns a pointer to the result string (somewhere within field)
it reduces size to n-1 if it is greater or equal
it terminates result with \0
*/
/* like diag_ulonglong_to_dec but signed; fields need also space for '-' */
static char *diag_longlong_to_dec(char *field, size_t n, long long ll, int leading0, int size) {
char *np;
int minus;
unsigned long ull;
int i;
if ((minus = (ll < 0))) {
ull = (~ll)+1;
} else {
ull = ll;
}
np = _diag_ulonglong_to_dec(field, n, ull);
if (np == NULL) return np;
if (size) {
if (size >= n) size = n-1;
i = size - strlen(np);
if (leading0) {
if (minus) --i;
while (--i >= 0) {
*--np = '0';
}
if (minus) *--np = '-';
} else {
if (minus) { *--np = '-'; --i; }
while (--i >= 0) {
*--np = ' ';
}
}
}
return np;
}
/* this function converts an unsigned long long number to hexadecimal ASCII
it is async signal safe and thread safe
it returns NULL if n==0
it returns NULL if field is too short to hold the result
it returns a pointer to the result string (somewhere within field)
it terminates result with \0
*/
static char *diag_ulonglong_to_hex(char *field, size_t n, unsigned long long ull, int leading0, size_t size) {
char *np = field+n; /* point to the end */
ptrdiff_t i;
char c;
if (n == 0) return NULL;
*--np = '\0'; /* \0 in last char of string */
/* calculate the result from right to left */
do { if (np==field) return NULL; i = (ull&0x0f);
*--np = (i<10?'0':('a'-10))+i; }
while (ull>>=4);
if (size) {
if (size >= n) size = n-1;
if (leading0) {
c = '0';
} else {
c = ' ';
}
i = size - strlen(np);
while (i-- > 0) {
*--np = c;
}
}
return np;
}
/* this function converts an unsigned long long number to octal ASCII
it is async signal safe and thread safe
it returns NULL if n==0
it returns NULL if field is too short to hold the result
it returns a pointer to the result string (somewhere within field)
it terminates result with \0
*/
static char *diag_ulonglong_to_oct(char *field, size_t n, unsigned long long ull, int leading0, size_t size) {
char *np = field+n; /* point to the end */
int i;
char c;
if (n == 0) return NULL;
*--np = '\0'; /* \0 in last char of string */
/* calculate the result from right to left */
do { if (np==field) return NULL; i = (ull&0x07); *--np = '0'+i; }
while (ull>>=3);
if (size) {
if (size >= n) size = n-1;
if (leading0) {
c = '0';
} else {
c = ' ';
}
i = size - strlen(np);
while (--i >= 0) {
*--np = c;
}
}
return np;
}
#endif /* HAVE_TYPE_LONGLONG */
/* this function is designed as a variant of vsnprintf(3) but async signal safe
and thread safe
it currently only implements a subset of the format directives
returns <0 if an error occurred (no scenario know yet)
returns >=size if output is truncated (conforming to C99 standard)
*/
int vsnprintf_r(char *str, size_t size, const char *format, va_list ap) {
size_t i = 0;
char c;
int full = 0; /* indicate if output buffer full */
--size; /* without trailing \0 */
while (c = *format++) {
if (c == '\\') {
} else if (c == '%') {
#if HAVE_TYPE_LONGLONG
# define num_buff_len ((sizeof(unsigned long long)*8+2)/3+1) /* hold up to u long long in octal w/ \0 */
#else
# define num_buff_len ((sizeof(unsigned long)*8+2)/3+1) /* hold up to u long in octal w/ \0 */
#endif
char lengthmod = '\0'; /* 'h' 'l' 'L' 'z' */
int leading0 = 0; /* or 1 */
size_t fsize = 0; /* size of field */
const char *st; /* string */
long lo; unsigned long ulo;
#if HAVE_TYPE_LONGLONG
long long ll; unsigned long long ull;
#endif
char field[num_buff_len]; /* result of number conversion */
char *np; /* num pointer */
c = *format++;
if (c == '\0') { break; }
/* flag characters */
switch (c) {
case '0': leading0 = 1; c = *format++; break;
/* not handled: '#' '-' ' ' '+' '\'' */
}
if (c == '\0') { break; }
/* field width */
switch (c) {
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
do {
fsize = 10*fsize+(c-'0');
c = *format++;
} while (c && isdigit((unsigned char)c));
break;
}
if (c == '\0') { break; }
/* precision - not handles */
/* length modifier */
switch (c) {
/* not handled: 'q' 'j' 't' */
/* handled: 'h' 'hh'->'H' 'z' 'Z'->'z' 'l' 'll'->'L' 'L' */
case 'Z': c = 'z'; /* fall through */
#if HAVE_TYPE_LONGLONG
case 'L':
#endif
case 'z': lengthmod = c; c = *format++; break;
case 'h':
lengthmod = c;
if ((c = *format++) == 'h') {
lengthmod = 'H'; c = *format++;
}
break;
case 'l':
lengthmod = c;
if ((c = *format++) == 'l') {
lengthmod = 'L'; c = *format++;
}
break;
}
if (c == '\0') { break; }
/* conversion specifier */
switch (c) {
case 'c': c = va_arg(ap, int); /* fall through */
case '%': *str++ = c; if (++i == size) { full = 1; } break;
case 's': st = va_arg(ap, const char *);
/* no modifier handled! */
while (c = *st++) {
*str++ = c;
if (++i == size) { full = 1; break; }
}
break;
case 'd':
#if HAVE_TYPE_LONGLONG
if (lengthmod == 'L') {
ll = va_arg(ap, long long);
np = diag_longlong_to_dec(field, num_buff_len, ll, leading0, fsize);
while (c = *np++) {
*str++ = c;
if (++i == size) { full = 1; break; }
}
} else
#endif
{
switch (lengthmod) {
case 'l': lo = va_arg(ap, long); break;
case 'z': lo = va_arg(ap, ptrdiff_t); break;
default: lo = va_arg(ap, int); break;
}
np = diag_long_to_dec(field, num_buff_len, lo, leading0, fsize);
while (c = *np++) { *str++ = c;
if (++i == size) { full = 1; break; }
}
}
break;
case 'u':
#if HAVE_TYPE_LONGLONG
if (lengthmod == 'L') {
ull = va_arg(ap, unsigned long long);
np = diag_ulonglong_to_dec(field, num_buff_len, ull, leading0, fsize);
while (c = *np++) { *str++ = c;
if (++i == size) { full = 1; break; }
}
} else
#endif
{
switch (lengthmod) {
case 'l': ulo = va_arg(ap, unsigned long); break;
case 'z': ulo = va_arg(ap, size_t); break;
default: ulo = va_arg(ap, unsigned int); break;
}
np = diag_ulong_to_dec(field, num_buff_len, ulo, leading0, fsize);
while (c = *np++) { *str++ = c;
if (++i == size) { full = 1; break; }
}
}
break;
case 'p':
ulo = va_arg(ap, size_t);
np = diag_ulong_to_hex(field, num_buff_len, ulo, leading0, fsize);
*str++ = '0'; if (++i == size) { full = 1; break; }
*str++ = 'x'; if (++i == size) { full = 1; break; }
while (c = *np++) { *str++ = c;
if (++i == size) { full = 1; break; }
}
break;
case 'x':
#if HAVE_TYPE_LONGLONG
if (lengthmod == 'L') {
ull = va_arg(ap, unsigned long long);
np = diag_ulonglong_to_hex(field, num_buff_len, ull, leading0, fsize);
while (c = *np++) { *str++ = c;
if (++i == size) { full = 1; break; }
}
} else
#endif
{
switch (lengthmod) {
case 'l': ulo = va_arg(ap, unsigned long); break;
case 'z': ulo = va_arg(ap, size_t); break;
default: ulo = va_arg(ap, unsigned int); break;
}
np = diag_ulong_to_hex(field, num_buff_len, ulo, leading0, fsize);
while (c = *np++) { *str++ = c;
if (++i == size) { full = 1; break; }
}
}
break;
case 'o':
#if HAVE_TYPE_LONGLONG
if (lengthmod == 'L') {
ull = va_arg(ap, unsigned long long);
np = diag_ulonglong_to_oct(field, num_buff_len, ull, leading0, fsize);
while (c = *np++) { *str++ = c;
if (++i == size) break;
}
} else
#endif
{
switch (lengthmod) {
case 'l': ulo = va_arg(ap, unsigned long); break;
case 'z': ulo = va_arg(ap, size_t); break;
default: ulo = va_arg(ap, unsigned int); break;
}
np = diag_ulong_to_oct(field, num_buff_len, ulo, leading0, fsize);
while (c = *np++) { *str++ = c;
if (++i == size) { full = 1; break; }
}
}
break;
default:
*str++ = c; if (++i == size) { full = 1; break; }
}
if (full) break;
} else {
*str++ = c;
if (++i == size) break;
}
}
*str = '\0';
return i;
}
int snprintf_r(char *str, size_t size, const char *format, ...) {
int result;
va_list ap;
va_start(ap, format);
result = vsnprintf_r(str, size, format, ap);
va_end(ap);
return result;
}

11
vsnprintf_r.h Normal file
View File

@@ -0,0 +1,11 @@
/* source: vsnprintf_r.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __vsnprintf_r_h_included
#define __vsnprintf_r_h_included 1
int vsnprintf_r(char *str, size_t size, const char *format, va_list ap);
int snprintf_r(char *str, size_t size, const char *format, ...);
#endif /* !defined(__vsnprintf_r_h_included) */

158
xio-ascii.c Normal file
View File

@@ -0,0 +1,158 @@
/* source: xio-ascii.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains functions for text encoding, decoding, and conversions */
#include <stddef.h>
#include <ctype.h>
#include <stdio.h>
#include "xio-ascii.h"
/* for each 6 bit pattern we have an ASCII character in the arry */
const static int base64chars[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/',
} ;
#define CHAR64(c) (base64chars[c])
char *
xiob64encodeline(const char *data, /* input data */
size_t bytes, /* length of input data, >=0 */
char *coded /* output buffer, must be long enough */
) {
int c1, c2, c3;
while (bytes > 0) {
c1 = *data++;
*coded++ = CHAR64(c1>>2);
if (--bytes == 0) {
*coded++ = CHAR64((c1&0x03)<<4);
*coded++ = '=';
*coded++ = '=';
} else {
c2 = *data++;
*coded++ = CHAR64(((c1&0x03)<<4)|(c2>>4));
if (--bytes == 0) {
*coded++ = CHAR64((c2&0x0f)<<2);
*coded++ = '=';
} else {
c3 = *data++; --bytes;
*coded++ = CHAR64(((c2&0x0f)<<2)|(c3>>6));
*coded++ = CHAR64(c3&0x3f);
}
}
}
return coded;
}
/* sanitize "untrusted" text, replacing special control characters with the C
string version ("\x"), and replacing unprintable chars with ".".
text can grow to double size, so keep output buffer long enough!
returns a pointer to the first untouched byte of the output buffer.
*/
char *xiosanitize(const char *data, /* input data */
size_t bytes, /* length of input data, >=0 */
char *coded /* output buffer, must be long enough */
) {
int c;
while (bytes > 0) {
c = *(unsigned char *)data++;
switch (c) {
case '\0' : *coded++ = '\\'; *coded++ = '0'; break;
case '\a' : *coded++ = '\\'; *coded++ = 'a'; break;
case '\b' : *coded++ = '\\'; *coded++ = 'b'; break;
case '\t' : *coded++ = '\\'; *coded++ = 't'; break;
case '\n' : *coded++ = '\\'; *coded++ = 'n'; break;
case '\v' : *coded++ = '\\'; *coded++ = 'v'; break;
case '\f' : *coded++ = '\\'; *coded++ = 'f'; break;
case '\r' : *coded++ = '\\'; *coded++ = 'r'; break;
case '\'' : *coded++ = '\\'; *coded++ = '\''; break;
case '\"' : *coded++ = '\\'; *coded++ = '"'; break;
case '\\' : *coded++ = '\\'; *coded++ = '\\'; break;
default:
if (!isprint(c))
c = '.';
*coded++ = c;
break;
}
--bytes;
}
return coded;
}
/* print the bytes in hex */
char *
xiohexdump(const unsigned char *data, size_t bytes, char *coded) {
int space = 0;
while (bytes-- > 0) {
if (space) { *coded++ = ' '; }
coded += sprintf(coded, "%02x", *data++);
space = 1;
}
return coded;
}
/* write the binary data to output buffer codbuff in human readable form.
bytes gives the length of the data, codlen the available space in codbuff.
coding specifies how the data is to be presented. Not much to select now.
returns a pointer to the first char in codbuff that has not been overwritten;
it might also point to the first char after the buffer!
this function does not write a terminating \0
*/
static char *
_xiodump(const unsigned char *data, size_t bytes, char *codbuff, size_t codlen,
int coding) {
int start = 1;
int space = coding & 0xff;
if (bytes <= 0) { return codbuff; }
if (codlen < 1) { return codbuff; }
if (space == 0) space = -1;
if (0) {
; /* for canonical reasons */
} else if (1) {
/* simple hexadecimal output */
if (3*bytes+1 > codlen) {
bytes = (codlen-1)/3; /* "truncate" data so generated text fits */
}
*codbuff++ = 'x';
while (bytes-- > 0) {
if (start == 0 && space == 0) {
*codbuff++ = ' ';
space = (coding & 0xff);
}
codbuff += sprintf(codbuff, "%02x", *data++);
start = 0;
}
}
return codbuff;
}
/* write the binary data to codbuff in human readable form.
bytes gives the length of the data, codlen the available space in codbuff.
coding specifies how the data is to be presented. Not much to select now.
null terminates the output. returns a pointer to the output string.
*/
char *
xiodump(const unsigned char *data, size_t bytes, char *codbuff, size_t codlen,
int coding) {
char *result;
result = _xiodump(data, bytes, codbuff, codlen-1, coding);
*result = '\0';
return codbuff;
}

24
xio-ascii.h Normal file
View File

@@ -0,0 +1,24 @@
/* source: xio-ascii.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_ascii_h_included
#define __xio_ascii_h_included 1
extern char *
xiob64encodeline(const char *data, /* input data */
size_t bytes, /* length of input data, >=0 */
char *coded /* output buffer, must be long enough */
);
extern char *xiosanitize(const char *data, /* input data */
size_t bytes, /* length of input data, >=0 */
char *coded /* output buffer, must be long enough */
);
extern char *
xiohexdump(const unsigned char *data, size_t bytes, char *coded);
extern char *
xiodump(const unsigned char *data, size_t bytes, char *coded, size_t codlen,
int coding);
#endif /* !defined(__xio_ascii_h_included) */

90
xio-creat.c Normal file
View File

@@ -0,0 +1,90 @@
/* source: xio-creat.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of create type */
#include "xiosysincludes.h"
#if WITH_CREAT
#include "xioopen.h"
#include "xio-named.h"
#include "xio-creat.h"
static int xioopen_creat(int arg, const char *argv[], struct opt *opts, int rw, xiofile_t *fd, const struct addrdesc *addrdesc);
/*! within stream model, this is a write-only address - use 2 instead of 3 */
const struct addrdesc xioaddr_creat = { "CREATE", 1+XIO_WRONLY, xioopen_creat, GROUP_FD|GROUP_NAMED|GROUP_FILE, 0, 0, 0 HELP(":<filename>") };
/* retrieve the mode option and perform the creat() call.
returns the file descriptor or a negative value. */
static int _xioopen_creat(const char *path, int rw, struct opt *opts) {
mode_t mode = 0666;
int fd;
retropt_modet(opts, OPT_PERM, &mode);
if ((fd = Creat(path, mode)) < 0) {
Error3("creat(\"%s\", 0%03o): %s",
path, mode, strerror(errno));
return STAT_RETRYLATER;
}
return fd;
}
static int xioopen_creat(
int argc,
const char *argv[],
struct opt *opts,
int xioflags,
xiofile_t *xxfd,
const struct addrdesc *addrdesc)
{
struct single *sfd = &xxfd->stream;
const char *filename = argv[1];
int rw = (xioflags&XIO_ACCMODE);
bool exists;
bool opt_unlink_close = false;
int result;
/* remove old file, or set user/permissions on old file; parse options */
if ((result =
_xioopen_named_early(argc, argv, xxfd, addrdesc->groups, &exists, opts,
addrdesc->syntax))
< 0) {
return result;
}
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
if (opt_unlink_close) {
if ((sfd->unlink_close = strdup(filename)) == NULL) {
Error1("strdup(\"%s\"): out of memory", filename);
}
sfd->opt_unlink_close = true;
}
Notice2("creating regular file \"%s\" for %s", filename, ddirection[rw]);
if ((result = _xioopen_creat(filename, rw, opts)) < 0)
return result;
sfd->fd = result;
applyopts_named(filename, opts, PH_PASTOPEN);
if ((result = applyopts2(sfd, -1, opts, PH_PASTOPEN, PH_LATE2)) < 0)
return result;
applyopts_cloexec(sfd->fd, opts);
applyopts_fchown(sfd->fd, opts);
if ((result = _xio_openlate(sfd, opts)) < 0)
return result;
return 0;
}
#endif /* WITH_CREAT */

10
xio-creat.h Normal file
View File

@@ -0,0 +1,10 @@
/* source: xio-creat.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_creat_h_included
#define __xio_creat_h_included 1
extern const struct addrdesc xioaddr_creat;
#endif /* !defined(__xio_creat_h_included) */

46
xio-dccp.c Normal file
View File

@@ -0,0 +1,46 @@
/* source: xio-dccp.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for DCCP related functions and options */
#include "xiosysincludes.h"
#if WITH_DCCP
#include "xioopen.h"
#include "xio-listen.h"
#include "xio-ip4.h"
#include "xio-ipapp.h"
#include "xio-dccp.h"
/****** DCCP addresses ******/
#if WITH_IP4 || WITH_IP6
const struct addrdesc xioaddr_dccp_connect = { "DCCP-CONNECT", 1+XIO_RDWR, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_DCCP|GROUP_CHILD|GROUP_RETRY, SOCK_DCCP, IPPROTO_DCCP, PF_UNSPEC HELP(":<host>:<port>") };
#if WITH_LISTEN
const struct addrdesc xioaddr_dccp_listen = { "DCCP-LISTEN", 1+XIO_RDWR, xioopen_ipapp_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_DCCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, SOCK_DCCP, IPPROTO_DCCP, PF_UNSPEC HELP(":<port>") };
#endif
#endif
#if WITH_IP4
const struct addrdesc xioaddr_dccp4_connect = { "DCCP4-CONNECT", 1+XIO_RDWR, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_DCCP|GROUP_CHILD|GROUP_RETRY, SOCK_DCCP, IPPROTO_DCCP, PF_INET HELP(":<host>:<port>") };
#if WITH_LISTEN
const struct addrdesc xioaddr_dccp4_listen = { "DCCP4-LISTEN", 1+XIO_RDWR, xioopen_ipapp_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_DCCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, SOCK_DCCP, IPPROTO_DCCP, PF_INET HELP(":<port>") };
#endif
#endif /* WITH_IP4 */
#if WITH_IP6
const struct addrdesc xioaddr_dccp6_connect = { "DCCP6-CONNECT", 1+XIO_RDWR, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_DCCP|GROUP_CHILD|GROUP_RETRY, SOCK_DCCP, IPPROTO_DCCP, PF_INET6 HELP(":<host>:<port>") };
#if WITH_LISTEN
const struct addrdesc xioaddr_dccp6_listen = { "DCCP6-LISTEN", 1+XIO_RDWR, xioopen_ipapp_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_DCCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, SOCK_DCCP, IPPROTO_DCCP, PF_INET6 HELP(":<port>") };
#endif
#endif /* WITH_IP6 */
/****** DCCP address options ******/
#if defined(SOL_DCCP) && defined(DCCP_SOCKOPT_QPOLICY_ID)
const struct optdesc xioopt_dccp_set_ccid = { "dccp-set-ccid", "ccid", OPT_DCCP_SET_CCID, GROUP_IP_DCCP, PH_PASTSOCKET, TYPE_BYTE, OFUNC_SOCKOPT, SOL_DCCP, DCCP_SOCKOPT_CCID };
#endif
#endif /* WITH_DCCP */

17
xio-dccp.h Normal file
View File

@@ -0,0 +1,17 @@
/* source: xio-dccp.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_dccp_h_included
#define __xio_dccp_h_included 1
extern const struct addrdesc xioaddr_dccp_connect;
extern const struct addrdesc xioaddr_dccp_listen;
extern const struct addrdesc xioaddr_dccp4_connect;
extern const struct addrdesc xioaddr_dccp4_listen;
extern const struct addrdesc xioaddr_dccp6_connect;
extern const struct addrdesc xioaddr_dccp6_listen;
extern const struct optdesc xioopt_dccp_set_ccid;
#endif /* !defined(__xio_dccp_h_included) */

150
xio-exec.c Normal file
View File

@@ -0,0 +1,150 @@
/* source: xio-exec.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of exec type */
#include "xiosysincludes.h"
#include "xioopen.h"
#include "nestlex.h"
#include "xio-progcall.h"
#include "xio-exec.h"
#if WITH_EXEC
static int xioopen_exec(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, const struct addrdesc *addrdesc);
const struct addrdesc xioaddr_exec = { "EXEC", 3, xioopen_exec, GROUP_FD|GROUP_FORK|GROUP_EXEC|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_TERMIOS|GROUP_FIFO|GROUP_PTY|GROUP_PARENT, 0, 0, 0 HELP(":<command-line>") };
const struct optdesc opt_dash = { "dash", "login", OPT_DASH, GROUP_EXEC, PH_PREEXEC, TYPE_BOOL, OFUNC_SPEC };
static int xioopen_exec(
int argc,
const char *argv[],
struct opt *opts,
int xioflags, /* XIO_RDONLY, XIO_MAYCHILD etc. */
xiofile_t *xfd,
const struct addrdesc *addrdesc)
{
struct single *sfd = &xfd->stream;
int status;
bool dash = false;
int duptostderr;
int numleft;
if (argc != 2) {
xio_syntax(argv[0], 1, argc-1, addrdesc->syntax);
return STAT_NORETRY;
}
retropt_bool(opts, OPT_DASH, &dash);
status =
_xioopen_foxec(xioflags, sfd, addrdesc->groups, &opts, &duptostderr);
if (status < 0)
return status;
if (status == 0) { /* child */
const char *ends[] = { " ", NULL };
const char *hquotes[] = { "'", NULL };
const char *squotes[] = { "\"", NULL };
const char *nests[] = {
"'", "'",
"(", ")",
"[", "]",
"{", "}",
NULL
} ;
char **pargv = NULL;
int pargc;
size_t len;
const char *strp;
char *token; /*! */
char *tokp;
char *path = NULL;
char *tmp;
/*! Close(something) */
/* parse command line */
Debug1("child: args = \"%s\"", argv[1]);
pargv = Malloc(8*sizeof(char *));
if (pargv == NULL) return STAT_RETRYLATER;
len = strlen(argv[1])+1;
strp = argv[1];
token = Malloc(len); /*! */
tokp = token;
if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests,
true, true, false) < 0) {
Error("internal: miscalculated string lengths");
}
*tokp++ = '\0';
pargv[0] = strrchr(tokp-1, '/');
if (pargv[0] == NULL) pargv[0] = token; else ++pargv[0];
pargc = 1;
while (*strp == ' ') {
while (*++strp == ' ') ;
if ((pargc & 0x07) == 0) {
pargv = Realloc(pargv, (pargc+8)*sizeof(char *));
if (pargv == NULL) return STAT_RETRYLATER;
}
pargv[pargc++] = tokp;
if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests,
true, true, false) < 0) {
Error("internal: miscalculated string lengths");
}
*tokp++ = '\0';
}
pargv[pargc] = NULL;
if ((tmp = Malloc(strlen(pargv[0])+2)) == NULL) {
return STAT_RETRYLATER;
}
if (dash) {
tmp[0] = '-';
strcpy(tmp+1, pargv[0]);
} else {
strcpy(tmp, pargv[0]);
}
pargv[0] = tmp;
if (setopt_path(opts, &path) < 0) {
/* this could be dangerous, so let us abort this child... */
Exit(1);
}
dropopts(opts, PH_PASTEXEC);
if ((numleft = leftopts(opts)) > 0) {
showleft(opts);
Error1("INTERNAL: %d option(s) remained unused", numleft);
return STAT_NORETRY;
}
/* only now redirect stderr */
if (duptostderr >= 0) {
diag_dup();
Dup2(duptostderr, 2);
}
Notice1("execvp'ing \"%s\"", token);
Execvp(token, pargv);
/* here we come only if execvp() failed */
switch (pargc) {
case 1:
Error3("execvp(\"%s\", \"%s\"): %s",
token, pargv[0], strerror(errno)); break;
case 2:
Error4("execvp(\"%s\", \"%s\", \"%s\"): %s",
token, pargv[0], pargv[1], strerror(errno)); break;
case 3:
default:
Error5("execvp(\"%s\", \"%s\", \"%s\", \"%s\", ...): %s", token,
pargv[0], pargv[1], pargv[2], strerror(errno));
break;
}
Exit(1); /* this child process */
}
/* parent */
_xio_openlate(sfd, opts);
return 0;
}
#endif /* WITH_EXEC */

12
xio-exec.h Normal file
View File

@@ -0,0 +1,12 @@
/* source: xio-exec.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_exec_h_included
#define __xio_exec_h_included 1
extern const struct addrdesc xioaddr_exec;
extern const struct optdesc opt_dash;
#endif /* !defined(__xio_exec_h_included) */

93
xio-fd.c Normal file
View File

@@ -0,0 +1,93 @@
/* source: xio-fd.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains common file descriptor related option definitions */
#include "xiosysincludes.h"
#include "xioopen.h"
#include "xio-fd.h"
/****** for ALL addresses - with open() or fcntl(F_SETFL) ******/
const struct optdesc opt_append = { "append", NULL, OPT_O_APPEND, GROUP_OPEN|GROUP_FD, PH_LATE, TYPE_BOOL, OFUNC_FCNTL, F_SETFL, O_APPEND };
const struct optdesc opt_nonblock = { "o-nonblock", "nonblock", OPT_O_NONBLOCK, GROUP_OPEN|GROUP_FD, PH_FD, TYPE_BOOL, OFUNC_FCNTL, F_SETFL, O_NONBLOCK };
#if defined(O_NDELAY) && (!defined(O_NONBLOCK) || O_NDELAY != O_NONBLOCK)
const struct optdesc opt_o_ndelay = { "o-ndelay", NULL, OPT_O_NDELAY, GROUP_OPEN|GROUP_FD, PH_LATE, TYPE_BOOL, OFUNC_FCNTL, F_SETFL, O_NDELAY };
#endif
#ifdef O_ASYNC
const struct optdesc opt_async = { "async", NULL, OPT_O_ASYNC, GROUP_OPEN|GROUP_FD, PH_LATE, TYPE_BOOL, OFUNC_FCNTL, F_SETFL, O_ASYNC };
#endif
#ifdef O_BINARY
const struct optdesc opt_o_binary = { "o-binary", "binary", OPT_O_BINARY, GROUP_OPEN|GROUP_FD, PH_OPEN, TYPE_BOOL, OFUNC_FCNTL, F_SETFL, O_BINARY };
#endif
#ifdef O_TEXT
const struct optdesc opt_o_text = { "o-text", "text", OPT_O_TEXT, GROUP_OPEN|GROUP_FD, PH_OPEN, TYPE_BOOL, OFUNC_FCNTL, F_SETFL, O_TEXT };
#endif
#ifdef O_NOINHERIT
const struct optdesc opt_o_noinherit = { "o-noinherit", "noinherit", OPT_O_NOINHERIT, GROUP_OPEN|GROUP_FD, PH_OPEN, TYPE_BOOL, OFUNC_FCNTL, F_SETFL, O_NOINHERIT };
#endif
#ifdef O_NOATIME
const struct optdesc opt_o_noatime = { "o-noatime", "noatime", OPT_O_NOATIME, GROUP_OPEN|GROUP_FD, PH_FD, TYPE_BOOL, OFUNC_FCNTL, F_SETFL, O_NOATIME };
#endif
/****** for ALL addresses - with fcntl(F_SETFD) ******/
const struct optdesc opt_cloexec = { "cloexec", NULL, OPT_CLOEXEC, GROUP_FD, PH_LATE, TYPE_BOOL, OFUNC_FCNTL, F_SETFD, FD_CLOEXEC };
/****** ftruncate() ******/
/* this record is good for ftruncate() or ftruncate64() if available */
#if HAVE_FTRUNCATE64
const struct optdesc opt_ftruncate32 = { "ftruncate32", NULL, OPT_FTRUNCATE32, GROUP_REG, PH_LATE, TYPE_OFF32, OFUNC_SPEC };
const struct optdesc opt_ftruncate64 = { "ftruncate64", "truncate", OPT_FTRUNCATE64, GROUP_REG, PH_LATE, TYPE_OFF64, OFUNC_SPEC };
#else
const struct optdesc opt_ftruncate32 = { "ftruncate32", "truncate", OPT_FTRUNCATE32, GROUP_REG, PH_LATE, TYPE_OFF32, OFUNC_SPEC };
#endif /* !HAVE_FTRUNCATE64 */
/****** for ALL addresses - permissions, ownership, and positioning ******/
const struct optdesc opt_group = { "group", "gid", OPT_GROUP, GROUP_FD|GROUP_NAMED,PH_FD,TYPE_GIDT,OFUNC_SPEC };
const struct optdesc opt_group_late= { "group-late","gid-l", OPT_GROUP_LATE,GROUP_FD, PH_LATE, TYPE_GIDT, OFUNC_SPEC };
const struct optdesc opt_perm = { "perm", "mode", OPT_PERM, GROUP_FD|GROUP_NAMED, PH_FD, TYPE_MODET,OFUNC_SPEC };
const struct optdesc opt_perm_late = { "perm-late", NULL, OPT_PERM_LATE, GROUP_FD, PH_LATE, TYPE_MODET,OFUNC_SPEC };
const struct optdesc opt_user = { "user", "uid", OPT_USER, GROUP_FD|GROUP_NAMED, PH_FD, TYPE_UIDT, OFUNC_SPEC };
const struct optdesc opt_user_late = { "user-late", "uid-l", OPT_USER_LATE, GROUP_FD, PH_LATE, TYPE_UIDT, OFUNC_SPEC };
/* for something like random access files */
#if HAVE_LSEEK64
const struct optdesc opt_lseek32_cur = { "lseek32-cur", NULL, OPT_SEEK32_CUR, GROUP_REG|GROUP_BLK, PH_LATE, TYPE_OFF32, OFUNC_SEEK32, SEEK_CUR };
const struct optdesc opt_lseek32_end = { "lseek32-end", NULL, OPT_SEEK32_END, GROUP_REG|GROUP_BLK, PH_LATE, TYPE_OFF32, OFUNC_SEEK32, SEEK_END };
const struct optdesc opt_lseek32_set = { "lseek32-set", NULL, OPT_SEEK32_SET, GROUP_REG|GROUP_BLK, PH_LATE, TYPE_OFF32, OFUNC_SEEK32, SEEK_SET };
const struct optdesc opt_lseek64_cur = { "lseek64-cur", "seek-cur", OPT_SEEK64_CUR, GROUP_REG|GROUP_BLK, PH_LATE, TYPE_OFF64, OFUNC_SEEK64, SEEK_CUR };
const struct optdesc opt_lseek64_end = { "lseek64-end", "seek-end", OPT_SEEK64_END, GROUP_REG|GROUP_BLK, PH_LATE, TYPE_OFF64, OFUNC_SEEK64, SEEK_END };
const struct optdesc opt_lseek64_set = { "lseek64-set", "seek", OPT_SEEK64_SET, GROUP_REG|GROUP_BLK, PH_LATE, TYPE_OFF64, OFUNC_SEEK64, SEEK_SET };
#else
const struct optdesc opt_lseek32_cur = { "lseek32-cur", "seek-cur", OPT_SEEK32_CUR, GROUP_REG|GROUP_BLK, PH_LATE, TYPE_OFF32, OFUNC_SEEK32, SEEK_CUR };
const struct optdesc opt_lseek32_end = { "lseek32-end", "seek-end", OPT_SEEK32_END, GROUP_REG|GROUP_BLK, PH_LATE, TYPE_OFF32, OFUNC_SEEK32, SEEK_END };
const struct optdesc opt_lseek32_set = { "lseek32-set", "seek", OPT_SEEK32_SET, GROUP_REG|GROUP_BLK, PH_LATE, TYPE_OFF32, OFUNC_SEEK32, SEEK_SET };
#endif /* !HAVE_LSEEK64 */
/* for all addresses (?) */
const struct optdesc opt_f_setlk_rd = { "f-setlk-rd", "setlk-rd", OPT_F_SETLK_RD, GROUP_FD, PH_FD,TYPE_BOOL, OFUNC_SPEC, F_SETLK, F_RDLCK };
const struct optdesc opt_f_setlkw_rd = { "f-setlkw-rd", "setlkw-rd",OPT_F_SETLKW_RD, GROUP_FD, PH_FD,TYPE_BOOL, OFUNC_SPEC, F_SETLKW, F_RDLCK };
const struct optdesc opt_f_setlk_wr = { "f-setlk-wr", "setlk", OPT_F_SETLK_WR, GROUP_FD, PH_FD,TYPE_BOOL, OFUNC_SPEC, F_SETLK, F_WRLCK };
const struct optdesc opt_f_setlkw_wr = { "f-setlkw-wr", "setlkw", OPT_F_SETLKW_WR, GROUP_FD, PH_FD,TYPE_BOOL, OFUNC_SPEC, F_SETLKW, F_WRLCK };
#if HAVE_FLOCK
const struct optdesc opt_flock_sh = { "flock-sh", NULL, OPT_FLOCK_SH, GROUP_FD, PH_FD,TYPE_BOOL, OFUNC_FLOCK, LOCK_SH };
const struct optdesc opt_flock_sh_nb = { "flock-sh-nb", NULL, OPT_FLOCK_SH_NB, GROUP_FD, PH_FD,TYPE_BOOL, OFUNC_FLOCK, LOCK_SH|LOCK_NB };
const struct optdesc opt_flock_ex = { "flock-ex", "flock", OPT_FLOCK_EX, GROUP_FD, PH_FD,TYPE_BOOL, OFUNC_FLOCK, LOCK_EX };
const struct optdesc opt_flock_ex_nb = { "flock-ex-nb", "flock-nb", OPT_FLOCK_EX_NB, GROUP_FD, PH_FD,TYPE_BOOL, OFUNC_FLOCK, LOCK_EX|LOCK_NB };
#endif /* HAVE_FLOCK */
const struct optdesc opt_cool_write = { "cool-write", "coolwrite", OPT_COOL_WRITE, GROUP_FD, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, XIO_OFFSETOF(cool_write) };
/* control closing of connections */
const struct optdesc opt_end_close = { "end-close", "close", OPT_END_CLOSE, GROUP_FD, PH_OFFSET, TYPE_CONST, OFUNC_OFFSET, XIO_OFFSETOF(howtoend), END_CLOSE };
const struct optdesc opt_shut_none = { "shut-none", NULL, OPT_SHUT_NONE, GROUP_FD, PH_OFFSET, TYPE_CONST, OFUNC_OFFSET, XIO_OFFSETOF(howtoshut), XIOSHUT_NONE };
const struct optdesc opt_shut_down = { "shut-down", NULL, OPT_SHUT_DOWN, GROUP_FD, PH_OFFSET, TYPE_CONST, OFUNC_OFFSET, XIO_OFFSETOF(howtoshut), XIOSHUT_DOWN };
const struct optdesc opt_shut_close= { "shut-close", NULL, OPT_SHUT_CLOSE, GROUP_FD, PH_OFFSET, TYPE_CONST, OFUNC_OFFSET, XIO_OFFSETOF(howtoshut), XIOSHUT_CLOSE };
const struct optdesc opt_shut_null = { "shut-null", NULL, OPT_SHUT_NULL, GROUP_FD, PH_OFFSET, TYPE_CONST, OFUNC_OFFSET, XIO_OFFSETOF(howtoshut), XIOSHUT_NULL };
/****** generic ioctl() options ******/
const struct optdesc opt_ioctl_void = { "ioctl-void", "ioctl", OPT_IOCTL_VOID, GROUP_FD, PH_FD, TYPE_INT, OFUNC_IOCTL_GENERIC, 0, 0, 0 };
const struct optdesc opt_ioctl_int = { "ioctl-int", NULL, OPT_IOCTL_INT, GROUP_FD, PH_FD, TYPE_INT_INT, OFUNC_IOCTL_GENERIC, 0, 0, 0 };
const struct optdesc opt_ioctl_intp = { "ioctl-intp", NULL, OPT_IOCTL_INTP, GROUP_FD, PH_FD, TYPE_INT_INTP, OFUNC_IOCTL_GENERIC, 0, 0, 0 };
const struct optdesc opt_ioctl_bin = { "ioctl-bin", NULL, OPT_IOCTL_BIN, GROUP_FD, PH_FD, TYPE_INT_BIN, OFUNC_IOCTL_GENERIC, 0, 0, 0 };
const struct optdesc opt_ioctl_string = { "ioctl-string",NULL, OPT_IOCTL_STRING,GROUP_FD, PH_FD, TYPE_INT_STRING,OFUNC_IOCTL_GENERIC, 0, 0, 0 };
/* POSIX STREAMS */
#define ENABLE_OPTIONS
#include "xio-streams.c"
#undef ENABLE_OPTIONS

51
xio-fd.h Normal file
View File

@@ -0,0 +1,51 @@
/* source: xio-fd.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_fd_h_included
#define __xio_fd_h_included 1
extern const struct optdesc opt_ioctl_void;
extern const struct optdesc opt_ioctl_int;
extern const struct optdesc opt_ioctl_intp;
extern const struct optdesc opt_ioctl_bin;
extern const struct optdesc opt_ioctl_string;
extern const struct optdesc opt_append;
extern const struct optdesc opt_nonblock;
extern const struct optdesc opt_o_ndelay;
extern const struct optdesc opt_async;
extern const struct optdesc opt_o_binary;
extern const struct optdesc opt_o_text;
extern const struct optdesc opt_o_noinherit;
extern const struct optdesc opt_cloexec;
extern const struct optdesc opt_ftruncate32;
extern const struct optdesc opt_ftruncate64;
extern const struct optdesc opt_group;
extern const struct optdesc opt_group_late;
extern const struct optdesc opt_perm;
extern const struct optdesc opt_perm_late;
extern const struct optdesc opt_user;
extern const struct optdesc opt_user_late;
extern const struct optdesc opt_lseek32_cur;
extern const struct optdesc opt_lseek32_end;
extern const struct optdesc opt_lseek32_set;
extern const struct optdesc opt_lseek64_cur;
extern const struct optdesc opt_lseek64_end;
extern const struct optdesc opt_lseek64_set;
extern const struct optdesc opt_flock_sh;
extern const struct optdesc opt_flock_sh_nb;
extern const struct optdesc opt_flock_ex;
extern const struct optdesc opt_flock_ex_nb;
extern const struct optdesc opt_f_setlk_rd;
extern const struct optdesc opt_f_setlkw_rd;
extern const struct optdesc opt_f_setlk_wr;
extern const struct optdesc opt_f_setlkw_wr;
extern const struct optdesc opt_cool_write;
extern const struct optdesc opt_end_close;
extern const struct optdesc opt_shut_none;
extern const struct optdesc opt_shut_down;
extern const struct optdesc opt_shut_close;
extern const struct optdesc opt_shut_null;
extern const struct optdesc opt_streams_i_push;
#endif /* !defined(__xio_fd_h_included) */

135
xio-fdnum.c Normal file
View File

@@ -0,0 +1,135 @@
/* source: xio-fdnum.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of fdnum type */
#include "xiosysincludes.h"
#include "xioopen.h"
#include "xio-listen.h"
#include "xio-fdnum.h"
#if WITH_FDNUM
static int xioopen_fdnum(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, const struct addrdesc *addrdesc);
static int xioopen_accept_fd(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, const struct addrdesc *addrdesc);
const struct addrdesc xioaddr_fd = { "FD", 1+XIO_RDWR, xioopen_fdnum, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, 0, 0, 0 HELP(":<fdnum>") };
#if WITH_LISTEN
const struct addrdesc xioaddr_accept_fd = { "ACCEPT-FD", 1+XIO_RDWR, xioopen_accept_fd, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, 0, 0, 0 HELP(":<fdnum>") };
#endif /* WITH_LISTEN */
/* use some file descriptor and apply the options. Set the FD_CLOEXEC flag. */
static int xioopen_fdnum(
int argc,
const char *argv[],
struct opt *opts,
int xioflags,
xiofile_t *xfd,
const struct addrdesc *addrdesc)
{
char *a1;
int rw = (xioflags&XIO_ACCMODE);
int numfd;
int result;
if (argc != 2) {
Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1);
}
numfd = strtoul(argv[1], &a1, 0);
if (*a1 != '\0') {
Error1("error in FD number \"%s\"", argv[1]);
}
/* we dont want to see these fds in child processes */
if (Fcntl_l(numfd, F_SETFD, FD_CLOEXEC) < 0) {
Warn2("fcntl(%d, F_SETFD, FD_CLOEXEC): %s", numfd, strerror(errno));
}
Notice2("using file descriptor %d for %s", numfd, ddirection[rw]);
if ((result = xioopen_fd(opts, rw, &xfd->stream, numfd)) < 0) {
return result;
}
return 0;
}
#if WITH_LISTEN
/* Use some file descriptor and apply the options. Set the FD_CLOEXEC flag. */
static int xioopen_accept_fd(
int argc,
const char *argv[],
struct opt *opts,
int xioflags,
xiofile_t *xfd,
const struct addrdesc *addrdesc)
{
char *a1;
int rw = (xioflags&XIO_ACCMODE);
int numfd;
union sockaddr_union us;
socklen_t uslen = sizeof(union sockaddr_union);
int result;
if (argc != 2) {
xio_syntax(argv[0], 1, argc-1, addrdesc->syntax);
return STAT_NORETRY;
}
numfd = strtoul(argv[1], &a1, 0);
if (*a1 != '\0') {
Error1("error in FD number \"%s\"", argv[1]);
}
/* we dont want to see these fds in child processes */
if (Fcntl_l(numfd, F_SETFD, FD_CLOEXEC) < 0) {
Warn2("fcntl(%d, F_SETFD, FD_CLOEXEC): %s", numfd, strerror(errno));
}
if (Getsockname(numfd, (struct sockaddr *)&us, &uslen) < 0) {
Warn2("getsockname(fd=%d, ...): %s", numfd, strerror(errno));
}
Notice2("using file descriptor %d accepting a connection for %s", numfd, ddirection[rw]);
xfd->stream.fd = numfd;
if ((result = _xioopen_accept_fd(&xfd->stream, xioflags, (struct sockaddr *)&us, uslen, opts, us.soa.sa_family, 0, 0)) < 0) {
return result;
}
return 0;
}
#endif /* WITH_LISTEN */
#endif /* WITH_FDNUM */
#if WITH_FD
/* Retrieves and apply options to a standard file descriptor.
Does not set FD_CLOEXEC flag. */
int xioopen_fd(struct opt *opts, int rw, struct single *sfd, int numfd) {
sfd->fd = numfd;
if (sfd->howtoend == END_UNSPEC)
sfd->howtoend = END_NONE;
#if WITH_TERMIOS
if (Isatty(sfd->fd)) {
if (Tcgetattr(sfd->fd, &sfd->savetty) < 0) {
Warn2("cannot query current terminal settings on fd %d: %s",
sfd->fd, strerror(errno));
} else {
sfd->ttyvalid = true;
}
}
#endif /* WITH_TERMIOS */
if (applyopts_single(sfd, opts, PH_INIT) < 0)
return -1;
applyopts2(sfd, -1, opts, PH_INIT, PH_FD);
return _xio_openlate(sfd, opts);
}
#endif /* WITH_FD */

13
xio-fdnum.h Normal file
View File

@@ -0,0 +1,13 @@
/* source: xio-fdnum.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_fdnum_h_included
#define __xio_fdnum_h_included 1
extern const struct addrdesc xioaddr_fd;
extern const struct addrdesc xioaddr_accept_fd;
extern int xioopen_fd(struct opt *opts, int rw, xiosingle_t *xfd, int numfd);
#endif /* !defined(__xio_fdnum_h_included) */

135
xio-file.c Normal file
View File

@@ -0,0 +1,135 @@
/* source: xio-file.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of open type */
#include "xiosysincludes.h"
#include "xioopen.h"
#include "xio-named.h"
#include "xio-file.h"
static int xioopen_open(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, const struct addrdesc *addrdesc);
#if WITH_OPEN
/****** OPEN addresses ******/
const struct optdesc opt_o_rdonly = { "o-rdonly", "rdonly", OPT_O_RDONLY, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG_PATTERN, O_RDONLY, O_ACCMODE };
const struct optdesc opt_o_wronly = { "o-wronly", "wronly", OPT_O_WRONLY, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG_PATTERN, O_WRONLY, O_ACCMODE };
const struct optdesc opt_o_rdwr = { "o-rdwr", "rdwr", OPT_O_RDWR, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG_PATTERN, O_RDWR, O_ACCMODE };
const struct optdesc opt_o_create = { "o-create", "creat", OPT_O_CREATE, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_CREAT };
const struct optdesc opt_o_excl = { "o-excl", "excl", OPT_O_EXCL, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_EXCL };
const struct optdesc opt_o_noctty = { "o-noctty", "noctty", OPT_O_NOCTTY, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_NOCTTY };
#ifdef O_SYNC
const struct optdesc opt_o_sync = { "o-sync", "sync", OPT_O_SYNC, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_SYNC };
#endif
#ifdef O_NOFOLLOW
const struct optdesc opt_o_nofollow = { "o-nofollow", "nofollow",OPT_O_NOFOLLOW, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_NOFOLLOW };
#endif
#ifdef O_DIRECTORY
const struct optdesc opt_o_directory = { "o-directory", "directory",OPT_O_DIRECTORY, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_DIRECTORY };
#endif
#ifdef O_LARGEFILE
const struct optdesc opt_o_largefile = { "o-largefile", "largefile",OPT_O_LARGEFILE, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_LARGEFILE };
#endif
#ifdef O_NSHARE
const struct optdesc opt_o_nshare = { "o-nshare", "nshare", OPT_O_NSHARE, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_NSHARE };
#endif
#ifdef O_RSHARE
const struct optdesc opt_o_rshare = { "o-rshare", "rshare", OPT_O_RSHARE, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_RSHARE };
#endif
#ifdef O_DEFER
const struct optdesc opt_o_defer = { "o-defer", "defer", OPT_O_DEFER, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_DEFER };
#endif
#ifdef O_DIRECT
const struct optdesc opt_o_direct = { "o-direct", "direct", OPT_O_DIRECT, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_DIRECT };
#endif
#ifdef O_DSYNC
const struct optdesc opt_o_dsync = { "o-dsync", "dsync", OPT_O_DSYNC, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_DSYNC };
#endif
#ifdef O_RSYNC
const struct optdesc opt_o_rsync = { "o-rsync", "rsync", OPT_O_RSYNC, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_RSYNC };
#endif
#ifdef O_DELAY
const struct optdesc opt_o_delay = { "o-delay", "delay", OPT_O_DELAY, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_DELAY };
#endif
#ifdef O_PRIV
const struct optdesc opt_o_priv = { "o-priv", "priv", OPT_O_PRIV, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_PRIV };
#endif
const struct optdesc opt_o_trunc = { "o-trunc", "trunc", OPT_O_TRUNC, GROUP_OPEN, PH_LATE, TYPE_BOOL, OFUNC_FLAG, O_TRUNC };
#endif /* WITH_OPEN */
#if _WITH_FILE /*! inconsistent name FILE vs. OPEN */
const struct addrdesc xioaddr_open = { "OPEN", 3, xioopen_open, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_REG|GROUP_NAMED|GROUP_OPEN|GROUP_FILE|GROUP_TERMIOS, 0, 0, 0 HELP(":<filename>") };
/* open for writing:
if the filesystem entry already exists, the data is appended
if it does not exist, a file is created and the data is appended
*/
static int xioopen_open(
int argc,
const char *argv[],
struct opt *opts,
int xioflags,
xiofile_t *xfd,
const struct addrdesc *addrdesc)
{
const char *filename = argv[1];
int rw = (xioflags & XIO_ACCMODE);
struct single *sfd = &xfd->stream;
bool exists;
bool opt_unlink_close = false;
int result;
/* remove old file, or set user/permissions on old file; parse options */
if ((result =
_xioopen_named_early(argc, argv, xfd, addrdesc->groups, &exists, opts,
addrdesc->syntax))
< 0) {
return result;
}
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
if (opt_unlink_close) {
if ((sfd->unlink_close = strdup(filename)) == NULL) {
Error1("strdup(\"%s\"): out of memory", filename);
}
sfd->opt_unlink_close = true;
}
Notice3("opening %s \"%s\" for %s",
filetypenames[(result&S_IFMT)>>12], filename, ddirection[rw]);
if ((result = _xioopen_open(filename, rw, opts)) < 0)
return result;
sfd->fd = result;
#if WITH_TERMIOS
if (Isatty(sfd->fd)) {
if (Tcgetattr(sfd->fd, &sfd->savetty) < 0) {
Warn2("cannot query current terminal settings on fd %d: %s",
sfd->fd, strerror(errno));
} else {
sfd->ttyvalid = true;
}
}
#endif /* WITH_TERMIOS */
applyopts_named(filename, opts, PH_FD);
applyopts(sfd, -1, opts, PH_FD);
applyopts_cloexec(sfd->fd, opts);
applyopts_fchown(sfd->fd, opts);
if ((result = _xio_openlate(sfd, opts)) < 0)
return result;
return 0;
}
#endif /* _WITH_FILE */

31
xio-file.h Normal file
View File

@@ -0,0 +1,31 @@
/* source: xio-file.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_file_h_included
#define __xio_file_h_included 1
extern const struct optdesc opt_o_rdonly;
extern const struct optdesc opt_o_wronly;
extern const struct optdesc opt_o_rdwr;
extern const struct optdesc opt_o_create;
extern const struct optdesc opt_o_excl;
extern const struct optdesc opt_o_noctty;
extern const struct optdesc opt_o_sync;
extern const struct optdesc opt_o_nofollow;
extern const struct optdesc opt_o_directory;
extern const struct optdesc opt_o_largefile;
extern const struct optdesc opt_o_nshare;
extern const struct optdesc opt_o_rshare;
extern const struct optdesc opt_o_defer;
extern const struct optdesc opt_o_direct;
extern const struct optdesc opt_o_dsync;
extern const struct optdesc opt_o_rsync;
extern const struct optdesc opt_o_delay;
extern const struct optdesc opt_o_priv;
extern const struct optdesc opt_o_trunc;
extern const struct optdesc opt_o_noatime;
extern const struct addrdesc xioaddr_open;
#endif /* !defined(__xio_file_h_included) */

134
xio-fs.c Normal file
View File

@@ -0,0 +1,134 @@
/* source: xio-fs.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for handling Linux fs options
they can also be set with chattr(1) and viewed with lsattr(1) */
#include "xiosysincludes.h"
#include "xioopen.h"
#include "xio-fs.h"
#if WITH_FS
/****** FD options ******/
#if defined(EXT2_IOC_GETFLAGS) && !defined(FS_IOC_GETFLAGS)
# define FS_IOC_GETFLAGS EXT2_IOC_GETFLAGS
#endif
#if defined(EXT2_IOC_SETFLAGS) && !defined(FS_IOC_SETFLAGS)
# define FS_IOC_SETFLAGS EXT2_IOC_SETFLAGS
#endif
#if defined(EXT2_SECRM_FL) && !defined(FS_SECRM_FL)
# define FS_SECRM_FL EXT2_SECRM_FL
#endif
#ifdef FS_SECRM_FL
/* secure deletion, chattr 's' */
const struct optdesc opt_fs_secrm = { "fs-secrm", "secrm", OPT_FS_SECRM, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, FS_IOC_GETFLAGS, FS_IOC_SETFLAGS, FS_SECRM_FL };
#endif
#if defined(EXT2_UNRM_FL) && !defined(FS_UNRM_FL)
# define FS_UNRM_FL EXT2_UNRM_FL
#endif
#ifdef FS_UNRM_FL
/* undelete, chattr 'u' */
const struct optdesc opt_fs_unrm = { "fs-unrm", "unrm", OPT_FS_UNRM, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, FS_IOC_GETFLAGS, FS_IOC_SETFLAGS, FS_UNRM_FL };
#endif /* FS_UNRM_FL */
#if defined(EXT2_COMPR_FL) && !defined(FS_COMPR_FL)
# define FS_COMPR_FL EXT2_COMPR_FL
#endif
#ifdef FS_COMPR_FL
/* compress file, chattr 'c' */
const struct optdesc opt_fs_compr = { "fs-compr", "compr", OPT_FS_COMPR, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, FS_IOC_GETFLAGS, FS_IOC_SETFLAGS, FS_COMPR_FL };
#endif /* FS_COMPR_FL */
#if defined(EXT2_SYNC_FL) && !defined(FS_SYNC_FL)
# define FS_SYNC_FL EXT2_SYNC_FL
#endif
#ifdef FS_SYNC_FL
/* synchronous update, chattr 'S' */
const struct optdesc opt_fs_sync = { "fs-sync", "sync", OPT_FS_SYNC, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, FS_IOC_GETFLAGS, FS_IOC_SETFLAGS, FS_SYNC_FL };
#endif /* FS_SYNC_FL */
#if defined(EXT2_IMMUTABLE_FL) && !defined(FS_IMMUTABLE_FL)
# define FS_IMMUTABLE_FL EXT2_IMMUTABLE_FL
#endif
#ifdef FS_IMMUTABLE_FL
/* immutable file, chattr 'i' */
const struct optdesc opt_fs_immutable = { "fs-immutable", "immutable", OPT_FS_IMMUTABLE, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, FS_IOC_GETFLAGS, FS_IOC_SETFLAGS, FS_IMMUTABLE_FL };
#endif /* FS_IMMUTABLE_FL */
#if defined(EXT2_APPEND_FL) && !defined(FS_APPEND_FL)
# define FS_APPEND_FL EXT2_APPEND_FL
#endif
#ifdef FS_APPEND_FL
/* writes to file may only append, chattr 'a' */
const struct optdesc opt_fs_append = { "fs-append", "append", OPT_FS_APPEND, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, FS_IOC_GETFLAGS, FS_IOC_SETFLAGS, FS_APPEND_FL };
#endif /* FS_APPEND_FL */
#if defined(EXT2_NODUMP_FL) && !defined(FS_NODUMP_FL)
# define FS_NODUMP_FL EXT2_NODUMP_FL
#endif
#ifdef FS_NODUMP_FL
/* do not dump file, chattr 'd' */
const struct optdesc opt_fs_nodump = { "fs-nodump", "nodump", OPT_FS_NODUMP, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, FS_IOC_GETFLAGS, FS_IOC_SETFLAGS, FS_NODUMP_FL };
#endif /* FS_NODUMP_FL */
#if defined(EXT2_NOATIME_FL) && !defined(FS_NOATIME_FL)
# define FS_NOATIME_FL EXT2_NOATIME_FL
#endif
#ifdef FS_NOATIME_FL
/* do not update atime, chattr 'A' */
const struct optdesc opt_fs_noatime = { "fs-noatime", "noatime", OPT_FS_NOATIME, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, FS_IOC_GETFLAGS, FS_IOC_SETFLAGS, FS_NOATIME_FL };
#endif /* FS_NOATIME_FL */
/* FS_DIRTY_FL ??? */
/* FS_COMPRBLK_FL one ore more compress clusters */
/* FS_NOCOMPR_FL access raw compressed data */
/* FS_ECOMPR_FL compression error */
/* FS_BTREE_FL btree format dir */
/* FS_INDEX_FL hash indexed directory */
/* FS_IMAGIC ??? */
#if defined(EXT2_JOURNAL_DATA_FL) && !defined(FS_JOURNAL_DATA_FL)
# define FS_JOURNAL_DATA_FL EXT2_JOURNAL_DATA_FL
#endif
#ifdef FS_JOURNAL_DATA_FL
/* file data should be journaled, chattr 'j' */
const struct optdesc opt_fs_journal_data = { "fs-journal-data", "journal-data", OPT_FS_JOURNAL_DATA, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, FS_IOC_GETFLAGS, FS_IOC_SETFLAGS, FS_JOURNAL_DATA_FL };
#endif /* FS_JOURNAL_DATA_FL */
#if defined(EXT2_NOTAIL_FL) && !defined(FS_NOTAIL_FL)
# define FS_NOTAIL_FL EXT2_NOTAIL_FL
#endif
#ifdef FS_NOTAIL_FL
/* file tail should not be merged, chattr 't' */
const struct optdesc opt_fs_notail = { "fs-notail", "notail", OPT_FS_NOTAIL, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, FS_IOC_GETFLAGS, FS_IOC_SETFLAGS, FS_NOTAIL_FL };
#endif /* FS_NOTAIL_FL */
#if defined(EXT2_DIRSYNC_FL) && !defined(FS_DIRSYNC_FL)
# define FS_DIRSYNC_FL EXT2_DIRSYNC_FL
#endif
#ifdef FS_DIRSYNC_FL
/* synchronous directory modifications, chattr 'D' */
const struct optdesc opt_fs_dirsync = { "fs-dirsync", "dirsync", OPT_FS_DIRSYNC, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, FS_IOC_GETFLAGS, FS_IOC_SETFLAGS, FS_DIRSYNC_FL };
#endif /* FS_DIRSYNC_FL */
#if defined(EXT2_TOPDIR_FL) && !defined(FS_TOPDIR_FL)
# define FS_TOPDIR_FL EXT2_TOPDIR_FL
#endif
#ifdef FS_TOPDIR_FL
/* top of directory hierarchies, chattr 'T' */
const struct optdesc opt_fs_topdir = { "fs-topdir", "topdir", OPT_FS_TOPDIR, GROUP_REG, PH_FD, TYPE_BOOL, OFUNC_IOCTL_MASK_LONG, FS_IOC_GETFLAGS, FS_IOC_SETFLAGS, FS_TOPDIR_FL };
#endif /* FS_TOPDIR_FL */
/* EXTENTS inode uses extents */
#endif /* WITH_FS */

58
xio-fs.h Normal file
View File

@@ -0,0 +1,58 @@
/* source: xio-fs.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_fs_h_included
#define __xio_fs_h_included 1
#if defined(EXT2_SECRM_FL) && !defined(FS_SECRM_FL)
# define FS_SECRM_FL EXT2_SECRM_FL
#endif
#if defined(EXT2_UNRM_FL) && !defined(FS_UNRM_FL)
# define FS_UNRM_FL EXT2_UNRM_FL
#endif
#if defined(EXT2_COMPR_FL) && !defined(FS_COMPR_FL)
# define FS_COMPR_FL EXT2_COMPR_FL
#endif
#if defined(EXT2_SYNC_FL) && !defined(FS_SYNC_FL)
# define FS_SYNC_FL EXT2_SYNC_FL
#endif
#if defined(EXT2_IMMUTABLE_FL) && !defined(FS_IMMUTABLE_FL)
# define FS_IMMUTABLE_FL EXT2_IMMUTABLE_FL
#endif
#if defined(EXT2_APPEND_FL) && !defined(FS_APPEND_FL)
# define FS_APPEND_FL EXT2_APPEND_FL
#endif
#if defined(EXT2_NODUMP_FL) && !defined(FS_NODUMP_FL)
# define FS_NODUMP_FL EXT2_NODUMP_FL
#endif
#if defined(EXT2_NOATIME_FL) && !defined(FS_NOATIME_FL)
# define FS_NOATIME_FL EXT2_NOATIME_FL
#endif
#if defined(EXT2_JOURNAL_DATA_FL) && !defined(FS_JOURNAL_DATA_FL)
# define FS_JOURNAL_DATA_FL EXT2_JOURNAL_DATA_FL
#endif
#if defined(EXT2_NOTAIL_FL) && !defined(FS_NOTAIL_FL)
# define FS_NOTAIL_FL EXT2_NOTAIL_FL
#endif
#if defined(EXT2_DIRSYNC_FL) && !defined(FS_DIRSYNC_FL)
# define FS_DIRSYNC_FL EXT2_DIRSYNC_FL
#endif
#if defined(EXT2_TOPDIR_FL) && !defined(FS_TOPDIR_FL)
# define FS_TOPDIR_FL EXT2_TOPDIR_FL
#endif
extern const struct optdesc opt_fs_secrm;
extern const struct optdesc opt_fs_unrm;
extern const struct optdesc opt_fs_compr;
extern const struct optdesc opt_fs_sync;
extern const struct optdesc opt_fs_immutable;
extern const struct optdesc opt_fs_append;
extern const struct optdesc opt_fs_nodump;
extern const struct optdesc opt_fs_noatime;
extern const struct optdesc opt_fs_journal_data;
extern const struct optdesc opt_fs_notail;
extern const struct optdesc opt_fs_dirsync;
extern const struct optdesc opt_fs_topdir;
#endif /* !defined(__xio_fs_h_included) */

134
xio-gopen.c Normal file
View File

@@ -0,0 +1,134 @@
/* source: xio-gopen.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of generic open type */
#include "xiosysincludes.h"
#include "xioopen.h"
#include "xio-named.h"
#include "xio-unix.h"
#include "xio-gopen.h"
#if WITH_GOPEN
static int xioopen_gopen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, const struct addrdesc *addrdesc);
const struct addrdesc xioaddr_gopen = { "GOPEN", 3, xioopen_gopen, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_REG|GROUP_NAMED|GROUP_OPEN|GROUP_FILE|GROUP_TERMIOS|GROUP_SOCKET|GROUP_SOCK_UNIX, 0, 0, 0 HELP(":<filename>") };
static int xioopen_gopen(
int argc,
const char *argv[],
struct opt *opts,
int xioflags,
xiofile_t *xxfd,
const struct addrdesc *addrdesc)
{
struct single *sfd = &xxfd->stream;
const char *filename = argv[1];
flags_t openflags = (xioflags & XIO_ACCMODE);
mode_t st_mode;
bool exists;
bool opt_unlink_close = false;
int result;
if ((result =
_xioopen_named_early(argc, argv, xxfd, GROUP_NAMED|addrdesc->groups, &exists,
opts, addrdesc->syntax))
< 0) {
return result;
}
st_mode = result;
if (exists) {
/* file (or at least named entry) exists */
if ((xioflags&XIO_ACCMODE) != XIO_RDONLY) {
openflags |= O_APPEND;
}
} else {
openflags |= O_CREAT;
}
/* note: when S_ISSOCK was undefined, it always gives 0 */
if (exists && S_ISSOCK(st_mode)) {
#if WITH_UNIX
union sockaddr_union us;
socklen_t uslen = sizeof(us);
char infobuff[256];
Info1("\"%s\" is a socket, connecting to it", filename);
result =
_xioopen_unix_client(sfd, xioflags, addrdesc->groups, 0, opts,
filename, addrdesc);
if (result < 0) {
return result;
}
applyopts_named(filename, opts, PH_PASTOPEN); /* unlink-late */
if (Getsockname(sfd->fd, (struct sockaddr *)&us, &uslen) < 0) {
Warn4("getsockname(%d, %p, {%d}): %s",
sfd->fd, &us, uslen, strerror(errno));
} else {
Notice1("successfully connected via %s",
sockaddr_unix_info(&us.un, uslen,
infobuff, sizeof(infobuff)));
}
#else
Error("\"%s\" is a socket, but UNIX socket support is not compiled in");
return -1;
#endif /* WITH_UNIX */
} else {
/* a file name */
Info1("\"%s\" is not a socket, open()'ing it", filename);
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
if (opt_unlink_close) {
if ((sfd->unlink_close = strdup(filename)) == NULL) {
Error1("strdup(\"%s\"): out of memory", filename);
}
sfd->opt_unlink_close = true;
}
Notice3("opening %s \"%s\" for %s",
filetypenames[(st_mode&S_IFMT)>>12], filename, ddirection[(xioflags&XIO_ACCMODE)]);
if ((result = _xioopen_open(filename, openflags, opts)) < 0)
return result;
#ifdef I_PUSH
if (S_ISCHR(st_mode) && Ioctl(result, I_FIND, "ldterm\0") == 0) {
Ioctl(result, I_PUSH, "ptem\0\0\0"); /* pad string length ... */
Ioctl(result, I_PUSH, "ldterm\0"); /* ... to requirements of ... */
Ioctl(result, I_PUSH, "ttcompat"); /* ... AdressSanitizer */
}
#endif
sfd->fd = result;
#if WITH_TERMIOS
if (Isatty(sfd->fd)) {
if (Tcgetattr(sfd->fd, &sfd->savetty) < 0) {
Warn2("cannot query current terminal settings on fd %d: %s",
sfd->fd, strerror(errno));
} else {
sfd->ttyvalid = true;
}
}
#endif /* WITH_TERMIOS */
applyopts_named(filename, opts, PH_FD);
applyopts(sfd, -1, opts, PH_FD);
applyopts_cloexec(sfd->fd, opts);
}
if ((result = applyopts2(sfd, -1, opts, PH_PASTSOCKET, PH_CONNECTED)) < 0)
return result;
if ((result = _xio_openlate(sfd, opts)) < 0)
return result;
return 0;
}
#endif /* WITH_GOPEN */

10
xio-gopen.h Normal file
View File

@@ -0,0 +1,10 @@
/* source: xio-gopen.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_gopen_h_included
#define __xio_gopen_h_included 1
extern const struct addrdesc xioaddr_gopen;
#endif /* !defined(__xio_gopen_h_included) */

342
xio-interface.c Normal file
View File

@@ -0,0 +1,342 @@
/* source: xio-interface.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of raw socket type */
#include "xiosysincludes.h"
#if _WITH_INTERFACE
#include "xioopen.h"
#include "xio-socket.h"
#include "xio-ascii.h"
#include "xio-interface.h"
static int xioopen_interface(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, const struct addrdesc *addrdesc);
/*0 const struct optdesc opt_interface_addr = { "interface-addr", "address", OPT_INTERFACE_ADDR, GROUP_INTERFACE, PH_FD, TYPE_STRING, OFUNC_SPEC };*/
/*0 const struct optdesc opt_interface_netmask = { "interface-netmask", "netmask", OPT_INTERFACE_NETMASK, GROUP_INTERFACE, PH_FD, TYPE_STRING, OFUNC_SPEC };*/
const struct optdesc opt_iff_up = { "iff-up", "up", OPT_IFF_UP, GROUP_INTERFACE, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_UP };
const struct optdesc opt_iff_broadcast = { "iff-broadcast", NULL, OPT_IFF_BROADCAST, GROUP_INTERFACE, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_BROADCAST };
const struct optdesc opt_iff_debug = { "iff-debug" , NULL, OPT_IFF_DEBUG, GROUP_INTERFACE, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_DEBUG };
const struct optdesc opt_iff_loopback = { "iff-loopback" , "loopback", OPT_IFF_LOOPBACK, GROUP_INTERFACE, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_LOOPBACK };
const struct optdesc opt_iff_pointopoint = { "iff-pointopoint", "pointopoint",OPT_IFF_POINTOPOINT, GROUP_INTERFACE, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_POINTOPOINT };
const struct optdesc opt_iff_notrailers = { "iff-notrailers", "notrailers", OPT_IFF_NOTRAILERS, GROUP_INTERFACE, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_NOTRAILERS };
const struct optdesc opt_iff_running = { "iff-running", "running", OPT_IFF_RUNNING, GROUP_INTERFACE, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_RUNNING };
const struct optdesc opt_iff_noarp = { "iff-noarp", "noarp", OPT_IFF_NOARP, GROUP_INTERFACE, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_NOARP };
const struct optdesc opt_iff_promisc = { "iff-promisc", "promisc", OPT_IFF_PROMISC, GROUP_INTERFACE, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_PROMISC };
const struct optdesc opt_iff_allmulti = { "iff-allmulti", "allmulti", OPT_IFF_ALLMULTI, GROUP_INTERFACE, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_ALLMULTI };
#ifdef IFF_MASTER
const struct optdesc opt_iff_master = { "iff-master", "master", OPT_IFF_MASTER, GROUP_INTERFACE, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_MASTER };
#endif
#ifdef IFF_SLAVE
const struct optdesc opt_iff_slave = { "iff-slave", "slave", OPT_IFF_SLAVE, GROUP_INTERFACE, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_SLAVE };
#endif
const struct optdesc opt_iff_multicast = { "iff-multicast", NULL, OPT_IFF_MULTICAST, GROUP_INTERFACE, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_MULTICAST };
#ifdef IFF_PORTSEL
const struct optdesc opt_iff_portsel = { "iff-portsel", "portsel", OPT_IFF_PORTSEL, GROUP_INTERFACE, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_PORTSEL };
#endif
#ifdef IFF_AUTOMEDIA
const struct optdesc opt_iff_automedia = { "iff-automedia", "automedia", OPT_IFF_AUTOMEDIA, GROUP_INTERFACE, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_AUTOMEDIA };
#endif
/*const struct optdesc opt_iff_dynamic = { "iff-dynamic", "dynamic", OPT_IFF_DYNAMIC, GROUP_INTERFACE, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(short), IFF_DYNAMIC };*/
#ifdef PACKET_AUXDATA
const struct optdesc opt_retrieve_vlan = { "retrieve-vlan", NULL, OPT_RETRIEVE_VLAN, GROUP_INTERFACE, PH_LATE, TYPE_CONST, OFUNC_SPEC };
#endif
#if LATER
const struct optdesc opt_route = { "route", NULL, OPT_ROUTE, GROUP_INTERFACE, PH_INIT, TYPE_STRING, OFUNC_SPEC };
#endif
#if WITH_INTERFACE
const struct addrdesc xioaddr_interface = { "INTERFACE", 3, xioopen_interface, GROUP_FD|GROUP_SOCKET|GROUP_INTERFACE, PF_PACKET, 0, 0 HELP(":<interface>") };
#endif /* WITH_INTERFACE */
static
int _xioopen_interface(const char *ifname,
struct opt *opts, int xioflags, xiofile_t *xxfd,
groups_t groups, int pf) {
xiosingle_t *sfd = &xxfd->stream;
union sockaddr_union us = {{0}};
socklen_t uslen;
int socktype = SOCK_RAW;
unsigned int ifidx;
bool needbind = false;
char *bindstring = NULL;
struct sockaddr_ll sall = { 0 };
int rc;
if (ifindex(ifname, &ifidx, -1) < 0) {
Error1("unknown interface \"%s\"", ifname);
ifidx = 0; /* desparate attempt to continue */
}
if (sfd->howtoend == END_UNSPEC)
sfd->howtoend = END_INTERFACE;
retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_socket_pf(opts, &pf);
/* ...res_opts[] */
if (applyopts_single(sfd, opts, PH_INIT) < 0) return -1;
applyopts(sfd, -1, opts, PH_INIT);
sfd->salen = sizeof(sfd->peersa);
if (pf == PF_UNSPEC) {
pf = sfd->peersa.soa.sa_family;
}
sfd->dtype = XIODATA_RECVFROM_SKIPIP;
if (retropt_string(opts, OPT_BIND, &bindstring)) {
needbind = true;
}
/*!!! parse by ':' */
us.ll.sll_family = pf;
us.ll.sll_protocol = htons(ETH_P_ALL);
us.ll.sll_ifindex = ifidx;
uslen = sizeof(sall);
needbind = true;
sfd->peersa = (union sockaddr_union)us;
rc =
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
opts, xioflags, sfd, groups, pf, socktype, 0, 0);
if (rc < 0)
return rc;
strncpy(sfd->para.interface.name, ifname, IFNAMSIZ);
_xiointerface_get_iff(sfd->fd, ifname, &sfd->para.interface.save_iff);
_xiointerface_apply_iff(sfd->fd, ifname, sfd->para.interface.iff_opts);
if (_interface_retrieve_vlan(sfd, opts) < 0)
return STAT_NORETRY;
#ifdef PACKET_IGNORE_OUTGOING
/* Raw socket might also provide packets that are outbound - we are not
interested in these and disable this "feature" in kernel if possible */
if (Setsockopt(sfd->fd, SOL_PACKET, PACKET_IGNORE_OUTGOING, &one, sizeof(one)) < 0) {
Warn2("setsockopt(%d, SOL_PACKET, PACKET_IGNORE_OUTGOING, {1}): %s",
sfd->fd, strerror(errno));
}
#endif /*defined(PACKET_IGNORE_OUTGOING) */
return 0;
}
int _interface_retrieve_vlan(struct single *sfd, struct opt *opts) {
#if HAVE_STRUCT_TPACKET_AUXDATA
if (retropt_bool(opts, OPT_RETRIEVE_VLAN,
&sfd->para.socket.retrieve_vlan)
== 0) {
if (!xioparms.experimental) {
Warn1("option %s is experimental", opts->desc->defname);
}
}
if (sfd->para.socket.retrieve_vlan) {
if (_interface_setsockopt_auxdata(sfd->fd, 1) < 0) {
return -1;
}
}
#endif /* HAVE_STRUCT_TPACKET_AUXDATA */
return 0;
}
int _interface_setsockopt_auxdata(int fd, int auxdata) {
#ifdef PACKET_AUXDATA
/* Linux strips VLAN tag off incoming packets and makes it available per
ancillary data as auxdata. Apply option packet-auxdata if you want the
VLAN tag to be restored by Socat in the received packet */
if (auxdata) {
int rc;
Info1("setsockopt(fd=%d, level=SOL_PACKET, optname=PACKET_AUXDATA)", fd);
rc = Setsockopt(fd, SOL_PACKET, PACKET_AUXDATA, &auxdata, sizeof(auxdata));
if (rc < 0) {
Error3("setsockopt(%d, SOL_PACKET, PACKET_AUXDATA, , {%d}): %s",
fd, auxdata, strerror(errno));
}
}
#endif /* defined(PACKET_AUXDATA) */
return 0;
}
static
int xioopen_interface(
int argc,
const char *argv[],
struct opt *opts,
int xioflags,
xiofile_t *xxfd,
const struct addrdesc *addrdesc)
{
xiosingle_t *sfd = &xxfd->stream;
int result;
if (argc != 2) {
xio_syntax(argv[0], 1, argc-1, addrdesc->syntax);
return STAT_NORETRY;
}
if ((result =
_xioopen_interface(argv[1], opts, xioflags, xxfd, addrdesc->groups,
addrdesc->arg1))
!= STAT_OK) {
return result;
}
sfd->dtype = XIOREAD_RECV|XIOWRITE_SENDTO;
if (addrdesc->arg1 == PF_INET) {
sfd->dtype |= XIOREAD_RECV_SKIPIP;
}
sfd->para.socket.la.soa.sa_family = sfd->peersa.soa.sa_family;
_xio_openlate(sfd, opts);
return STAT_OK;
}
/* Retrieves the interface flags related to sockfd */
int _xiointerface_get_iff(
int sockfd,
const char *name,
short *save_iff)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
if (Ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s",
sockfd, ifr.ifr_name, strerror(errno));
}
*save_iff = ifr.ifr_flags;
return 0;
}
/* Applies the interface flags to the socket FD.
Used by INTERFACE and TUN
*/
int _xiointerface_set_iff(
int sockfd,
const char *name,
short new_iff)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
if (Ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s",
sockfd, ifr.ifr_name, strerror(errno));
}
ifr.ifr_flags = new_iff;
if (Ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
Error4("ioctl(%d, SIOCSIFFLAGS, {\"%s\", %hd}: %s",
sockfd, ifr.ifr_name, ifr.ifr_flags, strerror(errno));
}
return 0;
}
/* Applies the interface flags to the socket FD
Used by INTERFACE and TUN
*/
int _xiointerface_apply_iff(
int sockfd,
const char *name,
short iff_opts[2])
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
if (Ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s",
sockfd, ifr.ifr_name, strerror(errno));
}
Debug2("\"%s\": system set flags: 0x%hx", ifr.ifr_name, ifr.ifr_flags);
ifr.ifr_flags |= iff_opts[0];
ifr.ifr_flags &= ~iff_opts[1];
Debug2("\"%s\": xio merged flags: 0x%hx", ifr.ifr_name, ifr.ifr_flags);
if (Ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
Error4("ioctl(%d, SIOCSIFFLAGS, {\"%s\", %hd}: %s",
sockfd, ifr.ifr_name, ifr.ifr_flags, strerror(errno));
}
ifr.ifr_flags = 0;
if (Ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s",
sockfd, ifr.ifr_name, strerror(errno));
}
Debug2("\"%s\": resulting flags: 0x%hx", ifr.ifr_name, ifr.ifr_flags);
return 0;
}
#if HAVE_STRUCT_CMSGHDR && HAVE_STRUCT_TPACKET_AUXDATA
/* Converts the ancillary message in *cmsg into a form useable for further
processing. Knows the specifics of common message types.
On PACKET_AUXDATA it stored the ancillary data in the XFD.
For other types:
returns the number of resulting syntax elements in *num,
returns a sequence of \0 terminated type strings in *typbuff,
returns a sequence of \0 terminated name strings in *nambuff,
returns a sequence of \0 terminated value strings in *valbuff,
the respective len parameters specify the available space in the buffers
returns STAT_OK or other STAT_*
*/
int
xiolog_ancillary_packet(struct single *sfd,
struct cmsghdr *cmsg, int *num,
char *typbuff, int typlen,
char *nambuff, int namlen,
char *envbuff, int envlen,
char *valbuff, int vallen) {
#if LATER
const char *cmsgtype, *cmsgname, *cmsgenvn;
size_t msglen;
#endif
struct tpacket_auxdata *auxp;
int rc = STAT_OK;
*num = 0;
#if defined(CMSG_DATA)
#if LATER
msglen = cmsg->cmsg_len-((char *)CMSG_DATA(cmsg)-(char *)cmsg);
#endif
switch (cmsg->cmsg_type) {
#if HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TPID
case PACKET_AUXDATA:
#if LATER
cmsgname = "packet_auxdata";
cmsgtype = "auxdata";
cmsgenvn = "AUXDATA";
#endif
auxp = (struct tpacket_auxdata *)CMSG_DATA(cmsg);
Info8("%s(): Ancillary message: PACKET_AUXDATA: status="F_uint32_t", len="F_uint32_t", snaplen="F_uint32_t", mac="F_uint16_t", net="F_uint16_t", vlan_tci="F_uint16_t", vlan_tpid="F_uint16_t"", __func__, auxp->tp_status, auxp->tp_len, auxp->tp_snaplen, auxp->tp_mac, auxp->tp_net, auxp->tp_vlan_tci, auxp->tp_vlan_tpid);
sfd->para.socket.ancill_data_packet_auxdata = *auxp;
sfd->para.socket.ancill_flag.packet_auxdata = 1;
snprintf(typbuff, typlen, "PACKET.%u", cmsg->cmsg_type);
nambuff[0] = '\0'; strncat(nambuff, "vlan", namlen-1);
snprintf(strchr(valbuff, '\0')-1/*def \n*/, vallen-strlen(valbuff)+1, ", %d", auxp->tp_vlan_tci);
break;
#endif /* HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TPID */
default: /* binary data */
Warn1("xiolog_ancillary_packet(): INTERNAL: cmsg_type=%d not handled", cmsg->cmsg_type);
return rc;
}
return rc;
#else /* !defined(CMSG_DATA) */
return STAT_NORETRY;
#endif /* !defined(CMSG_DATA) */
}
#endif /* HAVE_STRUCT_CMSGHDR && HAVE_STRUCT_TPACKET_AUXDATA */
#endif /* _WITH_INTERFACE */

38
xio-interface.h Normal file
View File

@@ -0,0 +1,38 @@
/* source: xio-interface.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_interface_h_included
#define __xio_interface_h_included 1
extern const struct addrdesc xioaddr_interface;
extern const struct optdesc opt_interface_addr;
extern const struct optdesc opt_interface_netmask;
extern const struct optdesc opt_iff_up;
extern const struct optdesc opt_iff_broadcast;
extern const struct optdesc opt_iff_debug;
extern const struct optdesc opt_iff_loopback;
extern const struct optdesc opt_iff_pointopoint;
extern const struct optdesc opt_iff_notrailers;
extern const struct optdesc opt_iff_running;
extern const struct optdesc opt_iff_noarp;
extern const struct optdesc opt_iff_promisc;
extern const struct optdesc opt_iff_allmulti;
extern const struct optdesc opt_iff_master;
extern const struct optdesc opt_iff_slave;
extern const struct optdesc opt_iff_multicast;
extern const struct optdesc opt_iff_portsel;
extern const struct optdesc opt_iff_automedia;
/*extern const struct optdesc opt_iff_dynamic;*/
extern const struct optdesc opt_retrieve_vlan;
extern int xiolog_ancillary_packet(struct single *sfd, struct cmsghdr *cmsg, int *num, char *typbuff, int typlen, char *nambuff, int namlen, char *envbuff, int envlen, char *valbuff, int vallen);
extern int _interface_retrieve_vlan(struct single *fd, struct opt *opts);
extern int _xiointerface_get_iff(int sockfd, const char *name, short *save_iff);
extern int _xiointerface_set_iff(int sockfd, const char *name, short new_iff);
extern int _xiointerface_apply_iff(int sockfd, const char *name, short iff_opts[2]);
extern int _interface_setsockopt_auxdata(int fd, int auxdata);
#endif /* !defined(__xio_interface_h_included) */

1093
xio-ip.c Normal file

File diff suppressed because it is too large Load Diff

65
xio-ip.h Normal file
View File

@@ -0,0 +1,65 @@
/* source: xio-ip.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_ip_h_included
#define __xio_ip_h_included 1
extern const struct optdesc opt_ip_options;
extern const struct optdesc opt_ip_pktinfo;
extern const struct optdesc opt_ip_recvtos;
extern const struct optdesc opt_ip_recvttl;
extern const struct optdesc opt_ip_recvopts;
extern const struct optdesc opt_ip_retopts;
extern const struct optdesc opt_ip_tos;
extern const struct optdesc opt_ip_ttl;
extern const struct optdesc opt_ip_hdrincl;
extern const struct optdesc opt_ip_recverr;
extern const struct optdesc opt_ip_mtu_discover;
extern const struct optdesc opt_ip_mtu;
extern const struct optdesc opt_ip_freebind;
extern const struct optdesc opt_ip_router_alert;
extern const struct optdesc opt_ip_multicast_ttl;
extern const struct optdesc opt_ip_multicast_loop;
extern const struct optdesc opt_ip_multicast_if;
extern const struct optdesc opt_ip_pktoptions;
extern const struct optdesc opt_ip_add_membership;
extern const struct optdesc opt_ip_add_source_membership;
extern const struct optdesc opt_ip_recvdstaddr;
extern const struct optdesc opt_ip_recvif;
extern const struct optdesc opt_ip_transparent;
extern const struct optdesc opt_ai_addrconfig;
extern const struct optdesc opt_ai_passive;
extern const struct optdesc opt_ai_v4mapped;
extern const struct optdesc opt_res_debug;
extern const struct optdesc opt_res_aaonly;
extern const struct optdesc opt_res_usevc;
extern const struct optdesc opt_res_primary;
extern const struct optdesc opt_res_igntc;
extern const struct optdesc opt_res_recurse;
extern const struct optdesc opt_res_defnames;
extern const struct optdesc opt_res_stayopen;
extern const struct optdesc opt_res_dnsrch;
extern const struct optdesc opt_res_retrans;
extern const struct optdesc opt_res_retry;
extern const struct optdesc opt_res_nsaddr;
extern int xioinit_ip(int *pf, char ipv);
extern int xiogetaddrinfo(const char *node, const char *service, int family, int socktype, int protocol, struct addrinfo **res, const int ai_flags[2]);
extern void xiofreeaddrinfo(struct addrinfo *res);
extern int xioresolve(const char *node, const char *service, int family, int socktype, int protocol, union sockaddr_union *addr, socklen_t *addrlen, const int ai_flags[2]);
extern int xiolog_ancillary_ip(struct single *sfd, struct cmsghdr *cmsg, int *num, char *typbuff, int typlen, char *nambuff, int namlen, char *envbuff, int envlen, char *valbuff, int vallen);
extern int xiotype_ip_add_membership(char *token, const struct optname *ent, struct opt *opt);
extern int xioapply_ip_add_membership(xiosingle_t *xfd, struct opt *opt);
extern int xiotype_ip_add_source_membership(char* token, const struct optname *ent, struct opt *opt);
extern int xioapply_ip_add_source_membership(struct single *xfd, struct opt *opt);
#if WITH_RESOLVE && HAVE_RESOLV_H
extern int xio_res_init(struct single *sfd, struct __res_state *save_res);
extern int xio_res_restore(struct __res_state *save_res);
#endif /* WITH_RESOLVE && HAVE_RESOLV_H */
#endif /* !defined(__xio_ip_h_included) */

142
xio-ip4.c Normal file
View File

@@ -0,0 +1,142 @@
/* source: xio-ip4.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for IP4 related functions */
#include "xiosysincludes.h"
#if WITH_IP4
#include "xioopen.h"
#include "xio-socket.h"
#include "xio-ip.h"
#include "xio-ip4.h"
int xioparsenetwork_ip4(
const char *rangename,
struct xiorange *range,
const int ai_flags[2])
{
struct in_addr *netaddr_in = &range->netaddr.ip4.sin_addr;
struct in_addr *netmask_in = &range->netmask.ip4.sin_addr;
char *rangename1; /* a copy of rangename with writing allowed */
char *delimpos; /* absolute address of delimiter */
unsigned int bits; /* netmask bits */
union sockaddr_union sau;
socklen_t socklen = sizeof(sau);
int rc;
if ((rangename1 = strdup(rangename)) == NULL) {
Error1("strdup(\"%s\"): out of memory", rangename);
return STAT_RETRYLATER;
}
if (delimpos = strchr(rangename1, '/')) {
char *endptr;
bits = strtoul(delimpos+1, &endptr, 10);
if (! ((*(delimpos+1) != '\0') && (*endptr == '\0'))) {
Error1("not a valid IPv4 netmask in \"%s\"", rangename);
bits = 32; /* most secure selection */
} else if (bits > 32) {
Error1("IPv4 netmask \"%s\" is too large", rangename);
bits = 32;
}
if (bits <= 0) {
netmask_in->s_addr = 0;
} else {
netmask_in->s_addr = htonl((0xffffffff << (32-bits)));
}
} else if (delimpos = strchr(rangename1, ':')) {
if ((rc = xioresolve(delimpos+1, NULL, PF_INET, 0, 0,
&sau, &socklen, ai_flags))
!= STAT_OK) {
return rc;
}
netmask_in->s_addr = sau.ip4.sin_addr.s_addr;
} else {
Error1("xioparsenetwork_ip4(\"%s\",,): missing netmask delimiter", rangename);
free(rangename1);
return STAT_NORETRY;
}
{
*delimpos = 0;
if ((rc = xioresolve(rangename1, NULL, PF_INET, 0, 0,
&sau, &socklen, ai_flags))
!= STAT_OK) {
return rc;
}
netaddr_in->s_addr = sau.ip4.sin_addr.s_addr;
}
free(rangename1);
return STAT_OK;
}
/* check if peer address is within permitted range.
return >= 0 if so. */
int xiocheckrange_ip4(struct sockaddr_in *pa, struct xiorange *range) {
struct in_addr *netaddr_in = &range->netaddr.ip4.sin_addr;
struct in_addr *netmask_in = &range->netmask.ip4.sin_addr;
char addrbuf[256], maskbuf[256];
char peername[256];
/* is provided client address valid? */
if (pa->sin_addr.s_addr == 0) {
Warn("invalid client address 0.0.0.0");
return -1;
}
/* client address restriction */
Debug2("permitted client subnet: %s:%s",
inet4addr_info(ntohl(netaddr_in->s_addr), addrbuf, sizeof(addrbuf)),
inet4addr_info(ntohl(netmask_in->s_addr), maskbuf, sizeof(maskbuf)));
Debug1("client address is 0x%08x",
ntohl(pa->sin_addr.s_addr));
Debug1("masked address is 0x%08x",
ntohl(pa->sin_addr.s_addr & netmask_in->s_addr));
if ((pa->sin_addr.s_addr & netmask_in->s_addr)
!= netaddr_in->s_addr) {
Debug1("client address %s is not permitted",
sockaddr_inet4_info(pa, peername, sizeof(peername)));
return -1;
}
return 0;
}
/* returns information that can be used for constructing an environment
variable describing the socket address.
if idx is 0, this function writes "ADDR" into namebuff and the IP address
into valuebuff, and returns 1 (which means that one more info is there).
if idx is 1, it writes "PORT" into namebuff and the port number into
valuebuff, and returns 0 (no more info)
namelen and valuelen contain the max. allowed length of output chars in the
respective buffer.
on error this function returns -1.
*/
int
xiosetsockaddrenv_ip4(int idx, char *namebuff, size_t namelen,
char *valuebuff, size_t valuelen,
struct sockaddr_in *sa, int ipproto) {
switch (idx) {
case 0:
strcpy(namebuff, "ADDR");
inet4addr_info(ntohl(sa->sin_addr.s_addr), valuebuff, valuelen);
switch (ipproto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
#ifdef IPPROTO_SCTP
case IPPROTO_SCTP:
#endif
return 1; /* there is port information to also be retrieved */
default:
return 0; /* no port info coming */
}
case 1:
strcpy(namebuff, "PORT");
snprintf(valuebuff, valuelen, "%u", ntohs(sa->sin_port));
return 0;
}
return -1;
}
#endif /* WITH_IP4 */

18
xio-ip4.h Normal file
View File

@@ -0,0 +1,18 @@
/* source: xio-ip4.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_ip4_h_included
#define __xio_ip4_h_included 1
extern const struct optdesc opt_ip4_add_membership;
extern int xioparsenetwork_ip4(const char *rangename, struct xiorange *range, const int ai_flags[2]);
extern
int xiocheckrange_ip4(struct sockaddr_in *pa, struct xiorange *range);
extern int
xiosetsockaddrenv_ip4(int idx, char *namebuff, size_t namelen,
char *valuebuff, size_t valuelen,
struct sockaddr_in *sa, int ipproto);
#endif /* !defined(__xio_ip4_h_included) */

671
xio-ip6.c Normal file
View File

@@ -0,0 +1,671 @@
/* source: xio-ip6.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for IP6 related functions */
#include "xiosysincludes.h"
#if WITH_IP6
#include "xioopen.h"
#include "xio-ascii.h"
#include "xio-socket.h"
#include "xio-ip.h" /* xioresolve() */
#include "xio-ip6.h"
#include "nestlex.h"
static char *inet6addr_info(const struct in6_addr *sa, char *buff, size_t blen);
#ifdef IPV6_V6ONLY
const struct optdesc opt_ipv6_v6only = { "ipv6-v6only", "ipv6only", OPT_IPV6_V6ONLY, GROUP_SOCK_IP6, PH_PREBIND, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_V6ONLY };
#endif
#ifdef IPV6_JOIN_GROUP
const struct optdesc opt_ipv6_join_group = { "ipv6-join-group", "join-group", OPT_IPV6_JOIN_GROUP, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_IP_MREQN, OFUNC_SOCKOPT, SOL_IPV6, IPV6_JOIN_GROUP };
#endif
#ifdef MCAST_JOIN_SOURCE_GROUP
const struct optdesc opt_ipv6_join_source_group = { "ipv6-join-source-group", "join-source-group", OPT_IPV6_JOIN_SOURCE_GROUP, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_GROUP_SOURCE_REQ, OFUNC_SOCKOPT, SOL_IPV6, MCAST_JOIN_SOURCE_GROUP };
#endif
#ifdef IPV6_PKTINFO
const struct optdesc opt_ipv6_pktinfo = { "ipv6-pktinfo", "pktinfo", OPT_IPV6_PKTINFO, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_PKTINFO };
#endif
#ifdef IPV6_RECVPKTINFO
const struct optdesc opt_ipv6_recvpktinfo = { "ipv6-recvpktinfo", "recvpktinfo", OPT_IPV6_RECVPKTINFO, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVPKTINFO };
#endif
#ifdef IPV6_RTHDR
const struct optdesc opt_ipv6_rthdr = { "ipv6-rthdr", "rthdr", OPT_IPV6_RTHDR, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RTHDR };
#endif
#ifdef IPV6_RECVRTHDR
const struct optdesc opt_ipv6_recvrthdr = { "ipv6-recvrthdr", "recvrthdr", OPT_IPV6_RECVRTHDR, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVRTHDR };
#endif
#ifdef IPV6_AUTHHDR
const struct optdesc opt_ipv6_authhdr = { "ipv6-authhdr", "authhdr", OPT_IPV6_AUTHHDR, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_AUTHHDR };
#endif
#ifdef IPV6_DSTOPTS
const struct optdesc opt_ipv6_dstopts = { "ipv6-dstopts", "dstopts", OPT_IPV6_DSTOPTS, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_DSTOPTS };
#endif
#ifdef IPV6_RECVDSTOPTS
const struct optdesc opt_ipv6_recvdstopts = { "ipv6-recvdstopts", "recvdstopts", OPT_IPV6_RECVDSTOPTS, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVDSTOPTS };
#endif
#ifdef IPV6_HOPOPTS
const struct optdesc opt_ipv6_hopopts = { "ipv6-hopopts", "hopopts", OPT_IPV6_HOPOPTS, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_HOPOPTS };
#endif
#ifdef IPV6_RECVHOPOPTS
const struct optdesc opt_ipv6_recvhopopts = { "ipv6-recvhopopts", "recvhopopts", OPT_IPV6_RECVHOPOPTS, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVHOPOPTS };
#endif
#ifdef IPV6_FLOWINFO /* is in linux/in6.h */
const struct optdesc opt_ipv6_flowinfo= { "ipv6-flowinfo","flowinfo",OPT_IPV6_FLOWINFO,GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_FLOWINFO };
#endif
#ifdef IPV6_HOPLIMIT
const struct optdesc opt_ipv6_hoplimit= { "ipv6-hoplimit","hoplimit",OPT_IPV6_HOPLIMIT,GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_HOPLIMIT };
#endif
const struct optdesc opt_ipv6_unicast_hops= { "ipv6-unicast-hops","unicast-hops",OPT_IPV6_UNICAST_HOPS,GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_UNICAST_HOPS };
#ifdef IPV6_RECVHOPLIMIT
const struct optdesc opt_ipv6_recvhoplimit= { "ipv6-recvhoplimit","recvhoplimit",OPT_IPV6_RECVHOPLIMIT,GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVHOPLIMIT };
#endif
#ifdef IPV6_RECVERR
const struct optdesc opt_ipv6_recverr = { "ipv6-recverr", "recverr", OPT_IPV6_RECVERR, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVERR };
#endif
#ifdef IPV6_TCLASS
const struct optdesc opt_ipv6_tclass = { "ipv6-tclass", "tclass", OPT_IPV6_TCLASS, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_TCLASS };
#endif
#ifdef IPV6_RECVTCLASS
const struct optdesc opt_ipv6_recvtclass = { "ipv6-recvtclass", "recvtclass", OPT_IPV6_RECVTCLASS, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVTCLASS };
#endif
#ifdef IPV6_RECVPATHMTU
const struct optdesc opt_ipv6_recvpathmtu = { "ipv6-recvpathmtu", "recvpathmtu", OPT_IPV6_RECVPATHMTU, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVPATHMTU };
#endif
/* Returns canonical form of IPv6 address.
IPv6 address may be enclose in brackets.
Returns STAT_OK on success, STAT_NORETRY on failure. */
int xioip6_pton(
const char *src,
struct in6_addr *dst,
const int ai_flags[2])
{
union sockaddr_union sockaddr;
socklen_t sockaddrlen = sizeof(sockaddr);
if (src[0] == '[') {
char plainaddr[INET6_ADDRSTRLEN];
char *clos;
strncpy(plainaddr, src+1, INET6_ADDRSTRLEN);
plainaddr[INET6_ADDRSTRLEN-1] = '\0';
if ((clos = strchr(plainaddr, ']')) != NULL)
*clos = '\0';
return xioip6_pton(plainaddr, dst, ai_flags);
}
if (xioresolve(src, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen,
ai_flags)
!= STAT_OK) {
return STAT_NORETRY;
}
*dst = sockaddr.ip6.sin6_addr;
return STAT_OK;
}
int xioparsenetwork_ip6(
const char *rangename,
struct xiorange *range,
const int ai_flags[2])
{
char *delimpos; /* absolute address of delimiter */
size_t delimind; /* index of delimiter in string */
unsigned int bits; /* netmask bits */
char *endptr;
char *baseaddr;
union sockaddr_union sockaddr;
socklen_t sockaddrlen = sizeof(sockaddr);
union xioin6_u *rangeaddr = (union xioin6_u *)&range->netaddr.ip6.sin6_addr;
union xioin6_u *rangemask = (union xioin6_u *)&range->netmask.ip6.sin6_addr;
union xioin6_u *nameaddr = (union xioin6_u *)&sockaddr.ip6.sin6_addr;
if ((delimpos = strchr(rangename, '/')) == NULL) {
Error1("xioparsenetwork_ip6(\"%s\",,): missing mask bits delimiter '/'",
rangename);
return STAT_NORETRY;
}
delimind = delimpos - rangename;
if (rangename[0] != '[' || rangename[delimind-1] != ']') {
Error1("missing brackets for IPv6 range definition \"%s\"",
rangename);
return STAT_NORETRY;
}
if ((baseaddr = strndup(rangename+1,delimind-2)) == NULL) {
Error1("strdup(\"%s\"): out of memory", rangename+1);
return STAT_NORETRY;
}
baseaddr[delimind-2] = '\0';
if (xioresolve(baseaddr, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen,
ai_flags)
!= STAT_OK) {
return STAT_NORETRY;
}
rangeaddr->u6_addr32[0] = nameaddr->u6_addr32[0];
rangeaddr->u6_addr32[1] = nameaddr->u6_addr32[1];
rangeaddr->u6_addr32[2] = nameaddr->u6_addr32[2];
rangeaddr->u6_addr32[3] = nameaddr->u6_addr32[3];
bits = strtoul(delimpos+1, &endptr, 10);
if (! ((*(delimpos+1) != '\0') && (*endptr == '\0'))) {
Error1("not a valid netmask in \"%s\"", rangename);
bits = 128; /* most secure selection */
} else if (bits > 128) {
Error1("netmask \"%s\" is too large", rangename);
bits = 128;
}
/* I am starting to dislike C...uint32_t << 32 is undefined... */
if (bits == 0) {
rangemask->u6_addr32[0] = 0;
rangemask->u6_addr32[1] = 0;
rangemask->u6_addr32[2] = 0;
rangemask->u6_addr32[3] = 0;
} else if (bits <= 32) {
rangemask->u6_addr32[0] = htonl(0xffffffff << (32-bits));
rangemask->u6_addr32[1] = 0;
rangemask->u6_addr32[2] = 0;
rangemask->u6_addr32[3] = 0;
} else if (bits <= 64) {
rangemask->u6_addr32[0] = 0xffffffff;
rangemask->u6_addr32[1] = htonl(0xffffffff << (64-bits));
rangemask->u6_addr32[2] = 0;
rangemask->u6_addr32[3] = 0;
} else if (bits <= 96) {
rangemask->u6_addr32[0] = 0xffffffff;
rangemask->u6_addr32[1] = 0xffffffff;
rangemask->u6_addr32[2] = htonl(0xffffffff << (96-bits));
rangemask->u6_addr32[3] = 0;
} else {
rangemask->u6_addr32[0] = 0xffffffff;
rangemask->u6_addr32[1] = 0xffffffff;
rangemask->u6_addr32[2] = 0xffffffff;
rangemask->u6_addr32[3] = htonl(0xffffffff << (128-bits));
}
return 0;
}
int xiorange_ip6andmask(struct xiorange *range) {
int i;
#if 0
range->addr.s6_addr32[0] &= range->mask.s6_addr32[0];
range->addr.s6_addr32[1] &= range->mask.s6_addr32[1];
range->addr.s6_addr32[2] &= range->mask.s6_addr32[2];
range->addr.s6_addr32[3] &= range->mask.s6_addr32[3];
#else
for (i = 0; i < 16; ++i) {
range->netaddr.ip6.sin6_addr.s6_addr[i] &=
range->netmask.ip6.sin6_addr.s6_addr[i];
}
#endif
return 0;
}
/* check if peer address is within permitted range.
return >= 0 if so. */
int xiocheckrange_ip6(struct sockaddr_in6 *pa, struct xiorange *range) {
union xioin6_u masked;
int i;
char peername[256];
union xioin6_u *rangeaddr = (union xioin6_u *)&range->netaddr.ip6.sin6_addr;
union xioin6_u *rangemask = (union xioin6_u *)&range->netmask.ip6.sin6_addr;
Debug16("permitted client subnet: [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
htons(rangeaddr->u6_addr16[0]), htons(rangeaddr->u6_addr16[1]),
htons(rangeaddr->u6_addr16[2]), htons(rangeaddr->u6_addr16[3]),
htons(rangeaddr->u6_addr16[4]), htons(rangeaddr->u6_addr16[5]),
htons(rangeaddr->u6_addr16[6]), htons(rangeaddr->u6_addr16[7]),
htons(rangemask->u6_addr16[0]), htons(rangemask->u6_addr16[1]),
htons(rangemask->u6_addr16[2]), htons(rangemask->u6_addr16[3]),
htons(rangemask->u6_addr16[4]), htons(rangemask->u6_addr16[5]),
htons(rangemask->u6_addr16[6]), htons(rangemask->u6_addr16[7]));
Debug1("client address is %s",
sockaddr_inet6_info(pa, peername, sizeof(peername)));
for (i = 0; i < 4; ++i) {
masked.u6_addr32[i] = ((union xioin6_u *)&pa->sin6_addr.s6_addr[0])->u6_addr32[i] & rangemask->u6_addr32[i];
}
Debug8("masked address is [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
htons(masked.u6_addr16[0]), htons(masked.u6_addr16[1]),
htons(masked.u6_addr16[2]), htons(masked.u6_addr16[3]),
htons(masked.u6_addr16[4]), htons(masked.u6_addr16[5]),
htons(masked.u6_addr16[6]), htons(masked.u6_addr16[7]));
if (masked.u6_addr32[0] != rangeaddr->u6_addr32[0] ||
masked.u6_addr32[1] != rangeaddr->u6_addr32[1] ||
masked.u6_addr32[2] != rangeaddr->u6_addr32[2] ||
masked.u6_addr32[3] != rangeaddr->u6_addr32[3]) {
Debug1("client address %s is not permitted", peername);
return -1;
}
return 0;
}
#if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)
/* provides info about the ancillary message:
converts the ancillary message in *cmsg into a form useable for further
processing. knows the specifics of common message types.
returns the number of resulting syntax elements in *num
returns a sequence of \0 terminated type strings in *typbuff
returns a sequence of \0 terminated name strings in *nambuff
returns a sequence of \0 terminated value strings in *valbuff
the respective len parameters specify the available space in the buffers
returns STAT_OK on success
*/
int xiolog_ancillary_ip6(
struct single *sfd,
struct cmsghdr *cmsg,
int *num,
char *typbuff, int typlen,
char *nambuff, int namlen,
char *envbuff, int envlen,
char *valbuff, int vallen)
{
char scratch1[42]; /* can hold an IPv6 address in ASCII */
char scratch2[32];
size_t msglen;
*num = 1; /* good for most message types */
msglen = cmsg->cmsg_len-((char *)CMSG_DATA(cmsg)-(char *)cmsg);
envbuff[0] = '\0';
switch (cmsg->cmsg_type) {
#if defined(IPV6_PKTINFO) && HAVE_STRUCT_IN6_PKTINFO
case IPV6_PKTINFO: {
struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
*num = 2;
typbuff[0] = '\0'; strncat(typbuff, "IPV6_PKTINFO", typlen-1);
snprintf(nambuff, namlen, "%s%c%s", "dstaddr", '\0', "if");
snprintf(envbuff, envlen, "%s%c%s", "IPV6_DSTADDR", '\0', "IPV6_IF");
snprintf(valbuff, vallen, "%s%c%s",
inet6addr_info(&pktinfo->ipi6_addr, scratch1, sizeof(scratch1)),
'\0', xiogetifname(pktinfo->ipi6_ifindex, scratch2, -1));
}
return STAT_OK;
#endif /* defined(IPV6_PKTINFO) && HAVE_STRUCT_IN6_PKTINFO */
#ifdef IPV6_HOPLIMIT
case IPV6_HOPLIMIT:
typbuff[0] = '\0'; strncat(typbuff, "IPV6_HOPLIMIT", typlen-1);
nambuff[0] = '\0'; strncat(nambuff, "hoplimit", namlen-1);
{
int *intp = (int *)CMSG_DATA(cmsg);
snprintf(valbuff, vallen, "%d", *intp);
}
return STAT_OK;
#endif /* defined(IPV6_HOPLIMIT) */
#ifdef IPV6_RTHDR
case IPV6_RTHDR:
typbuff[0] = '\0'; strncat(typbuff, "IPV6_RTHDR", typlen-1);
nambuff[0] = '\0'; strncat(nambuff, "rthdr", namlen-1);
xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
return STAT_OK;
#endif /* defined(IPV6_RTHDR) */
#ifdef IPV6_AUTHHDR
case IPV6_AUTHHDR:
typbuff[0] = '\0'; strncat(typbuff, "IPV6_AUTHHDR", typlen-1);
nambuff[0] = '\0'; strncat(nambuff, "authhdr", namlen-1);
xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
return STAT_OK;
#endif
#ifdef IPV6_DSTOPTS
case IPV6_DSTOPTS:
typbuff[0] = '\0'; strncat(typbuff, "IPV6_DSTOPTS", typlen-1);
nambuff[0] = '\0'; strncat(nambuff, "dstopts", namlen-1);
xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
return STAT_OK;
#endif /* defined(IPV6_DSTOPTS) */
#ifdef IPV6_HOPOPTS
case IPV6_HOPOPTS:
typbuff[0] = '\0'; strncat(typbuff, "IPV6_HOPOPTS", typlen-1);
nambuff[0] = '\0'; strncat(nambuff, "hopopts", namlen-1);
xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
return STAT_OK;
#endif /* defined(IPV6_HOPOPTS) */
#ifdef IPV6_FLOWINFO
case IPV6_FLOWINFO:
typbuff[0] = '\0'; strncat(typbuff, "IPV6_FLOWINFO", typlen-1);
nambuff[0] = '\0'; strncat(nambuff, "flowinfo", namlen-1);
xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
return STAT_OK;
#endif
#ifdef IPV6_TCLASS
case IPV6_TCLASS: {
unsigned int u;
typbuff[0] = '\0'; strncat(typbuff, "IPV6_TCLASS", typlen-1);
nambuff[0] = '\0'; strncat(nambuff, "tclass", namlen-1);
u = ntohl(*(unsigned int *)CMSG_DATA(cmsg));
xiodump((const unsigned char *)&u, msglen, valbuff, vallen, 0);
return STAT_OK;
}
#endif
default:
snprintf(typbuff, typlen, "IPV6.%u", cmsg->cmsg_type);
nambuff[0] = '\0'; strncat(nambuff, "data", namlen-1);
xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
return STAT_OK;
}
return STAT_OK;
}
#endif /* defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA) */
/* convert the IP6 socket address to human readable form. buff should be at
least 50 chars long. output includes the port number */
static char *inet6addr_info(const struct in6_addr *sa, char *buff, size_t blen) {
if (xio_snprintf(buff, blen, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
#if HAVE_IP6_SOCKADDR==0
(sa->s6_addr[0]<<8)+sa->s6_addr[1],
(sa->s6_addr[2]<<8)+sa->s6_addr[3],
(sa->s6_addr[4]<<8)+sa->s6_addr[5],
(sa->s6_addr[6]<<8)+sa->s6_addr[7],
(sa->s6_addr[8]<<8)+sa->s6_addr[9],
(sa->s6_addr[10]<<8)+sa->s6_addr[11],
(sa->s6_addr[12]<<8)+sa->s6_addr[13],
(sa->s6_addr[14]<<8)+sa->s6_addr[15]
#elif HAVE_IP6_SOCKADDR==1
ntohs(((unsigned short *)&sa->u6_addr.u6_addr16)[0]),
ntohs(((unsigned short *)&sa->u6_addr.u6_addr16)[1]),
ntohs(((unsigned short *)&sa->u6_addr.u6_addr16)[2]),
ntohs(((unsigned short *)&sa->u6_addr.u6_addr16)[3]),
ntohs(((unsigned short *)&sa->u6_addr.u6_addr16)[4]),
ntohs(((unsigned short *)&sa->u6_addr.u6_addr16)[5]),
ntohs(((unsigned short *)&sa->u6_addr.u6_addr16)[6]),
ntohs(((unsigned short *)&sa->u6_addr.u6_addr16)[7])
#elif HAVE_IP6_SOCKADDR==2
ntohs(((unsigned short *)&sa->u6_addr16)[0]),
ntohs(((unsigned short *)&sa->u6_addr16)[1]),
ntohs(((unsigned short *)&sa->u6_addr16)[2]),
ntohs(((unsigned short *)&sa->u6_addr16)[3]),
ntohs(((unsigned short *)&sa->u6_addr16)[4]),
ntohs(((unsigned short *)&sa->u6_addr16)[5]),
ntohs(((unsigned short *)&sa->u6_addr16)[6]),
ntohs(((unsigned short *)&sa->u6_addr16)[7])
#elif HAVE_IP6_SOCKADDR==3
ntohs(((unsigned short *)&sa->in6_u.u6_addr16)[0]),
ntohs(((unsigned short *)&sa->in6_u.u6_addr16)[1]),
ntohs(((unsigned short *)&sa->in6_u.u6_addr16)[2]),
ntohs(((unsigned short *)&sa->in6_u.u6_addr16)[3]),
ntohs(((unsigned short *)&sa->in6_u.u6_addr16)[4]),
ntohs(((unsigned short *)&sa->in6_u.u6_addr16)[5]),
ntohs(((unsigned short *)&sa->in6_u.u6_addr16)[6]),
ntohs(((unsigned short *)&sa->in6_u.u6_addr16)[7])
#elif HAVE_IP6_SOCKADDR==4
(sa->_S6_un._S6_u8[0]<<8)|(sa->_S6_un._S6_u8[1]&0xff),
(sa->_S6_un._S6_u8[2]<<8)|(sa->_S6_un._S6_u8[3]&0xff),
(sa->_S6_un._S6_u8[4]<<8)|(sa->_S6_un._S6_u8[5]&0xff),
(sa->_S6_un._S6_u8[6]<<8)|(sa->_S6_un._S6_u8[7]&0xff),
(sa->_S6_un._S6_u8[8]<<8)|(sa->_S6_un._S6_u8[9]&0xff),
(sa->_S6_un._S6_u8[10]<<8)|(sa->_S6_un._S6_u8[11]&0xff),
(sa->_S6_un._S6_u8[12]<<8)|(sa->_S6_un._S6_u8[13]&0xff),
(sa->_S6_un._S6_u8[14]<<8)|(sa->_S6_un._S6_u8[15]&0xff)
#elif HAVE_IP6_SOCKADDR==5
ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[0]),
ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[1]),
ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[2]),
ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[3]),
ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[4]),
ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[5]),
ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[6]),
ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[7])
#endif
) >= blen) {
Warn("sockaddr_inet6_info(): buffer too short");
buff[blen-1] = '\0';
}
return buff;
}
/* returns information that can be used for constructing an environment
variable describing the socket address.
if idx is 0, this function writes "ADDR" into namebuff and the IP address
into valuebuff, and returns 1 (which means that one more info is there).
if idx is 1, it writes "PORT" into namebuff and the port number into
valuebuff, and returns 0 (no more info)
namelen and valuelen contain the max. allowed length of output chars in the
respective buffer.
on error this function returns -1.
*/
int
xiosetsockaddrenv_ip6(int idx, char *namebuff, size_t namelen,
char *valuebuff, size_t valuelen,
struct sockaddr_in6 *sa, int ipproto) {
switch (idx) {
case 0:
strcpy(namebuff, "ADDR");
snprintf(valuebuff, valuelen, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
(sa->sin6_addr.s6_addr[0]<<8)+
sa->sin6_addr.s6_addr[1],
(sa->sin6_addr.s6_addr[2]<<8)+
sa->sin6_addr.s6_addr[3],
(sa->sin6_addr.s6_addr[4]<<8)+
sa->sin6_addr.s6_addr[5],
(sa->sin6_addr.s6_addr[6]<<8)+
sa->sin6_addr.s6_addr[7],
(sa->sin6_addr.s6_addr[8]<<8)+
sa->sin6_addr.s6_addr[9],
(sa->sin6_addr.s6_addr[10]<<8)+
sa->sin6_addr.s6_addr[11],
(sa->sin6_addr.s6_addr[12]<<8)+
sa->sin6_addr.s6_addr[13],
(sa->sin6_addr.s6_addr[14]<<8)+
sa->sin6_addr.s6_addr[15]);
switch (ipproto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
#ifdef IPPROTO_SCTP
case IPPROTO_SCTP:
#endif
return 1; /* there is port information to also be retrieved */
default:
return 0; /* no port info coming */
}
case 1:
strcpy(namebuff, "PORT");
snprintf(valuebuff, valuelen, "%u", ntohs(sa->sin6_port));
return 0;
}
return -1;
}
#if defined(HAVE_STRUCT_IPV6_MREQ)
int xioapply_ipv6_join_group(
struct single *sfd,
struct opt *opt)
{
struct ipv6_mreq ip6_mreq = {{{{0}}}};
union sockaddr_union sockaddr1;
socklen_t socklen1 = sizeof(sockaddr1.ip6);
int res;
/* Always two parameters */
/* First parameter is multicast address */
if ((res =
xioresolve(opt->value.u_string/*multiaddr*/, NULL,
sfd->para.socket.la.soa.sa_family,
SOCK_DGRAM, IPPROTO_IP,
&sockaddr1, &socklen1,
sfd->para.socket.ip.ai_flags))
!= STAT_OK) {
return res;
}
ip6_mreq.ipv6mr_multiaddr = sockaddr1.ip6.sin6_addr;
if (ifindex(opt->value2.u_string/*param2*/,
&ip6_mreq.ipv6mr_interface, -1)
< 0) {
Error1("interface \"%s\" not found",
opt->value2.u_string/*param2*/);
ip6_mreq.ipv6mr_interface = htonl(0);
}
if (Setsockopt(sfd->fd, opt->desc->major, opt->desc->minor,
&ip6_mreq, sizeof(ip6_mreq)) < 0) {
Error6("setsockopt(%d, %d, %d, {...,0x%08x}, "F_Zu"): %s",
sfd->fd, opt->desc->major, opt->desc->minor,
ip6_mreq.ipv6mr_interface,
sizeof(ip6_mreq),
strerror(errno));
opt->desc = ODESC_ERROR;
return -1;
}
return 0;
}
#endif /* defined(HAVE_STRUCT_IPV6_MREQ) */
#if HAVE_STRUCT_GROUP_SOURCE_REQ
int xiotype_ip6_join_source_group(
char *token, const struct optname *ent, struct opt *opt)
{
/* We do not resolve the addresses here because we do not yet know
if we are coping with an IPv4 or IPv6 socat address */
const char *ends[] = { ":", NULL };
const char *nests[] = { "[","]", NULL };
char buff[512], *buffp=buff; size_t bufspc = sizeof(buff)-1;
char *tokp = token;
int parsres;
/* Parse first IP address (mcast group), expect ':' */
parsres =
nestlex((const char **)&tokp, &buffp, &bufspc,
ends, NULL, NULL, nests,
true, false, false);
if (parsres < 0) {
Error1("option too long: \"%s\"", token);
return -1;
} else if (parsres > 0) {
Error1("syntax error in \"%s\"", token);
return -1;
}
if (*tokp != ':') {
Error1("syntax in option %s: missing ':'", token);
}
*buffp++ = '\0';
if ((opt->value.u_string/*mcaddr*/ = strdup(buff)) == NULL) {
int _errno = errno;
Error1("strdup(\"%s\"): out of memory", buff);
errno = _errno;
return -1;
}
++tokp;
/* Parse interface name/index, expect ':' or '\0'' */
buffp = buff;
parsres =
nestlex((const char **)&tokp, &buffp, &bufspc,
ends, NULL, NULL, nests,
true, false, false);
if (parsres < 0) {
Error1("option too long: \"%s\"", token);
return -1;
} else if (parsres > 0) {
Error1("syntax error in \"%s\"", token);
return -1;
}
if (*tokp != ':') {
Error1("syntax in option %s: missing ':'", token);
}
*buffp++ = '\0';
if ((opt->value2.u_string/*ifindex*/ = Malloc(IF_NAMESIZE)) == NULL) {
int _errno = errno;
free(opt->value.u_string);
errno = _errno;
return -1;
}
strncpy(opt->value2.u_string/*ifindex*/, buff, IF_NAMESIZE);
++tokp;
/* Parse second IP address (source address), expect ':' or '\0'' */
buffp = buff;
parsres =
nestlex((const char **)&tokp, &buffp, &bufspc,
ends, NULL, NULL, nests,
true, false, false);
if (parsres < 0) {
Error1("option too long: \"%s\"", token);
return -1;
} else if (parsres > 0) {
Error1("syntax error in \"%s\"", token);
return -1;
}
if (*tokp) {
Error1("syntax in option %s: trailing cruft", token);
}
*buffp++ = '\0';
if ((opt->value3.u_string/*srcaddr*/ = strdup(buff)) == NULL) {
int _errno = errno;
Error1("strdup(\"%s\"): out of memory", buff);
free(opt->value.u_string);
errno = _errno;
return -1;
}
Info4("setting option \"%s\" to {\"%s\",\"%s\",\"%s\"}",
ent->desc->defname,
opt->value.u_string/*mcaddr*/,
opt->value2.u_string/*ifindex*/,
opt->value3.u_string/*srcaddr*/);
if (!xioparms.experimental) {
Warn1("option %s is experimental", opt->desc->defname);
}
return 0;
}
int xioapply_ip6_join_source_group(struct single *sfd, struct opt *opt) {
struct group_source_req ip6_gsr = {0};
union sockaddr_union sockaddr1;
socklen_t socklen1 = sizeof(sockaddr1.ip6);
union sockaddr_union sockaddr2;
socklen_t socklen2 = sizeof(sockaddr2.ip6);
int res;
/* First parameter is always multicast address */
if ((res =
xioresolve(opt->value.u_string/*mcaddr*/, NULL,
sfd->para.socket.la.soa.sa_family,
SOCK_DGRAM, IPPROTO_IP, &sockaddr1, &socklen1,
sfd->para.socket.ip.ai_flags))
!= STAT_OK) {
return res;
}
memcpy(&ip6_gsr.gsr_group, &sockaddr1.ip6, socklen1);
/* Second parameter is interface name/index */
if (ifindex(opt->value2.u_string/*ifindex*/,
&ip6_gsr.gsr_interface, -1)
< 0) {
Error1("interface \"%s\" not found",
opt->value.u_string/*ifindex*/);
ip6_gsr.gsr_interface = 0;
}
/* Third parameter is source address */
if ((res =
xioresolve(opt->value3.u_string/*srcaddr*/, NULL,
sfd->para.socket.la.soa.sa_family,
SOCK_DGRAM, IPPROTO_IP, &sockaddr2, &socklen2,
sfd->para.socket.ip.ai_flags))
!= STAT_OK) {
return res;
}
memcpy(&ip6_gsr.gsr_source, &sockaddr2.ip6, socklen2);
if (Setsockopt(sfd->fd, opt->desc->major, opt->desc->minor,
&ip6_gsr, sizeof(ip6_gsr)) < 0) {
Error6("setsockopt(%d, %d, %d, {%d,...}, "F_Zu"): %s",
sfd->fd, opt->desc->major, opt->desc->minor,
ip6_gsr.gsr_interface,
sizeof(ip6_gsr),
strerror(errno));
opt->desc = ODESC_ERROR;
return -1;
}
return 0;
}
#endif /* HAVE_STRUCT_GROUP_SOURCE_REQ */
#endif /* WITH_IP6 */

54
xio-ip6.h Normal file
View File

@@ -0,0 +1,54 @@
/* source: xio-ip6.h */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_ip6_h_included
#define __xio_ip6_h_included 1
#if WITH_IP6
#ifndef INET6_ADDRSTRLEN
# define INET6_ADDRSTRLEN 46
#endif
extern const struct optdesc opt_ipv6_v6only;
extern const struct optdesc opt_ipv6_join_group;
extern const struct optdesc opt_ipv6_join_source_group;
extern const struct optdesc opt_ipv6_pktinfo;
extern const struct optdesc opt_ipv6_recvpktinfo;
extern const struct optdesc opt_ipv6_rthdr;
extern const struct optdesc opt_ipv6_recvrthdr;
extern const struct optdesc opt_ipv6_authhdr;
extern const struct optdesc opt_ipv6_dstopts;
extern const struct optdesc opt_ipv6_recvdstopts;
extern const struct optdesc opt_ipv6_hopopts;
extern const struct optdesc opt_ipv6_unicast_hops;
extern const struct optdesc opt_ipv6_recvhopopts;
extern const struct optdesc opt_ipv6_flowinfo;
extern const struct optdesc opt_ipv6_hoplimit;
extern const struct optdesc opt_ipv6_recvhoplimit;
extern const struct optdesc opt_ipv6_recverr;
extern const struct optdesc opt_ipv6_tclass;
extern const struct optdesc opt_ipv6_recvtclass;
extern const struct optdesc opt_ipv6_recvpathmtu;
extern int xioip6_pton(const char *src, struct in6_addr *dst, const int ai_flags[2]);
extern int xioparsenetwork_ip6(const char *rangename, struct xiorange *range, const int ai_flags[2]);
extern int xiorange_ip6andmask(struct xiorange *range);
extern
int xiocheckrange_ip6(struct sockaddr_in6 *pa, struct xiorange *range);
extern
int xiolog_ancillary_ip6(struct single *sfd, struct cmsghdr *cmsg, int *num, char *typbuff, int typlen, char *nambuff, int namlen, char *envbuff, int envlen, char *valbuff, int vallen);
extern int
xiosetsockaddrenv_ip6(int idx, char *namebuff, size_t namelen,
char *valuebuff, size_t valuelen,
struct sockaddr_in6 *sa, int ipproto);
extern int xioapply_ipv6_join_group(xiosingle_t *xfd, struct opt *opt);
extern int xiotype_ip6_join_source_group(char* token, const struct optname *ent, struct opt *opt);
extern int xioapply_ip6_join_source_group(struct single *xfd, struct opt *opt);
#endif /* WITH_IP6 */
#endif /* !defined(__xio_ip6_h_included) */

Some files were not shown because too many files have changed in this diff Show More