merged features ancillary, envvar

This commit is contained in:
Gerhard Rieger 2008-09-22 22:17:55 +02:00
parent bd3810642b
commit 2ffe5a324e
42 changed files with 1898 additions and 287 deletions

33
CHANGES
View file

@ -3,6 +3,34 @@ new features:
new address option "escape" allows to break a socat instance even when
raw terminal mode prevents ^C etc.
socat sets environment variables SOCAT_VERSION, SOCAT_PID, SOCAT_PPID
for use in executed scripts
socat sets environment variables SOCAT_SOCKADDR, SOCAT_SOCKPORT,
SOCAT_PEERADDR, SOCAT_PEERPORT in LISTEN type addresses (feature
suggested by Ed Sawicki)
socat receives all ancillary messages with each received packet on
datagram related addresses. The messages are logged in raw form with
debug level, and broken down with info level. note: each type of
ancillary message must be enabled by appropriate address options.
socat provides the contents of ancillary messages received on RECVFROM
addresses in appropriate environment variables:
SOCAT_IP_PKTINFO_DSTADDR, SOCAT_IP_PKTINFO_IF, SOCAT_IP_PKTINFO_LOCADDR
(not on BSD); SOCAT_IP_RECVDSTADDR, SOCAT_IP_RECVIF (BSD);
SOCAT_SCM_TIMESTAMP, SOCAT_IP_OPTIONS, SOCAT_IP_TOS, SOCAT_IP_TTL,
SOCAT_IPV6_HOPLIMIT, SOCAT_IPV6_TCLASS, SOCAT_IPV6_PKTINFO_DSTADDR
the following address options were added to enable ancillary messages:
so-timestamp, ip-pktinfo, ip-recvdstaddr, ip-recverr, ip-recvif,
ip-recvopts, ip-recvtos, ip-recvttl, ipv6-recvdstopts, ipv6-recverr,
ipv6-recvhoplimit, ipv6-recvhopopts, ipv6-recvpathmtu,
ipv6-recvpktinfo, ipv6-recvrthdr, ipv6-recvtclass
new address options ipv6-tclass and ipv6-unicast-hops set the related
socket options.
corrections:
some raw IP and UNIX datagram modes failed on BSD systems
@ -13,9 +41,10 @@ corrections:
there was a bug in ip*-recv with bind option: it did not bind, and
with the first received packet an error occurred:
socket_init(): unknown address family 0
test: RAWIP4RECVBIND
RECVFROM addresses with FORK option hung after processing the first
packet.
packet. test: UDP4RECVFROM_FORK
corrected a few mistakes that caused compiler warnings on 64bit hosts
@ -24,7 +53,7 @@ corrections:
when the EXEC address got a string with consecutive spaces it created
additional empty arguments (thanks to Olivier Hervieu for reporting
this bug)
this bug). test: EXECSPACES
in ignoreeof polling mode socat also blocked data transfer in the other
direction during the 1s wait intervalls (thanks to Jorgen Cederlof for

12
README
View file

@ -180,10 +180,22 @@ 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
strutc 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 other socket. This makes problems with the exec and
system addresses.

View file

@ -1 +1 @@
"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock+escape"
"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock+escape+timestamp+ancillary+envvar"

View file

@ -224,6 +224,15 @@
/* 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
@ -334,6 +343,9 @@
/* 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 your struct ip has ip_hl; otherwise assume ip_vhl */
#undef HAVE_STRUCT_IP_IP_HL

View file

@ -64,6 +64,8 @@ AC_CHECK_HEADERS(arpa/nameser.h)
AC_HEADER_RESOLV()
AC_CHECK_HEADERS(termios.h linux/if_tun.h)
AC_CHECK_HEADERS(net/if_dl.h)
AC_CHECK_HEADERS(linux/types.h linux/errqueue.h)
AC_CHECK_HEADERS(sys/utsname.h sys/select.h sys/file.h)
AC_CHECK_HEADERS(util.h libutil.h sys/stropts.h regex.h)
AC_CHECK_HEADERS(linux/fs.h linux/ext2_fs.h)
@ -1044,6 +1046,19 @@ if test $sc_cv_struct_msghdr_msgflags = yes; then
fi
AC_MSG_RESULT($sc_cv_struct_msghdr_msgflags)
dnl check for struct cmsghdr
AC_MSG_CHECKING(for struct cmsghdr)
AC_CACHE_VAL(sc_cv_struct_cmsghdr,
[AC_TRY_COMPILE([#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>],[struct cmsghdr s;],
[sc_cv_struct_cmsghdr=yes],
[sc_cv_struct_cmsghdr=no])])
if test $sc_cv_struct_cmsghdr = yes; then
AC_DEFINE(HAVE_STRUCT_CMSGHDR)
fi
AC_MSG_RESULT($sc_cv_struct_cmsghdr)
dnl check for ip_hl in struct ip
AC_MSG_CHECKING(for struct ip.ip_hl)
AC_CACHE_VAL(sc_cv_struct_ip_ip_hl,

View file

@ -240,8 +240,7 @@ interfaces. This membership cannot be dropped on Linux.
sockets without exception accept packets that are directly addressed to them;
the multi- and broadcast receiving features are just extensions to the normal
functionality. socat has no way to find out if an incoming packet is addressed
to a unicast, multicast or broadcast address. Please contact the author if you
know how the target address can be determined.</p>
to a unicast, multicast, or broadcast address.</p>
<p>Authentication or encryption are not available.</p>

View file

@ -127,7 +127,8 @@ dit(bf(tt(-lf))tt( <logfile>))
dit(bf(tt(-ls)))
Writes messages to stderr (this is the default).
label(option_lp)dit(bf(tt(-lp))tt(<progname>))
Overrides the program name printed in error messages.
Overrides the program name printed in error messages and used for
constructing environment variable names.
dit(bf(tt(-lu)))
Extends the timestamp of error messages to microsecond resolution. Does not
work when logging to syslog.
@ -364,6 +365,7 @@ label(ADDRESS_IP_DATAGRAM)dit(bf(tt(IP-DATAGRAM:<address>:<protocol>)))
Option groups: link(FD)(GROUP_FD), link(SOCKET)(GROUP_SOCKET),
link(IP4)(GROUP_IP4), link(IP6)(GROUP_IP6), link(RANGE)(GROUP_RANGE) nl()
Useful options:
link(bind)(OPTION_BIND),
link(range)(OPTION_RANGE),
link(tcpwrap)(OPTION_TCPWRAPPERS),
link(broadcast)(OPTION_SO_BROADCAST),
@ -373,7 +375,6 @@ label(ADDRESS_IP_DATAGRAM)dit(bf(tt(IP-DATAGRAM:<address>:<protocol>)))
link(ip-add-membership)(OPTION_IP_ADD_MEMBERSHIP),
link(ttl)(OPTION_TTL),
link(tos)(OPTION_TOS),
link(bind)(OPTION_BIND),
link(pf)(OPTION_PROTOCOL_FAMILY)nl()
See also:
link(IP4-DATAGRAM)(ADDRESS_IP4_DATAGRAM),
@ -783,7 +784,8 @@ label(ADDRESS_UDP_DATAGRAM)dit(bf(tt(UDP-DATAGRAM:<address>:<port>)))
options. This address type can for example be used for implementing
symmetric or asymmetric broadcast or multicast communications.nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(RANGE)(GROUP_RANGE) nl()
Useful options:
Useful options:
link(bind)(OPTION_BIND),
link(range)(OPTION_RANGE),
link(tcpwrap)(OPTION_TCPWRAPPERS),
link(broadcast)(OPTION_SO_BROADCAST),
@ -793,7 +795,6 @@ label(ADDRESS_UDP_DATAGRAM)dit(bf(tt(UDP-DATAGRAM:<address>:<port>)))
link(ip-add-membership)(OPTION_IP_ADD_MEMBERSHIP),
link(ttl)(OPTION_TTL),
link(tos)(OPTION_TOS),
link(bind)(OPTION_BIND),
link(sourceport)(OPTION_SOURCEPORT),
link(pf)(OPTION_PROTOCOL_FAMILY)nl()
See also:
@ -1543,8 +1544,8 @@ label(OPTION_INTERFACE)dit(bf(tt(interface=<interface>)))
label(OPTION_SO_BROADCAST)dit(bf(tt(broadcast)))
For datagram sockets, allows sending to broadcast addresses and receiving
packets addressed to broadcast addresses.
label(OPTION_BSDCOMPAT)dit(bf(tt(bsdcompat)))
Emulates some (old?) bugs of the BSD socket implementation.
COMMENT(label(OPTION_BSDCOMPAT)dit(bf(tt(bsdcompat)))
Emulates some (old?) bugs of the BSD socket implementation.)
label(OPTION_DEBUG)dit(bf(tt(debug)))
Enables socket debugging.
label(OPTION_DONTROUTE)dit(bf(tt(dontroute)))
@ -1639,6 +1640,9 @@ COMMENT(label(OPTION_USEIFBUFS)dit(bf(tt(useifbufs)))
label(OPTION_PROTOCOL_FAMILY)dit(bf(tt(pf=<string>)))
Forces the use of the specified IP version. <string> can be
something like "ip4" or "ip6".
label(OPTION_SO_TIMESTAMP)dit(bf(tt(so-timestamp)))
Sets the SO_TIMESTAMP socket option. This enables receiving and logging of
timestamp ancillary messages.
enddit()
startdit()enddit()nl()
@ -1665,13 +1669,13 @@ label(OPTION_TOS)dit(bf(tt(tos=<tos>)))
label(OPTION_TTL)dit(bf(tt(ttl=<ttl>)))
Sets the TTL (time to live) field of outgoing packets to <ttl>
[link(byte)(TYPE_BYTE)].
label(OPTION_IPOPTIONS)dit(bf(tt(ipoptions=<data>)))
label(OPTION_IPOPTIONS)dit(bf(tt(ip-options=<data>)))
Sets IP options like source routing. Must be given in binary form,
recommended format is a leading "x" followed by an even number of hex
digits. This option may be used multiple times, data are appended.
E.g., to connect to host 10.0.0.1 via some gateway using a loose source
route, use the gateway as address parameter and set a loose source route
using the option code(ipoptions=x8307040a000001).nl()
using the option code(ip-options=x8307040a000001).nl()
IP options are defined in RFC 791. COMMENT(, RFC 2113)nl()
COMMENT( x00 end of option list
x01 no operation (nop)
@ -1690,20 +1694,32 @@ COMMENT(label(OPTION_IP_MULTICAST_LOOP)dit(bf(tt(multicastloop)))
Allow looping back outgoing multicast to the local interface.)
COMMENT(label(OPTION_IP_MULTICAST_TTL)dit(bf(tt(multicastttl)))
Set the TTL for outgoing multicast packets.)
COMMENT(label(OPTION_PKTINFO)dit(bf(tt(pktinfo)))
Set the IP_PKTINFO socket option.)
label(OPTION_IP_PKTINFO)dit(bf(tt(pktinfo)))
Sets the IP_PKTINFO socket option. This enables receiving and logging of
ancillary messages containing destination address and interface (Linux).
COMMENT(label(OPTION_PKTOPTS)dit(bf(tt(pktopts)))
Set the IP_PKTOPTIONS socket option.)
COMMENT(label(OPTION_RECVERR)dit(bf(tt(recverr)))
Set the IP_RECVERR socket option.)
COMMENT(label(OPTION_RECVOPTS)dit(bf(tt(recvopts)))
Set the IP_RECVOPTS socket option.)
COMMENT(label(OPTION_RECVTOS)dit(bf(tt(recvtos)))
Set the IP_RECVTOS socket option.)
COMMENT(label(OPTION_RECVTTL)dit(bf(tt(recvttl)))
Set the IP_RECVTTL socket option.)
label(OPTION_IP_RECVERR)dit(bf(tt(recverr)))
Sets the IP_RECVERR socket option. This enables receiving and logging of
ancillary messages containing detailled error information.
label(OPTION_IP_RECVOPTS)dit(bf(tt(recvopts)))
Sets the IP_RECVOPTS socket option. This enables receiving and logging of IP
options ancillary messages (Linux, *BSD).
label(OPTION_IP_RECVTOS)dit(bf(tt(recvtos)))
Sets the IP_RECVTOS socket option. This enables receiving and logging of TOS
(type of service) ancillary messages (Linux).
label(OPTION_IP_RECVTTL)dit(bf(tt(recvttl)))
Sets the IP_RECVTTL socket option. This enables receiving and logging of TTL
(time to live) ancillary messages (Linux, *BSD).
COMMENT(label(OPTION_RETOPTS)dit(bf(tt(retopts)))
Set the IP_RETOPTS socket option.)
label(OPTION_IP_RECVDSTADDR)dit(bf(tt(recvdstaddr)))
Sets the IP_RECVDSTADDR socket option. This enables receiving and logging of
ancillary messages containing destination address
(*BSD).
label(OPTION_IP_RECVIF)dit(bf(tt(recvif)))
Sets the IP_RECVIF socket option. This enables receiving and logging of
interface ancillary messages (*BSD).
COMMENT(label(OPTION_ROUTERALERT)dit(bf(tt(routeralert)))
Set the IP_ROUTER_ALERT socket option.)
label(OPTION_IP_ADD_MEMBERSHIP)
@ -1758,6 +1774,30 @@ label(OPTION_IPV6_V6ONLY)dit(bf(tt(ipv6only=<bool>)))
Sets the IPV6_V6ONLY socket option. If 0, the TCP stack will also accept
connections using IPv4 protocol on the same port. The default is system
dependent.
label(OPTION_IPV6_RECVDSTOPTS)dit(bf(tt(ipv6-recvdstopts)))
Sets the IPV6_RECVDSTOPTS socket option. This enables receiving and logging
of ancillary messages containing the destination options.
label(OPTION_IPV6_RECVHOPLIMIT)dit(bf(tt(ipv6-recvhoplimit)))
Sets the IPV6_RECVHOPLIMIT socket option. This enables receiving and logging
of ancillary messages containing the hoplimit.
label(OPTION_IPV6_RECVHOPOPTS)dit(bf(tt(ipv6-recvhopopts)))
Sets the IPV6_RECVHOPOPTS socket option. This enables receiving and logging
of ancillary messages containing the hop options.
label(OPTION_IPV6_RECVPKTINFO)dit(bf(tt(ipv6-recvpktinfo)))
Sets the IPV6_RECVPKTINFO socket option. This enables receiving and logging
of ancillary messages containing destination address and interface.
label(OPTION_IPV6_UNICAST_HOPS)dit(bf(tt(ipv6-unicast-hops=link(TYPE_INT)(<int>))))
Sets the IPV6_UNICAST_HOPS socket option. This sets the hop count limit
(TTL) for outgoing unicast packets.
label(OPTION_IPV6_RECVRTHDR)dit(bf(tt(ipv6-recvrthdr)))
Sets the IPV6_RECVRTHDR socket option. This enables receiving and logging
of ancillary messages containing routing information.
label(OPTION_IPV6_TCLASS)dit(bf(tt(ipv6-tclass)))
Sets the IPV6_TCLASS socket option. This sets the transfer class of outgoing
packets.
label(OPTION_IPV6_RECVTCLASS)dit(bf(tt(ipv6-recvtclass)))
Sets the IPV6_RECVTCLASS socket option. This enables receiving and logging
of ancillary messages containing the transfer class.
enddit()
startdit()enddit()nl()
@ -2932,45 +2972,126 @@ manpagefiles()
label(ENVIRONMENT_VARIABLES)
manpagesection(ENVIRONMENT VARIABLES)
Input variables carry information from the environment to socat, output
variables are set by socat for use in executed scripts and programs.
In the output variables beginning with "SOCAT" this prefix is actually replaced
by the upper case name of the executable or the value of option
link(-lp)(option_lp).
startdit()
dit(bf(SOCAT_DEFAULT_LISTEN_IP)) (Values 4 or 6) Sets the IP version to be used
dit(bf(SOCAT_DEFAULT_LISTEN_IP) (input)) (Values 4 or 6) Sets the IP version to
be used
for listen, recv, and recvfrom addresses if no link(pf)(OPTION_PROTOCOL_FAMILY)
(protocol-family) option is given. Is overridden by socat options
link(-4)(option_4) or link(-6)(option_6).
dit(bf(SOCAT_PREFERRED_RESOLVE_IP)) (Values 0, 4, or 6) Sets the IP version to
dit(bf(SOCAT_PREFERRED_RESOLVE_IP) (input)) (Values 0, 4, or 6) Sets the IP
version to
be used when resolving target host names when version is not specified by
address type, option link(pf)(OPTION_PROTOCOL_FAMILY) (protocol-family), or
address format. If name resolution does not return a matching entry, the first
result (with differing IP version) is taken. With value 0, socat always selects
the first record and its IP version.
dit(bf(SOCAT_FORK_WAIT)) Specifies the time (seconds) to sleep the parent and
child processes after successful fork(). Useful for debugging.
dit(bf(SOCAT_FORK_WAIT) (input)) Specifies the time (seconds) to sleep the
parent and child processes after successful fork(). Useful for debugging.
dit(bf(HOSTNAME)) Is used to determine the hostname for logging (see
dit(bf(SOCAT_VERSION) (output)) Socat sets this variable to its version string,
e.g. tt("1.6.1.0") for released versions or e.g. tt("1.6.0.1+envvar") for
temporary versions; can be used in scripts invoked by socat.
dit(bf(SOCAT_PID) (output)) Socat sets this variable to its process id. In case
of link(fork)(OPTION_FORK) address option, SOCAT_PID gets the child processes
id. Forking for link(exec)(ADDRESS_EXEC) and link(system)(ADDRESS_SYSTEM) does
not change SOCAT_PID.
dit(bf(SOCAT_PPID) (output)) Socat sets this variable to its process id. In
case of link(fork)(OPTION_FORK), SOCAT_PPID keeps the pid of the master process.
dit(bf(SOCAT_PEERADDR) (output)) With passive socket addresses (all LISTEN and
RECVFROM addresses), this variable is set to a string describing the peers
socket address. Port information is not included.
dit(bf(SOCAT_PEERPORT) (output)) With appropriate passive socket addresses (TCP
and UDP - LISTEN and RECVFROM), this variable is set to a string containing the
number of the peer port.
dit(bf(SOCAT_SOCKADDR) (output)) With all LISTEN addresses, this variable is
set to a string describing the local socket address. Port information is not
included.
dit(bf(SOCAT_SOCKPORT) (output)) With TCP-LISTEN and UDP-LISTEN addresses, this
variable is set to the local port.
dit(bf(SOCAT_TIMESTAMP) (output)) With all RECVFROM addresses where address
option link(so-timestamp)(OPTION_SO_TIMESTAMP) is applied, socat sets this
variable to the resulting timestamp.
dit(bf(SOCAT_IP_OPTIONS) (output)) With all IPv4 based RECVFROM addresses where
address option link(ip-recvopts)(OPTION_IP_RECVOPTS) is applied, socat fills
this variable with the IP options of the received packet.
dit(bf(SOCAT_IP_DSTADDR) (output)) With all IPv4 based RECVFROM addresses where
address option link(ip-recvdstaddr)(OPTION_IP_RECVDSTADDR) (BSD) or
link(ip-pktinfo)(OPTION_IP_PKTINFO) (other platforms) is applied, socat sets
this variable to the destination address of the received packet. This is
particularly useful to identify broadcast and multicast addressed packets.
dit(bf(SOCAT_IP_IF) (output)) With all IPv4 based RECVFROM addresses where
address option link(ip-recvif)(OPTION_IP_RECVIF) (BSD) or
link(ip-pktinfo)(OPTION_IP_PKTINFO) (other platforms) is applied, socat sets
this variable to the name of the interface where the packet was received.
dit(bf(SOCAT_IP_LOCADDR) (output)) With all IPv4 based RECVFROM
addresses where address option link(ip-pktinfo)(OPTION_IP_PKTINFO) is applied,
socat sets this variable to the address of the interface where the packet was
received.
dit(bf(SOCAT_IP_TOS) (output)) With all IPv4 based RECVFROM addresses where
address option link(ip-recvtos)(OPTION_IP_RECVTOS) is applied, socat sets this
variable to the TOS (type of service) of the received packet.
dit(bf(SOCAT_IP_TTL) (output)) With all IPv4 based RECVFROM addresses where
address option link(ip-recvttl)(OPTION_IP_RECVTTL) is applied, socat sets this
variable to the TTL (time to live) of the received packet.
dit(bf(SOCAT_IPV6_HOPLIMIT) (output)) With all IPv6 based RECVFROM addresses
where address option link(ipv6-recvhoplimit)(OPTION_IPV6_RECVHOPLIMIT) is
applied, socat sets this variable to the hoplimit value of the received packet.
dit(bf(SOCAT_IPV6_DSTADDR) (output)) With all IPv6 based RECVFROM
addresses where address option link(ipv6-recvpktinfo)(OPTION_IPV6_RECVPKTINFO)
is applied, socat sets this variable to the destination address of the received
packet.
dit(bf(SOCAT_IPV6_TCLASS) (output)) With all IPv6 based RECVFROM addresses
where address option link(ipv6-recvtclass)(OPTION_IPV6_RECVTCLASS) is applied,
socat sets this variable to the transfer class of the received packet.
dit(bf(HOSTNAME) (input)) Is used to determine the hostname for logging (see
link(-lh)(option_lh)).
dit(bf(LOGNAME)) Is used as name for the socks client user name if no
dit(bf(LOGNAME) (input)) Is used as name for the socks client user name if no
link(socksuser)(OPTION_SOCKSUSER) is given.nl()
With options link(su)(OPTION_SUBSTUSER) and
link(su-d)(OPTION_SUBSTUSER_DELAYED), LOGNAME is set to the given user name.
dit(bf(USER)) Is used as name for the socks client user name if no
dit(bf(USER) (input)) Is used as name for the socks client user name if no
link(socksuser)(OPTION_SOCKSUSER) is given and LOGNAME is empty.nl()
With options link(su)(OPTION_SUBSTUSER) and
link(su-d)(OPTION_SUBSTUSER_DELAYED), USER is set to the given user name.
dit(bf(SHELL))
dit(bf(SHELL) (output))
With options link(su)(OPTION_SUBSTUSER) and
link(su-d)(OPTION_SUBSTUSER_DELAYED), SHELL is set to the login shell of the
given user.
dit(bf(PATH))
dit(bf(PATH) (output))
Can be set with option link(path)(OPTION_PATH) for link(exec)(ADDRESS_EXEC) and
link(system)(ADDRESS_SYSTEM) addresses.
dit(bf(HOME))
dit(bf(HOME) (output))
With options link(su)(OPTION_SUBSTUSER) and
link(su-d)(OPTION_SUBSTUSER_DELAYED), HOME is set to the home directory of the
given user.

View file

@ -30,12 +30,11 @@ int hostan(FILE *outfile) {
#if WITH_SOCKET
static int iffan(FILE *outfile) {
/* Linux: man 7 netdevice */
/* FreeBSD: man 4 networking */
/* FreeBSD, NetBSD: man 4 networking */
/* Solaris: man 7 if_tcp */
/* currently we support Linux and a little FreeBSD */
#ifdef SIOCGIFCONF /* not Solaris */
#ifdef SIOCGIFINDEX /* not OpenBSD */
#define IFBUFSIZ 32*sizeof(struct ifreq) /*1024*/
int s;
@ -62,22 +61,24 @@ static int iffan(FILE *outfile) {
struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i);
struct ifreq ifr;
#if 0 || defined(SIOCGIFINDEX) /* not NetBSD, OpenBSD */
strcpy(ifr.ifr_name, ifp->ifr_name);
if (Ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
Error3("ioctl(%d, SIOCGIFINDEX, {\"%s\"}): %s",
s, &ifr.ifr_name, strerror(errno));
return 1;
}
/*fprintf(outfile, "%2d: %s\n", ifr.ifr_ifindex, ifp->ifr_ifrn.ifrn_name);*/
#if HAVE_STRUCT_IFREQ_IFR_INDEX
fprintf(outfile, "%2d: %s\n", ifr.ifr_index, ifp->ifr_name);
#elif HAVE_STRUCT_IFREQ_IFR_IFINDEX
fprintf(outfile, "%2d: %s\n", ifr.ifr_ifindex, ifp->ifr_name);
#endif /* HAVE_STRUCT_IFREQ_IFR_INDEX */
#else /* !defined(SIOCGIFINDEX) */
fprintf(outfile, "%2d: %s\n", i/sizeof(struct ifreq), ifp->ifr_name);
#endif /* defined(SIOCGIFINDEX) */
}
Close(s);
#endif /* defined(SIOCGIFCONF) */
#endif /* defined(SIOCGIFINDEX) */
return 0;
}
#endif /* WITH_SOCKET */

View file

@ -267,12 +267,14 @@ int main(int argc, const char *argv[]) {
Error("-U and -u must not be combined");
}
xioinitialize2();
Info(copyright_socat);
#if WITH_OPENSSL
Info(copyright_openssl);
Info(copyright_ssleay);
#endif
Debug2("socat version %s on %s", socatversion, timestamp);
xiosetenv("VERSION", socatversion, 1); /* SOCAT_VERSION */
uname(&ubuf); /* ! here we circumvent internal tracing (Uname) */
Debug4("running on %s version %s, release %s, machine %s\n",
ubuf.sysname, ubuf.version, ubuf.release, ubuf.machine);

31
sycls.c
View file

@ -1,5 +1,5 @@
/* source: sycls.c */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* 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
@ -1055,11 +1055,14 @@ int Recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from,
int Recvmsg(int s, struct msghdr *msgh, int flags) {
int retval, _errno;
char infobuff[256];
Debug3("recvmsg(%d, %p, %d)", s, msgh, flags);
Debug10("recvmsg(%d, %p{%p,%u,%p,%u,%p,%u,%d}, %d)", s, msgh,
msgh->msg_name, msgh->msg_namelen, msgh->msg_iov, msgh->msg_iovlen,
msgh->msg_control, msgh->msg_controllen, msgh->msg_flags, flags);
retval = recvmsg(s, msgh, flags);
_errno = errno;
Debug2("recvmsg(, {%s}, ) -> %d",
Debug5("recvmsg(, {%s,%u,,%u,,%u,}, ) -> %d",
msgh->msg_name?sockaddr_info(msgh->msg_name, msgh->msg_namelen, infobuff, sizeof(infobuff)):"NULL",
msgh->msg_namelen, msgh->msg_iovlen, msgh->msg_controllen,
retval);
errno = _errno;
return retval;
@ -1419,6 +1422,28 @@ int Mkstemp(char *template) {
return result;
}
int Setenv(const char *name, const char *value, int overwrite) {
int result, _errno;
Debug3("setenv(\"%s\", \"%s\", %d)", name, value, overwrite);
result = setenv(name, value, overwrite);
_errno = errno;
Debug1("setenv() -> %d", result);
errno = _errno;
return result;
}
/* on Linux it returns int but on FreeBSD void.
we do not expect many errors, so we take void which works on all systems. */
void Unsetenv(const char *name) {
int _errno;
Debug1("unsetenv(\"%s\")", name);
unsetenv(name);
_errno = errno;
Debug("unsetenv() ->");
errno = _errno;
return;
}
#if WITH_READLINE
char *Readline(const char *prompt) {

View file

@ -1,5 +1,5 @@
/* source: sycls.h */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __sycls_h_included
@ -137,6 +137,8 @@ int Atexit(void (*func)(void));
void Exit(int status);
void Abort(void);
int Mkstemp(char *template);
int Setenv(const char *name, const char *value, int overwrite);
void Unsetenv(const char *name);
char *Readline(const char *prompt);
void Using_history(void);
@ -256,6 +258,8 @@ void Add_history(const char *string);
#define Exit(s) exit(s)
#define Abort() abort()
#define Mkstemp(t) mkstemp(t)
#define Setenv(n,v,o) setenv(n,v,o)
#define Unsetenv(n) unsetenv(n)
#define Readline(p) readline(p)
#define Using_history() using_history()

View file

@ -1,5 +1,5 @@
/* source: sysincludes.h */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __sysincludes_h_included
@ -108,6 +108,9 @@
#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
@ -116,6 +119,12 @@
#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_TUN_H
#include <linux/if_tun.h>
#endif

View file

@ -129,60 +129,48 @@ socklen_t socket_init(int af, union sockaddr_union *sa) {
#if _WITH_SOCKET
char *sockaddr_info(const struct sockaddr *sa, socklen_t salen, char *buff, size_t blen) {
char ubuff[5*UNIX_PATH_MAX+3];
union sockaddr_union *sau = (union sockaddr_union *)sa;
char *lbuff = buff;
char *cp = lbuff;
int n;
if ((n = snprintf(cp, blen, "AF=%d ", sa->sa_family)) < 0) {
if ((n = snprintf(cp, blen, "AF=%d ", sau->soa.sa_family)) < 0) {
Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen);
*buff = '\0';
return buff;
}
cp += n, blen -= n;
switch (sa->sa_family) {
switch (sau->soa.sa_family) {
#if WITH_UNIX
case 0:
case AF_UNIX:
#if WITH_ABSTRACT_UNIXSOCKET
if (salen > XIOUNIXSOCKOVERHEAD &&
sa->sa_data[0] == '\0') {
char *nextc;
nextc =
sanitize_string((char *)&sa->sa_data, salen-XIOUNIXSOCKOVERHEAD,
ubuff, XIOSAN_DEFAULT_BACKSLASH_OCT_3);
*nextc = '\0';
snprintf(cp, blen, "\"%s\"", ubuff);
} else
#endif /* WITH_ABSTRACT_UNIXSOCKET */
{
char *nextc;
nextc =
sanitize_string((char *)&sa->sa_data,
MIN(UNIX_PATH_MAX, strlen((char *)&sa->sa_data)),
ubuff, XIOSAN_DEFAULT_BACKSLASH_OCT_3);
*nextc = '\0';
snprintf(cp, blen, "\"%s\"", ubuff);
}
case AF_UNIX: sockaddr_unix_info(&sau->un, salen, cp+1, blen-1);
cp[0] = '"';
*strchr(cp+1, '\0') = '"';
break;
#endif
#if WITH_IP4
case AF_INET: sockaddr_inet4_info((struct sockaddr_in *)sa, cp, blen);
case AF_INET: sockaddr_inet4_info(&sau->ip4, cp, blen);
break;
#endif
#if WITH_IP6
case AF_INET6: sockaddr_inet6_info((struct sockaddr_in6 *)sa, cp, blen);
case AF_INET6: sockaddr_inet6_info(&sau->ip6, cp, blen);
break;
#endif
default:
if ((n = snprintf(cp, blen, "AF=%d ", sa->sa_family)) < 0) {
Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen);
*buff = '\0';
return buff;
}
cp += n, blen -= n;
if ((snprintf(cp, blen,
"0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
sa->sa_data[0], sa->sa_data[1], sa->sa_data[2],
sa->sa_data[3], sa->sa_data[4], sa->sa_data[5],
sa->sa_data[6], sa->sa_data[7], sa->sa_data[8],
sa->sa_data[9], sa->sa_data[10], sa->sa_data[11],
sa->sa_data[12], sa->sa_data[13])) < 0) {
sau->soa.sa_data[0], sau->soa.sa_data[1], sau->soa.sa_data[2],
sau->soa.sa_data[3], sau->soa.sa_data[4], sau->soa.sa_data[5],
sau->soa.sa_data[6], sau->soa.sa_data[7], sau->soa.sa_data[8],
sau->soa.sa_data[9], sau->soa.sa_data[10], sau->soa.sa_data[11],
sau->soa.sa_data[12], sau->soa.sa_data[13])) < 0) {
Warn("sockaddr_info(): buffer too short");
*buff = '\0';
return buff;
@ -195,10 +183,26 @@ char *sockaddr_info(const struct sockaddr *sa, socklen_t salen, char *buff, size
#if WITH_UNIX
char *sockaddr_unix_info(const struct sockaddr_un *sa, socklen_t salen, char *buff, size_t blen) {
blen = Min(blen, sizeof(sa->sun_path));
strncpy(buff, sa->sun_path, blen);
if (strlen(buff) >= blen) {
buff[blen-1] = '\0';
char ubuff[5*UNIX_PATH_MAX+3];
char *nextc;
#if WITH_ABSTRACT_UNIXSOCKET
if (salen > XIOUNIXSOCKOVERHEAD &&
sa->sun_path[0] == '\0') {
nextc =
sanitize_string(sa->sun_path, salen-XIOUNIXSOCKOVERHEAD,
ubuff, XIOSAN_DEFAULT_BACKSLASH_OCT_3);
*nextc = '\0';
strncpy(buff, ubuff, blen);
} else
#endif /* WITH_ABSTRACT_UNIXSOCKET */
{
nextc =
sanitize_string(sa->sun_path,
MIN(UNIX_PATH_MAX, strlen(sa->sun_path)),
ubuff, XIOSAN_DEFAULT_BACKSLASH_OCT_3);
*nextc = '\0';
strncpy(buff, ubuff, blen);
}
return buff;
}
@ -276,7 +280,7 @@ const char *inet_ntop(int pf, const void *binaddr,
#if WITH_IP6
/* convert the IP6 socket address to human readable form. buff should be at
least 50 chars long */
least 50 chars long. output includes the port number */
char *sockaddr_inet6_info(const struct sockaddr_in6 *sa, char *buff, size_t blen) {
if (snprintf(buff, blen, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:%hu",
#if HAVE_IP6_SOCKADDR==0
@ -434,6 +438,7 @@ int parseport(const char *portname, int ipproto) {
}
#endif /* WITH_TCP || WITH_UDP */
#if WITH_IP4 || WITH_IP6
/* check the systems interfaces for ifname and return its index
or -1 if no interface with this name was found */
@ -500,3 +505,80 @@ int ifindex(const char *ifname, unsigned int *ifindex) {
return 0;
}
#endif /* WITH_IP4 || WITH_IP6 */
/* constructs an environment variable whose name is built from socats uppercase
program name, and underscore and varname; if a variable of this name already
exists a non zero value of overwrite lets the old value be overwritten.
returns 0 on success or <0 if an error occurred. */
int xiosetenv(const char *varname, const char *value, int overwrite) {
# define XIO_ENVNAMELEN 256
const char *progname;
char envname[XIO_ENVNAMELEN];
size_t i, l;
progname = diag_get_string('p');
strncpy(envname, progname, XIO_ENVNAMELEN-1);
l = strlen(progname);
strncpy(envname+l, "_", XIO_ENVNAMELEN-1-l);
for (i = 0; i < l; ++i) envname[i] = toupper(envname[i]);
strncpy(envname+l+1, varname, XIO_ENVNAMELEN-1-l);
if (Setenv(envname, value, overwrite) < 0) {
Warn3("setenv(\"...\", \"%s\", 1): %s",
envname, value, strerror(errno));
Unsetenv(envname); /* dont want to have a wrong value */
return -1;
}
return 0;
# undef XIO_ENVNAMELEN
}
int xiosetenv2(const char *varname, const char *varname2, const char *value,
int overwrite) {
# define XIO_ENVNAMELEN 256
const char *progname;
char envname[XIO_ENVNAMELEN];
size_t i, l;
progname = diag_get_string('p');
strncpy(envname, progname, XIO_ENVNAMELEN-1);
l = strlen(progname);
strncpy(envname+l, "_", XIO_ENVNAMELEN-1-l);
l += 1;
strncpy(envname+l, varname, XIO_ENVNAMELEN-1-l);
l += strlen(varname);
strncpy(envname+l, "_", XIO_ENVNAMELEN-1-l);
l += 1;
strncpy(envname+l, varname2, XIO_ENVNAMELEN-1-l);
l += strlen(varname2);
for (i = 0; i < l; ++i) envname[i] = toupper(envname[i]);
if (Setenv(envname, value, overwrite) < 0) {
Warn3("setenv(\"...\", \"%s\", 1): %s",
envname, value, strerror(errno));
Unsetenv(envname); /* dont want to have a wrong value */
return -1;
}
return 0;
# undef XIO_ENVNAMELEN
}
/* like xiosetenv(), but uses an unsigned long value */
int xiosetenvulong(const char *varname, unsigned long value, int overwrite) {
# define XIO_LONGLEN 21 /* should suffice for 64bit longs with \0 */
char envbuff[XIO_LONGLEN];
snprintf(envbuff, XIO_LONGLEN, "%lu", value);
return xiosetenv(varname, envbuff, overwrite);
# undef XIO_LONGLEN
}
/* like xiosetenv(), but uses an unsigned short value */
int xiosetenvushort(const char *varname, unsigned short value, int overwrite) {
# define XIO_SHORTLEN 11 /* should suffice for 32bit shorts with \0 */
char envbuff[XIO_SHORTLEN];
snprintf(envbuff, XIO_SHORTLEN, "%hu", value);
return xiosetenv(varname, envbuff, overwrite);
# undef XIO_SHORTLEN
}

View file

@ -1,5 +1,5 @@
/* source: sysutils.h */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __sysutils_h_included
@ -97,4 +97,13 @@ extern int parseport(const char *portname, int proto);
extern int ifindexbyname(const char *ifname);
extern int ifindex(const char *ifname, unsigned int *ifindex);
extern int xiosetenv(const char *varname, const char *value, int overwrite);
extern int
xiosetenv2(const char *varname, const char *varname2, const char *value,
int overwrite);
extern int xiosetenvulong(const char *varname, unsigned long value,
int overwrite);
extern int xiosetenvushort(const char *varname, unsigned short value,
int overwrite);
#endif /* !defined(__sysutils_h_included) */

415
test.sh
View file

@ -48,13 +48,15 @@ opts="$opt_t $OPTS"
export SOCAT_OPTS="$opts"
#debug="1"
debug=
TESTS="$@"
TESTS="$@"; export TESTS
INTERFACE=eth0; # not used for function tests
MCINTERFACE=lo # !!! Linux only
#LOCALHOST=192.168.58.1
#LOCALHOST=localhost
LOCALHOST=127.0.0.1
LOCALHOST6=[::1]
#PROTO=$(awk '{print($2);}' /etc/protocols |sort -n |tail -n 1)
#PROTO=$(($PROTO+1))
PROTO=$((144+RANDOM/2048))
PORT=12002
SOURCEPORT=2002
@ -1912,14 +1914,21 @@ waitudp6port () {
return 1
}
# we need this misleading function name for canonical reasons
waitunixport () {
waitfile "$1" "$2" "$3"
}
# wait until a filesystem entry exists
waitfile () {
local crit=-e
case "X$1" in X-*) crit="$1"; shift ;; esac
local file="$1"
local logic="$2" # 0..wait until gone; 1..wait until exists (default)
local logic="$2" # 0..wait until gone; 1..wait until exists (default);
# 2..wait until not empty
local timeout="$3"
[ "$logic" ] || logic=1
[ "$logic" -eq 2 ] && crit=-s
[ "$timeout" ] || timeout=5
while [ $timeout -gt 0 ]; do
if [ \( \( $logic -ne 0 \) -a $crit "$file" \) -o \
@ -7657,7 +7666,7 @@ printf "test $F_n $TEST... " $N
$CMD1 2>"${te}1" &
pid1="$!"
waitip4port $ts1p 1
usleep 100000 # give process a chance to add membership
usleep 100000 # give process a chance to add multicast membership
echo "$da" |$CMD2 >>"$tf" 2>>"${te}2"
rc2="$?"
kill "$pid1" 2>/dev/null; wait;
@ -8147,13 +8156,12 @@ rc2=$?
sleep 1
#read -p ">"
l="$(childprocess $pid1)"
rcc=$?
kill $pid1 2>/dev/null; wait
if [ $rc2 -ne 0 ]; then
$PRINTF "$NO_RESULT\n" # already handled in test UDP4STREAM
$PRINTF "$NO_RESULT (client failed)\n" # already handled in test UDP4STREAM
numCANT=$((numCANT+1))
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$NO_RESULT\n" # already handled in test UDP4STREAM
$PRINTF "$NO_RESULT (diff failed)\n" # already handled in test UDP4STREAM
numCANT=$((numCANT+1))
elif $(isdefunct "$l"); then
$PRINTF "$FAILED: $SOCAT:\n"
@ -8169,7 +8177,7 @@ fi ;;
esac
PORT=$((PORT+1))
N=$((N+1))
set +vx
# there was a bug with udp-recvfrom and fork: terminating sub processes became
# zombies because the master process caught SIGCHLD but did not wait()
@ -8198,7 +8206,6 @@ rc2=$?
sleep 1
#read -p ">"
l="$(childprocess $pid1)"
rcc=$?
kill $pid1 2>/dev/null; wait
if [ $rc2 -ne 0 ]; then
$PRINTF "$NO_RESULT\n" # already handled in test UDP4DGRAM
@ -8513,6 +8520,398 @@ esac
N=$((N+1))
while read SCM_ENABLE SCM_RECV SCM_TYPE SCM_NAME SCM_VALUE
do
# test: logging of ancillary message with ip-recvopt
NAME=UDP4SCM_$SCM_TYPE
case "$TESTS" in
*%functions%*|*%ip4%*|*%dgram%*|*%udp%*|*%udp4%*|*%recv%*|*%ancillary%*|*%$NAME%*)
#set -vx
TEST="$NAME: IPv4 ancillary messages"
# idea: start a socat process with udp4-recv:..,ip-recvopts and send it a packet
# with IP options (ip-options). check the info log for the appropriate output.
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
ts1p=$PORT; PORT=$((PORT+1))
ts1a="127.0.0.1"
ts1="$ts1a:$ts1p"
CMD0="$SOCAT $opts -d -d -d -u UDP4-RECV:$ts1p,reuseaddr,$SCM_RECV -"
CMD1="$SOCAT $opts -u - UDP4-SENDTO:$ts1,$SCM_ENABLE"
printf "test $F_n $TEST... " $N
# is this option supported?
if $SOCAT -hhh |grep "[[:space:]]$SCM_RECV[[:space:]]" >/dev/null; then
$CMD0 >"$tf" 2>"${te}0" &
pid0="$!"
waitudp4port $ts1p 1
echo "XYZ" |$CMD1 2>>"${te}1"
rc1="$?"
sleep 1
i=0; while [ ! -s "${te}0" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done
kill "$pid0" 2>/dev/null; wait
# do not show more messages than requested
case "$opts" in
*-d*-d*-d*-d*) LEVELS="[EWNID]" ;;
*-d*-d*-d*) LEVELS="[EWNI]" ;;
*-d*-d*) LEVELS="[EWN]" ;;
*-d*) LEVELS="[EW]" ;;
*) LEVELS="[E]" ;;
esac
if [ "$rc1" -ne 0 ]; then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD0 &"
echo "$CMD1"
grep " $LEVELS " "${te}0"
grep " $LEVELS " "${te}1"
numFAIL=$((numFAIL+1))
elif ! grep "ancillary message: $SCM_TYPE: $SCM_NAME=$SCM_VALUE" ${te}0 >/dev/null; then
$PRINTF "$FAILED\n"
echo "$CMD0 &"
echo "$CMD1"
grep " $LEVELS " "${te}0"
grep " $LEVELS " "${te}1"
numFAIL=$((numFAIL+1))
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then
grep " $LEVELS " "${te}0"; echo; grep " $LEVELS " "${te}1";
fi
numOK=$((numOK+1))
fi
else # option is not supported
$PRINTF "${YELLOW}$SCM_RECV not available${NORMAL}\n"
numCANT=$((numCANT+1))
fi # option is not supported
set +vx
;;
esac
N=$((N+1))
done <<<"ip-options=x01000000 ip-recvopts IP_OPTIONS options x01000000
, so-timestamp SCM_TIMESTAMP timestamp $(date '+%a %b %e %H:%M:.. %Y')
ip-ttl=53 ip-recvttl IP_TTL ttl 53
ip-tos=7 ip-recvtos IP_TOS tos 7
, ip-pktinfo IP_PKTINFO locaddr 127.0.0.1
, ip-recvif IP_RECVIF if lo
, ip-recvdstaddr IP_RECVDSTADDR dstaddr 127.0.0.1"
# test: logging of ancillary message
while read PF KEYW ADDR IPPORT SCM_ENABLE SCM_RECV SCM_TYPE SCM_NAME ROOT SCM_VALUE
do
if [ -z "$PF" ]; then continue; fi
#
pf="$(echo $PF |tr A-Z a-z)"
proto="$(echo $KEYW |tr A-Z a-z)"
NAME=${KEYW}SCM_$SCM_TYPE
case "$TESTS" in
*%functions%*|*%$pf%*|*%dgram%*|*%udp%*|*%$proto%*|*%recv%*|*%ancillary%*|*%$ROOT%*|*%$NAME%*)
TEST="$NAME: $KEYW log ancillary message $SCM_TYPE $SCM_NAME"
# idea: start a socat process with *-RECV:..,... , ev. with ancillary message
# enabling option and send it a packet, ev. with some option. check the info log
# for the appropriate output.
if [ "$ROOT" = root -a $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then
$PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N
numCANT=$((numCANT+1))
else
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
case "X$IPPORT" in
"XPORT")
tra="$PORT" # test recv address
tsa="$ADDR:$PORT" # test sendto address
PORT=$((PORT+1)) ;;
"XPROTO")
tra="$PROTO" # test recv address
tsa="$ADDR:$PROTO" # test sendto address
PROTO=$((PROTO+1)) ;;
*)
tra="$(eval echo "$ADDR")" # resolve $N
tsa="$tra"
esac
CMD0="$SOCAT $opts -d -d -d -u $KEYW-RECV:$tra,reuseaddr,$SCM_RECV -"
CMD1="$SOCAT $opts -u - $KEYW-SENDTO:$tsa,$SCM_ENABLE"
printf "test $F_n $TEST... " $N
# is this option supported?
if $SOCAT -hhh |grep "[[:space:]]$SCM_RECV[[:space:]]" >/dev/null; then
$CMD0 >"$tf" 2>"${te}0" &
pid0="$!"
wait${proto}port $tra 1
echo "XYZ" |$CMD1 2>"${te}1"
rc1="$?"
sleep 1
i=0; while [ ! -s "${te}0" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done
kill "$pid0" 2>/dev/null; wait
# do not show more messages than requested
case "$opts" in
*-d*-d*-d*-d*) LEVELS="[EWNID]" ;;
*-d*-d*-d*) LEVELS="[EWNI]" ;;
*-d*-d*) LEVELS="[EWN]" ;;
*-d*) LEVELS="[EW]" ;;
*) LEVELS="[E]" ;;
esac
if [ "$rc1" -ne 0 ]; then
$PRINTF "$NO_RESULT: $SOCAT:\n"
echo "$CMD0 &"
echo "$CMD1"
grep " $LEVELS " "${te}0"
grep " $LEVELS " "${te}1"
numCANT=$((numCANT+1))
elif ! grep "ancillary message: $SCM_TYPE: $SCM_NAME=$SCM_VALUE" ${te}0 >/dev/null; then
$PRINTF "$FAILED\n"
echo "$CMD0 &"
echo "$CMD1"
grep " $LEVELS " "${te}0"
grep " $LEVELS " "${te}1"
numFAIL=$((numFAIL+1))
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then
grep " $LEVELS " "${te}0"; echo; grep " $LEVELS " "${te}1";
fi
numOK=$((numOK+1))
fi
set +vx
else # option is not supported
$PRINTF "${YELLOW}$SCM_RECV not available${NORMAL}\n"
numCANT=$((numCANT+1))
fi # option is not supported
fi # must be root
;;
esac
N=$((N+1))
#
done <<<"
IP4 UDP4 127.0.0.1 PORT ip-options=x01000000 ip-recvopts IP_OPTIONS options user x01000000
IP4 UDP4 127.0.0.1 PORT , so-timestamp SCM_TIMESTAMP timestamp user $(date '+%a %b %e %H:%M:.. %Y')
IP4 UDP4 127.0.0.1 PORT ip-ttl=53 ip-recvttl IP_TTL ttl user 53
IP4 UDP4 127.0.0.1 PORT ip-tos=7 ip-recvtos IP_TOS tos user 7
IP4 UDP4 127.0.0.1 PORT , ip-pktinfo IP_PKTINFO locaddr user 127.0.0.1
IP4 UDP4 127.0.0.1 PORT , ip-pktinfo IP_PKTINFO dstaddr user 127.0.0.1
IP4 UDP4 127.0.0.1 PORT , ip-pktinfo IP_PKTINFO if user lo
IP4 UDP4 127.0.0.1 PORT , ip-recvif IP_RECVIF if user lo0
IP4 UDP4 127.0.0.1 PORT , ip-recvdstaddr IP_RECVDSTADDR dstaddr user 127.0.0.1
IP4 IP4 127.0.0.1 PROTO ip-options=x01000000 ip-recvopts IP_OPTIONS options root x01000000
IP4 IP4 127.0.0.1 PROTO , so-timestamp SCM_TIMESTAMP timestamp root $(date '+%a %b %e %H:%M:.. %Y')
IP4 IP4 127.0.0.1 PROTO ip-ttl=53 ip-recvttl IP_TTL ttl root 53
IP4 IP4 127.0.0.1 PROTO ip-tos=7 ip-recvtos IP_TOS tos root 7
IP4 IP4 127.0.0.1 PROTO , ip-pktinfo IP_PKTINFO locaddr root 127.0.0.1
IP4 IP4 127.0.0.1 PROTO , ip-pktinfo IP_PKTINFO dstaddr root 127.0.0.1
IP4 IP4 127.0.0.1 PROTO , ip-pktinfo IP_PKTINFO if root lo
IP4 IP4 127.0.0.1 PROTO , ip-recvif IP_RECVIF if root lo0
IP4 IP4 127.0.0.1 PROTO , ip-recvdstaddr IP_RECVDSTADDR dstaddr root 127.0.0.1
IP6 UDP6 [::1] PORT , so-timestamp SCM_TIMESTAMP timestamp user $(date '+%a %b %e %H:%M:.. %Y')
IP6 UDP6 [::1] PORT , ipv6-recvpktinfo IPV6_PKTINFO dstaddr user [[]0000:0000:0000:0000:0000:0000:0000:0001[]]
IP6 UDP6 [::1] PORT ipv6-unicast-hops=35 ipv6-recvhoplimit IPV6_HOPLIMIT hoplimit user 35
IP6 UDP6 [::1] PORT ipv6-tclass=0xaa ipv6-recvtclass IPV6_TCLASS tclass user xaa000000
IP6 IP6 [::1] PROTO , so-timestamp SCM_TIMESTAMP timestamp root $(date '+%a %b %e %H:%M:.. %Y')
IP6 IP6 [::1] PROTO , ipv6-recvpktinfo IPV6_PKTINFO dstaddr root [[]0000:0000:0000:0000:0000:0000:0000:0001[]]
IP6 IP6 [::1] PROTO ipv6-unicast-hops=35 ipv6-recvhoplimit IPV6_HOPLIMIT hoplimit root 35
IP6 IP6 [::1] PROTO ipv6-tclass=0xaa ipv6-recvtclass IPV6_TCLASS tclass root xaa000000
UNIX UNIX $td/test\$N.server - , so-timestamp SCM_TIMESTAMP timestamp user $(date '+%a %b %e %H:%M:.. %Y')
"
# this one fails, appearently due to a Linux weakness:
# UNIX so-timestamp
# test: setting of environment variables that describe a stream socket
# connection: SOCAT_SOCKADDR, SOCAT_PEERADDR; and SOCAT_SOCKPORT,
# SOCAT_PEERPORT when applicable
while read KEYW TEST_SOCKADDR TEST_PEERADDR TEST_SOCKPORT TEST_PEERPORT; do
if [ -z "$KEYW" ]; then continue; fi
#
test_proto="$(echo $KEYW |tr A-Z a-z)"
NAME=${KEYW}LISTENENV
case "$TESTS" in
*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%$test_proto%*|*%envvar%*|*%$NAME%*)
TEST="$NAME: $KEYW-LISTEN fills environment variables with socket addresses"
# have a server accepting a connection and invoking some shell code. The shell
# code extracts and prints the SOCAT related environment vars.
# outside code then checks if the environment contains the variables correctly
# describing the peer and local sockets.
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
TEST_SOCKADDR="$(echo $TEST_SOCKADDR |sed "s/\$N/$N/g")" # actual vars
tsa="$TEST_SOCKADDR" # test server address
tsp="$TEST_SOCKPORT" # test server port
if [ "$tsp" != ',' ]; then
tsa1="$tsp"; tsa2="$tsa"; tsa="$tsa:$tsp" # tsa2 used for server bind=
else
tsa1="$tsa"; tsa2= # tsa1 used for addr parameter
fi
TEST_PEERADDR="$(echo $TEST_PEERADDR |sed "s/\$N/$N/g")" # actual vars
tca="$TEST_PEERADDR" # test client address
tcp="$TEST_PEERPORT" # test client port
if [ "$tcp" != ',' ]; then
tca="$tca:$tcp"
fi
CMD0="$SOCAT $opts -u $KEYW-LISTEN:$tsa1 system:\"export -p\""
CMD1="$SOCAT $opts -u - $KEYW-CONNECT:$tsa,bind=$tca"
printf "test $F_n $TEST... " $N
eval "$CMD0 2>\"${te}0\" >\"$tf\" &"
pid0=$!
wait${test_proto}port $tsa1 1
echo |$CMD1 2>"${te}1"
rc1=$?
waitfile "$tf" 2
kill $pid0 2>/dev/null; wait
#set -vx
if [ $rc1 != 0 ]; then
$PRINTF "$NO_RESULT (client failed):\n"
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
numCANT=$((numCANT+1))
elif [ "$(grep SOCAT_SOCKADDR "${tf}" |sed -e 's/^[^=]*=//' |sed -e "s/[\"']//g")" = "$TEST_SOCKADDR" -a \
"$(grep SOCAT_PEERADDR "${tf}" |sed -e 's/^[^=]*=//' -e "s/[\"']//g")" = "$TEST_PEERADDR" -a \
\( "$TEST_SOCKPORT" = ',' -o "$(grep SOCAT_SOCKPORT "${tf}" |sed -e 's/^[^=]*=//' |sed -e 's/"//g')" = "$tsp" \) -a \
\( "$TEST_PEERPORT" = ',' -o "$(grep SOCAT_PEERPORT "${tf}" |sed -e 's/^[^=]*=//' |sed -e 's/"//g')" = "$tcp" \) \
]; then
$PRINTF "$OK\n"
if [ "$debug" ]; then
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
fi
numOK=$((numOK+1))
else
$PRINTF "$FAILED\n"
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
numFAIL=$((numFAIL+1))
fi
set +xv
;;
esac
N=$((N+1))
#
done <<<"
TCP4 $LOCALHOST $SECONDADDR $PORT $((PORT+1))
TCP6 [0000:0000:0000:0000:0000:0000:0000:0001] [0000:0000:0000:0000:0000:0000:0000:0001] $((PORT+2)) $((PORT+3))
UDP6 [0000:0000:0000:0000:0000:0000:0000:0001] [0000:0000:0000:0000:0000:0000:0000:0001] $((PORT+6)) $((PORT+7))
UNIX $td/test\$N.server $td/test\$N.client , ,
"
# this one fails do to weakness in socats UDP4-LISTEN implementation:
#UDP4 $LOCALHOST $SECONDADDR $((PORT+4)) $((PORT+5))
# test: environment variables from ancillary message
while read PF KEYW ADDR IPPORT SCM_ENABLE SCM_RECV SCM_ENVNAME ROOT SCM_VALUE
do
if [ -z "$PF" ]; then continue; fi
#
pf="$(echo $PF |tr A-Z a-z)"
proto="$(echo $KEYW |tr A-Z a-z)"
NAME=${KEYW}ENV_$SCM_ENVNAME
case "$TESTS" in
*%functions%*|*%$pf%*|*%dgram%*|*%udp%*|*%$proto%*|*%recv%*|*%ancillary%*|*%envvar%*|*%$ROOT%*|*%$NAME%*)
#set -vx
TEST="$NAME: $KEYW ancillary message brings $SCM_ENVNAME into environment"
# idea: start a socat process with *-RECVFROM:..,... , ev. with ancillary
# message enabling option and send it a packet, ev. with some option. write
# the resulting environment to a file and check its contents for the
# appropriate variable.
if [ "$ROOT" = root -a $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then
$PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N
numCANT=$((numCANT+1))
else
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
case "X$IPPORT" in
"XPORT")
tra="$PORT" # test recv address
tsa="$ADDR:$PORT" # test sendto address
PORT=$((PORT+1)) ;;
"XPROTO")
tra="$PROTO" # test recv address
tsa="$ADDR:$PROTO" # test sendto address
PROTO=$((PROTO+1)) ;;
*)
tra="$(eval echo "$ADDR")" # resolve $N
tsa="$tra"
esac
#CMD0="$SOCAT $opts -u $KEYW-RECVFROM:$tra,reuseaddr,$SCM_RECV system:\"export -p\""
CMD0="$SOCAT $opts -u $KEYW-RECVFROM:$tra,reuseaddr,$SCM_RECV system:\"echo \\\$SOCAT_$SCM_ENVNAME\""
CMD1="$SOCAT $opts -u - $KEYW-SENDTO:$tsa,$SCM_ENABLE"
printf "test $F_n $TEST... " $N
# is this option supported?
if $SOCAT -hhh |grep "[[:space:]]$SCM_RECV[[:space:]]" >/dev/null; then
eval "$CMD0 >\"$tf\" 2>\"${te}0\" &"
pid0="$!"
wait${proto}port $tra 1
echo "XYZ" |$CMD1 2>"${te}1"
rc1="$?"
waitfile "$tf" 2
#i=0; while [ ! -s "${te}0" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done
kill "$pid0" 2>/dev/null; wait
# do not show more messages than requested
#set -vx
if [ "$rc1" -ne 0 ]; then
$PRINTF "$NO_RESULT: $SOCAT:\n"
echo "$CMD0 &"
echo "$CMD1"
cat "${te}0"
cat "${te}1"
numCANT=$((numCANT+1))
#elif ! egrep "^export SOCAT_$SCM_ENVNAME=[\"']?$SCM_VALUE[\"']?\$" ${tf} >/dev/null; then
#elif ! eval echo "$SOCAT_\$SCM_VALUE" |diff - "${tf}" >/dev/null; then
elif ! expr "$(cat "$tf")" : "$(eval echo "\$SCM_VALUE")" >/dev/null; then
$PRINTF "$FAILED\n"
echo "$CMD0 &"
echo "$CMD1"
cat "${te}0"
cat "${te}1"
numFAIL=$((numFAIL+1))
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then
cat "${te}0"; echo; cat "${te}1";
fi
numOK=$((numOK+1))
fi
set +vx
else # option is not supported
$PRINTF "${YELLOW}$SCM_RECV not available${NORMAL}\n"
numCANT=$((numCANT+1))
fi # option is not supported
fi # must be root
;;
esac
N=$((N+1))
#
done <<<"
IP4 UDP4 127.0.0.1 PORT ip-options=x01000000 ip-recvopts IP_OPTIONS user x01000000
IP4 UDP4 127.0.0.1 PORT , so-timestamp TIMESTAMP user $(date '+%a %b %e %H:%M:.. %Y'), ...... usecs
IP4 UDP4 127.0.0.1 PORT ip-ttl=53 ip-recvttl IP_TTL user 53
IP4 UDP4 127.0.0.1 PORT ip-tos=7 ip-recvtos IP_TOS user 7
IP4 UDP4 127.0.0.1 PORT , ip-pktinfo IP_LOCADDR user 127.0.0.1
IP4 UDP4 127.0.0.1 PORT , ip-pktinfo IP_DSTADDR user 127.0.0.1
IP4 UDP4 127.0.0.1 PORT , ip-pktinfo IP_IF user lo
IP4 UDP4 127.0.0.1 PORT , ip-recvif IP_RECVIF user lo0
IP4 UDP4 127.0.0.1 PORT , ip-recvdstaddr IP_RECVDSTADDR user 127.0.0.1
IP4 IP4 127.0.0.1 PROTO ip-options=x01000000 ip-recvopts IP_OPTIONS root x01000000
IP4 IP4 127.0.0.1 PROTO , so-timestamp TIMESTAMP root $(date '+%a %b %e %H:%M:.. %Y'), ...... usecs
IP4 IP4 127.0.0.1 PROTO ip-ttl=53 ip-recvttl IP_TTL root 53
IP4 IP4 127.0.0.1 PROTO ip-tos=7 ip-recvtos IP_TOS root 7
IP4 IP4 127.0.0.1 PROTO , ip-pktinfo IP_LOCADDR root 127.0.0.1
IP4 IP4 127.0.0.1 PROTO , ip-pktinfo IP_DSTADDR root 127.0.0.1
IP4 IP4 127.0.0.1 PROTO , ip-pktinfo IP_IF root lo
IP4 IP4 127.0.0.1 PROTO , ip-recvif IP_RECVIF root lo0
IP4 IP4 127.0.0.1 PROTO , ip-recvdstaddr IP_RECVDSTADDR root 127.0.0.1
IP6 UDP6 [::1] PORT , ipv6-recvpktinfo IPV6_DSTADDR user [[]0000:0000:0000:0000:0000:0000:0000:0001[]]
IP6 UDP6 [::1] PORT ipv6-unicast-hops=35 ipv6-recvhoplimit IPV6_HOPLIMIT user 35
IP6 UDP6 [::1] PORT ipv6-tclass=0xaa ipv6-recvtclass IPV6_TCLASS user xaa000000
IP6 IP6 [::1] PROTO , ipv6-recvpktinfo IPV6_DSTADDR root [[]0000:0000:0000:0000:0000:0000:0000:0001[]]
IP6 IP6 [::1] PROTO ipv6-unicast-hops=35 ipv6-recvhoplimit IPV6_HOPLIMIT root 35
IP6 IP6 [::1] PROTO ipv6-tclass=0xaa ipv6-recvtclass IPV6_TCLASS root xaa000000
UNIX UNIX $td/test\$N.server - , so-timestamp TIMESTAMP user $(date '+%a %b %e %H:%M:.. %Y')
"
echo "summary: $((N-1)) tests; $numOK ok, $numFAIL failed, $numCANT could not be performed"
if [ "$numFAIL" -gt 0 ]; then

16
utils.c
View file

@ -1,5 +1,5 @@
/* source: utils.c */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* useful additions to C library */
@ -145,3 +145,17 @@ char *sanitize_string(const char *data, /* input data */
}
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;
}

View file

@ -1,5 +1,5 @@
/* source: utils.h */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __utils_h_included
@ -63,6 +63,7 @@ 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);
#endif /* !defined(__utils_h_included) */

View file

@ -1,5 +1,5 @@
/* source: xio-ascii.c */
/* Copyright Gerhard Rieger 2002-2006 */
/* Copyright Gerhard Rieger 2002-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains functions for text encoding, decoding, and conversions */
@ -105,3 +105,52 @@ char *
}
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!
*/
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) { codbuff[0] = '\0'; return codbuff; }
if (space == 0) space = -1;
if (0) {
; /* for canonical reasons */
} else if (1) {
/* simple hexadecimal output */
if (bytes > 2*codlen+1) {
bytes = (codlen-1)/2;
}
*codbuff++ = 'x'; --codlen;
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;
}

View file

@ -1,5 +1,5 @@
/* source: xio-ascii.h */
/* Copyright Gerhard Rieger 2002-2006 */
/* Copyright Gerhard Rieger 2002-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_ascii_h_included
@ -17,4 +17,8 @@ extern char *xiosanitize(const char *data, /* input data */
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) */

122
xio-ip.c
View file

@ -9,6 +9,8 @@
#if _WITH_IP4 || _WITH_IP6
#include "xioopen.h"
#include "xio-ascii.h"
#include "xio-socket.h"
#include "xio-ip.h"
#include "xio-ip6.h"
@ -25,7 +27,7 @@ const struct optdesc opt_ip_pktinfo = { "ip-pktinfo", "pktinfo", OPT_IP_PKTINF
#ifdef IP_RECVTOS
const struct optdesc opt_ip_recvtos = { "ip-recvtos", "recvtos", OPT_IP_RECVTOS, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_RECVTOS };
#endif
#ifdef IP_RECVTTL
#ifdef IP_RECVTTL /* -Cygwin */
const struct optdesc opt_ip_recvttl = { "ip-recvttl", "recvttl", OPT_IP_RECVTTL, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_RECVTTL };
#endif
#ifdef IP_RECVOPTS
@ -65,6 +67,12 @@ const struct optdesc opt_ip_pktoptions = { "ip-pktoptions", "pktopts", OPT_IP_PK
#ifdef IP_ADD_MEMBERSHIP
const struct optdesc opt_ip_add_membership = { "ip-add-membership", "membership",OPT_IP_ADD_MEMBERSHIP, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_IP_MREQN, OFUNC_SOCKOPT, SOL_IP, IP_ADD_MEMBERSHIP };
#endif
#ifdef IP_RECVDSTADDR
const struct optdesc opt_ip_recvdstaddr = { "ip-recvdstaddr", "recvdstaddr",OPT_IP_RECVDSTADDR, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_RECVDSTADDR };
#endif
#ifdef IP_RECVIF
const struct optdesc opt_ip_recvif = { "ip-recvif", "recvdstaddrif",OPT_IP_RECVIF, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_RECVIF };
#endif
#if HAVE_RESOLV_H
const struct optdesc opt_res_debug = { "res-debug", NULL, OPT_RES_DEBUG, GROUP_SOCK_IP, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, (size_t)&((xiosingle_t *)0)->para.socket.ip.res_opts, sizeof(unsigned long), RES_DEBUG };
@ -509,4 +517,116 @@ int parserange(const char *rangename, int pf, union xiorange_union *range) {
return 0;
}
#if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)
/* these are valid for IPv4 and IPv6 */
int xiolog_ancillary_ip(struct cmsghdr *cmsg, int *num,
char *typbuff, int typlen,
char *nambuff, int namlen,
char *envbuff, int envlen,
char *valbuff, int vallen) {
const char *cmsgtype, *cmsgname = NULL, *cmsgenvn = NULL, *cmsgfmt = NULL;
size_t msglen;
char scratch1[16]; /* can hold an IPv4 address in ASCII */
char scratch2[16];
char scratch3[16];
msglen = cmsg->cmsg_len-((char *)CMSG_DATA(cmsg)-(char *)cmsg);
envbuff[0] = '\0';
switch (cmsg->cmsg_type) {
default:
*num = 1;
strncpy(typbuff, "IP", typlen);
snprintf(nambuff, namlen, "type_%u", cmsg->cmsg_type);
xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
return STAT_OK;
#ifdef IP_PKTINFO
case IP_PKTINFO: {
struct in_pktinfo *pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
*num = 3;
strncpy(typbuff, "IP_PKTINFO", typlen);
snprintf(nambuff, namlen, "%s%c%s%c%s", "if", '\0', "locaddr", '\0', "dstaddr");
snprintf(envbuff, envlen, "%s%c%s%c%s", "IP_IF", '\0',
"IP_LOCADDR", '\0', "IP_DSTADDR");
snprintf(valbuff, vallen, "%s%c%s%c%s",
xiogetifname(pktinfo->ipi_ifindex, scratch1, -1), '\0',
inet4addr_info(ntohl(pktinfo->ipi_spec_dst.s_addr), scratch2, sizeof(scratch2)), '\0',
inet4addr_info(ntohl(pktinfo->ipi_addr.s_addr), scratch3, sizeof(scratch3)));
}
return STAT_OK;
#endif /* IP_PKTINFO */
#ifdef IP_RECVERR
case IP_RECVERR: {
struct sock_extended_err *err =
(struct sock_extended_err *)CMSG_DATA(cmsg);
*num = 6;
strncpy(typbuff, "IP_RECVERR", typlen);
snprintf(nambuff, namlen, "%s%c%s%c%s%c%s%c%s%c%s",
"errno", '\0', "origin", '\0', "type", '\0',
"code", '\0', "info", '\0', "data");
snprintf(envbuff, envlen, "%s%c%s%c%s%c%s%c%s%c%s",
"IP_RECVERR_ERRNO", '\0', "IP_RECVERR_ORIGIN", '\0',
"IP_RECVERR_TYPE", '\0', "IP_RECVERR_CODE", '\0',
"IP_RECVERR_INFO", '\0', "IP_RECVERR_DATA");
snprintf(valbuff, vallen, "%u%c%u%c%u%c%u%c%u%c%u",
err->ee_errno, '\0', err->ee_origin, '\0', err->ee_type, '\0',
err->ee_code, '\0', err->ee_info, '\0', err->ee_data);
return STAT_OK;
}
#endif /* IP_RECVERR */
#ifdef IP_RECVIF
case IP_RECVIF: {
/* spec in FreeBSD: /usr/include/net/if_dl.h */
struct sockaddr_dl *sadl = (struct sockaddr_dl *)CMSG_DATA(cmsg);
*num = 1;
strncpy(typbuff, "IP_RECVIF", typlen);
strncpy(nambuff, "if", namlen);
strncpy(envbuff, "IP_IF", envlen);
strncpy(valbuff,
xiosubstr(scratch1, sadl->sdl_data, 0, sadl->sdl_nlen), vallen);
return STAT_OK;
}
#endif /* defined(IP_RECVIF) */
#ifdef IP_RECVDSTADDR
case IP_RECVDSTADDR:
*num = 1;
strncpy(typbuff, "IP_RECVDSTADDR", typlen);
strncpy(nambuff, "dstaddr", namlen);
strncpy(envbuff, "IP_DSTADDR", envlen);
inet4addr_info(ntohl(*(uint32_t *)CMSG_DATA(cmsg)), valbuff, vallen);
return STAT_OK;
#endif
case IP_OPTIONS:
case IP_RECVOPTS:
cmsgtype = "IP_OPTIONS"; cmsgname = "options"; cmsgfmt = NULL; break;
case IP_TOS:
cmsgtype = "IP_TOS"; cmsgname = "tos"; cmsgfmt = "%u"; break;
case IP_TTL: /* Linux */
#ifdef IP_RECVTTL
case IP_RECVTTL: /* FreeBSD */
#endif
cmsgtype = "IP_TTL"; cmsgname = "ttl"; cmsgfmt = "%u"; break;
}
/* when we come here we provide a single parameter
with type in cmsgtype, name in cmsgname, printf format in cmsgfmt */
*num = 1;
if (strlen(cmsgtype) >= typlen) Fatal("buff too short");
strncpy(typbuff, cmsgtype, typlen);
if (strlen(cmsgname) >= namlen) Fatal("buff too short");
strncpy(nambuff, cmsgname, namlen);
if (cmsgenvn) {
if (strlen(cmsgenvn) >= envlen) Fatal("buff too short");
strncpy(envbuff, cmsgenvn, envlen);
} else {
envbuff[0] = '\0';
}
if (cmsgfmt != NULL) {
snprintf(valbuff, vallen, cmsgfmt, *(unsigned char *)CMSG_DATA(cmsg));
} else {
xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
}
return STAT_OK;
}
#endif /* defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA) */
#endif /* _WITH_IP4 || _WITH_IP6 */

View file

@ -1,5 +1,5 @@
/* source: xio-ip.h */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_ip_h_included
@ -24,6 +24,8 @@ 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_recvdstaddr;
extern const struct optdesc opt_ip_recvif;
extern const struct optdesc opt_res_debug;
extern const struct optdesc opt_res_aaonly;
@ -44,5 +46,11 @@ int xioparsenetwork(const char *rangename, int pf,
union xiorange_union *range);
extern
int parserange(const char *rangename, int pf, union xiorange_union *range);
extern
int xiolog_ancillary_ip(struct cmsghdr *cmsg, int *num,
char *typbuff, int typlen,
char *nambuff, int namlen,
char *envbuff, int envlen,
char *valbuff, int vallen);
#endif /* !defined(__xio_ip_h_included) */

View file

@ -1,5 +1,5 @@
/* source: xio-ip4.c */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for IP4 related functions */
@ -43,4 +43,41 @@ int xiocheckrange_ip4(struct sockaddr_in *pa, struct xiorange_ip4 *range) {
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");
strcpy(valuebuff,
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 */

View file

@ -1,5 +1,5 @@
/* source: xio-ip4.h */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_ip4_h_included
@ -9,5 +9,9 @@ extern const struct optdesc opt_ip4_add_membership;
extern
int xiocheckrange_ip4(struct sockaddr_in *pa, struct xiorange_ip4 *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) */

228
xio-ip6.c
View file

@ -1,5 +1,5 @@
/* source: xio-ip6.c */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for IP6 related functions */
@ -9,17 +9,47 @@
#if WITH_IP6
#include "xioopen.h"
#include "xio-ascii.h"
#include "xio-socket.h"
#include "xio-ip.h" /* xiogetaddrinfo() */
#include "xio-ip6.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_PASTSOCKET, TYPE_BOOL, OFUNC_SOCKOPT, SOL_IPV6, IPV6_V6ONLY };
#endif
#ifdef IPV6_JOIN_GROUP
const struct optdesc opt_ipv6_join_group = { "ipv6-join-group", "join-group", OPT_IPV6_JOIN_GROUP, GROUP_SOCK_IP6, PH_PASTBIND, TYPE_IP_MREQN, OFUNC_SOCKOPT, SOL_IPV6, IPV6_JOIN_GROUP };
#endif
const struct optdesc opt_ipv6_pktinfo = { "ipv6-pktinfo", "pktinfo", OPT_IPV6_PKTINFO, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_BOOL, OFUNC_SOCKOPT, SOL_IPV6, IPV6_PKTINFO };
const struct optdesc opt_ipv6_recvpktinfo = { "ipv6-recvpktinfo", "recvpktinfo", OPT_IPV6_RECVPKTINFO, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_BOOL, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVPKTINFO };
const struct optdesc opt_ipv6_rthdr = { "ipv6-rthdr", "rthdr", OPT_IPV6_RTHDR, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_BOOL, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RTHDR };
const struct optdesc opt_ipv6_recvrthdr = { "ipv6-recvrthdr", "recvrthdr", OPT_IPV6_RECVRTHDR, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_BOOL, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVRTHDR };
#ifdef IPV6_AUTHHDR
const struct optdesc opt_ipv6_authhdr = { "ipv6-authhdr", "authhdr", OPT_IPV6_AUTHHDR, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_BOOL, OFUNC_SOCKOPT, SOL_IPV6, IPV6_AUTHHDR };
#endif
const struct optdesc opt_ipv6_dstopts = { "ipv6-dstopts", "dstopts", OPT_IPV6_DSTOPTS, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_BOOL, OFUNC_SOCKOPT, SOL_IPV6, IPV6_DSTOPTS };
const struct optdesc opt_ipv6_recvdstopts = { "ipv6-recvdstopts", "recvdstopts", OPT_IPV6_RECVDSTOPTS, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_BOOL, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVDSTOPTS };
const struct optdesc opt_ipv6_hopopts = { "ipv6-hopopts", "hopopts", OPT_IPV6_HOPOPTS, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_BOOL, OFUNC_SOCKOPT, SOL_IPV6, IPV6_HOPOPTS };
const struct optdesc opt_ipv6_recvhopopts = { "ipv6-recvhopopts", "recvhopopts", OPT_IPV6_RECVHOPOPTS, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_BOOL, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVHOPOPTS };
#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_BOOL, OFUNC_SOCKOPT, SOL_IPV6, IPV6_FLOWINFO };
#endif
const struct optdesc opt_ipv6_hoplimit= { "ipv6-hoplimit","hoplimit",OPT_IPV6_HOPLIMIT,GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_BOOL, OFUNC_SOCKOPT, SOL_IPV6, IPV6_HOPLIMIT };
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 };
const struct optdesc opt_ipv6_recvhoplimit= { "ipv6-recvhoplimit","recvhoplimit",OPT_IPV6_RECVHOPLIMIT,GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_BOOL, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVHOPLIMIT };
#ifdef IPV6_RECVERR
const struct optdesc opt_ipv6_recverr = { "ipv6-recverr", "recverr", OPT_IPV6_RECVERR, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_BOOL, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVERR };
#endif
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 };
const struct optdesc opt_ipv6_recvtclass = { "ipv6-recvtclass", "recvtclass", OPT_IPV6_RECVTCLASS, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_BOOL, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVTCLASS };
#ifdef IPV6_RECVPATHMTU
const struct optdesc opt_ipv6_recvpathmtu = { "ipv6-recvpathmtu", "recvpathmtu", OPT_IPV6_RECVPATHMTU, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_BOOL, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVPATHMTU };
#endif
int xioparsenetwork_ip6(const char *rangename, struct xiorange_ip6 *range) {
char *delimpos; /* absolute address of delimiter */
@ -142,4 +172,200 @@ int xiocheckrange_ip6(struct sockaddr_in6 *pa, struct xiorange_ip6 *range) {
return 0;
}
#if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)
/* provides info about the ancillary message */
int xiolog_ancillary_ip6(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) {
case IPV6_PKTINFO: {
struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
*num = 2;
strncpy(typbuff, "IPV6_PKTINFO", typlen);
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;
case IPV6_HOPLIMIT:
strncpy(typbuff, "IPV6_HOPLIMIT", typlen);
strncpy(nambuff, "hoplimit", namlen);
snprintf(valbuff, vallen, "%d", *(int *)CMSG_DATA(cmsg));
return STAT_OK;
case IPV6_RTHDR:
strncpy(typbuff, "IPV6_RTHDR", typlen);
strncpy(nambuff, "rthdr", namlen);
xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
return STAT_OK;
#ifdef IPV6_AUTHHDR
case IPV6_AUTHHDR:
strncpy(typbuff, "IPV6_AUTHHDR", typlen);
strncpy(nambuff, "authhdr", namlen);
xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
return STAT_OK;
#endif
case IPV6_DSTOPTS:
strncpy(typbuff, "IPV6_DSTOPTS", typlen);
strncpy(nambuff, "dstopts", namlen);
xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
return STAT_OK;
case IPV6_HOPOPTS:
strncpy(typbuff, "IPV6_HOPOPTS", typlen);
strncpy(nambuff, "hopopts", namlen);
xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
return STAT_OK;
#ifdef IPV6_FLOWINFO
case IPV6_FLOWINFO:
strncpy(typbuff, "IPV6_FLOWINFO", typlen);
strncpy(nambuff, "flowinfo", namlen);
xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
return STAT_OK;
#endif
case IPV6_TCLASS:
strncpy(typbuff, "IPV6_TCLASS", typlen);
strncpy(nambuff, "tclass", namlen);
xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
return STAT_OK;
default:
snprintf(typbuff, typlen, "IPV6.%u", cmsg->cmsg_type);
strncpy(nambuff, "data", namlen);
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 (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
) < 0) {
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;
}
#endif /* WITH_IP6 */

View file

@ -1,5 +1,5 @@
/* source: xio-ip6.h */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_ip6_h_included
@ -9,6 +9,23 @@
extern const struct optdesc opt_ipv6_v6only;
extern const struct optdesc opt_ipv6_join_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 xioparsenetwork_ip6(const char *rangename, struct xiorange_ip6 *range);
@ -16,6 +33,16 @@ extern int xiorange_ip6andmask(struct xiorange_ip6 *range);
extern
int xiocheckrange_ip6(struct sockaddr_in6 *pa, struct xiorange_ip6 *range);
extern
int xiolog_ancillary_ip6(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);
#endif /* WITH_IP6 */

View file

@ -104,30 +104,24 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
#if WITH_RETRY
if (dofork) {
pid_t pid;
while ((pid = Fork()) < 0) {
int level = E_ERROR;
if (xfd->forever || --xfd->retry) {
level = E_WARN; /* most users won't expect a problem here,
int level = E_ERROR;
if (xfd->forever || xfd->retry) {
level = E_WARN; /* most users won't expect a problem here,
so Notice is too weak */
}
Msg1(level, "fork(): %s", strerror(errno));
if (xfd->forever || xfd->retry) {
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
}
while ((pid = xio_fork(false, level)) < 0) {
if (xfd->forever || --xfd->retry) {
Nanosleep(&xfd->intervall, NULL); continue;
}
return STAT_RETRYLATER;
}
if (pid == 0) { /* child process */
Info1("just born: TCP client process "F_pid, Getpid());
/* drop parents locks, reset FIPS... */
if (xio_forked_inchild() != 0) {
Exit(1);
}
if (pid == 0) { /* child process */
xfd->forever = false; xfd->retry = 0;
break;
}
/* parent process */
Notice1("forked off child process "F_pid, pid);
Close(xfd->fd);
/* with and without retry */
Nanosleep(&xfd->intervall, NULL);
@ -139,6 +133,7 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
break;
}
} while (true);
/* only "active" process breaks (master without fork, or child) */
if ((result = _xio_openlate(xfd, opts)) < 0) {
return result;

View file

@ -98,9 +98,14 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
int backlog = 5; /* why? 1 seems to cause problems under some load */
char *rangename;
bool dofork = false;
pid_t pid; /* mostly int; only used with fork */
char infobuff[256];
char lisname[256];
union sockaddr_union _peername;
union sockaddr_union _sockname;
union sockaddr_union *pa = &_peername; /* peer address */
union sockaddr_union *la = &_sockname; /* local address */
socklen_t pas = sizeof(_peername); /* peer address size */
socklen_t las = sizeof(_sockname); /* local address size */
int result;
retropt_bool(opts, OPT_FORK, &dofork);
@ -199,12 +204,6 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
char peername[256];
char sockname[256];
int ps; /* peer socket */
union sockaddr_union _peername;
union sockaddr_union _sockname;
union sockaddr_union *pa = &_peername; /* peer address */
union sockaddr_union *la = &_sockname; /* local address */
socklen_t pas = sizeof(_peername); /* peer address size */
socklen_t las = sizeof(_sockname); /* local address size */
salen = sizeof(struct sockaddr);
do {
@ -232,16 +231,18 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
if (Getpeername(ps, &pa->soa, &pas) < 0) {
Warn4("getpeername(%d, %p, {"F_socklen"}): %s",
ps, pa, pas, strerror(errno));
pa = NULL;
}
if (Getsockname(ps, &la->soa, &las) < 0) {
Warn4("getsockname(%d, %p, {"F_socklen"}): %s",
ps, pa, pas, strerror(errno));
ps, la, las, strerror(errno));
la = NULL;
}
Notice2("accepting connection from %s on %s",
sockaddr_info(&pa->soa, pas, peername, sizeof(peername)),
sockaddr_info(&la->soa, las, sockname, sizeof(sockname)));
sockaddr_info(pa?&pa->soa:NULL, pas, peername, sizeof(peername)),
sockaddr_info(pa?&la->soa:NULL, las, sockname, sizeof(sockname)));
if (xiocheckpeer(xfd, pa, la) < 0) {
if (pa != NULL && la != NULL && xiocheckpeer(xfd, pa, la) < 0) {
if (Shutdown(ps, 2) < 0) {
Info2("shutdown(%d, 2): %s", ps, strerror(errno));
}
@ -253,16 +254,20 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
infobuff, sizeof(infobuff)));
applyopts(xfd->fd, opts, PH_FD);
applyopts(xfd->fd, opts, PH_CONNECTED);
if (dofork) {
if ((pid = Fork()) < 0) {
Msg1(level, "fork(): %s", strerror(errno));
pid_t pid; /* mostly int; only used with fork */
if ((pid = xio_fork(false, level==E_ERROR?level:E_WARN)) < 0) {
Close(xfd->fd);
return STAT_RETRYLATER;
}
if (pid == 0) { /* child */
pid_t cpid = Getpid();
Info1("just born: client process "F_pid, cpid);
xiosetenvulong("PID", cpid, 1);
if (Close(xfd->fd) < 0) {
Info2("close(%d): %s", xfd->fd, strerror(errno));
}
@ -270,16 +275,10 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
#if WITH_RETRY
/* !? */
xfd->retry = 0;
xfd->forever = 0;
xfd->forever = false; xfd->retry = 0;
level = E_ERROR;
#endif /* WITH_RETRY */
/* drop parents locks, reset FIPS... */
if (xio_forked_inchild() != 0) {
Exit(1);
}
#if WITH_UNIX
/* with UNIX sockets: only listening parent is allowed to remove
the socket file */
@ -295,7 +294,6 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
if (Close(ps) < 0) {
Info2("close(%d): %s", ps, strerror(errno));
}
Notice1("forked off child process "F_pid, pid);
Info("still listening");
} else {
if (Close(xfd->fd) < 0) {
@ -308,6 +306,10 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
if ((result = _xio_openlate(xfd, opts)) < 0)
return result;
/* set the env vars describing the local and remote sockets */
xiosetsockaddrenv("SOCK", la, las, proto);
xiosetsockaddrenv("PEER", pa, pas, proto);
return 0;
}

View file

@ -275,32 +275,23 @@ static int
#if WITH_RETRY
if (dofork) {
pid_t pid;
while ((pid = Fork()) < 0) {
int level = E_ERROR;
if (xfd->forever || xfd->retry) {
level = E_WARN;
}
Msg1(level, "fork(): %s", strerror(errno));
if (xfd->forever || xfd->retry) {
Nanosleep(&xfd->intervall, NULL);
--xfd->retry;
continue;
int level = E_ERROR;
if (xfd->forever || xfd->retry) {
level = E_WARN;
}
while ((pid = xio_fork(false, level)) < 0) {
if (xfd->forever || --xfd->retry) {
Nanosleep(&xfd->intervall, NULL); continue;
}
return STAT_RETRYLATER;
}
if (pid == 0) { /* child process */
Info1("just born: OpenSSL client process "F_pid, Getpid());
/* drop parents locks, reset FIPS... */
if (xio_forked_inchild() != 0) {
Exit(1);
}
xfd->forever = false;
xfd->retry = 0;
if (pid == 0) { /* child process */
xfd->forever = false; xfd->retry = 0;
break;
}
/* parent process */
Notice1("forked off child process "F_pid, pid);
Close(xfd->fd);
sycSSL_free(xfd->para.openssl.ssl);
xfd->para.openssl.ssl = NULL;

View file

@ -404,26 +404,10 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
xiosetchilddied(); /* set SIGCHLD handler */
if (withfork) {
const char *forkwaitstring;
int forkwaitsecs = 0;
pid = Fork();
pid = xio_fork(true, E_ERROR);
if (pid < 0) {
Error1("fork(): %s", strerror(errno));
return -1;
}
/* gdb recommends to have env controlled sleep after fork */
if (forkwaitstring = getenv("SOCAT_FORK_WAIT")) {
forkwaitsecs = atoi(forkwaitstring);
Sleep(forkwaitsecs);
}
if (pid == 0) { /* child */
/* drop parents locks, reset FIPS... */
if (xio_forked_inchild() != 0) {
Exit(1);
}
}
}
if (!withfork || pid == 0) { /* child */
uid_t user;

View file

@ -192,30 +192,23 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
#if WITH_RETRY
if (dofork) {
pid_t pid;
while ((pid = Fork()) < 0) {
int level = E_ERROR;
if (xfd->forever || xfd->retry) {
level = E_WARN;
}
Msg1(level, "fork(): %s", strerror(errno));
if (xfd->forever || xfd->retry--) {
Nanosleep(&xfd->intervall, NULL);
continue;
int level = E_ERROR;
if (xfd->forever || xfd->retry) {
level = E_WARN;
}
while ((pid = xio_fork(false, level)) < 0) {
if (xfd->forever || --xfd->retry) {
Nanosleep(&xfd->intervall, NULL); continue;
}
return STAT_RETRYLATER;
}
if (pid == 0) { /* child process */
Info1("just born: proxy client process "F_pid, Getpid());
/* drop parents locks, reset FIPS... */
if (xio_forked_inchild() != 0) {
Exit(1);
}
if (pid == 0) { /* child process */
xfd->forever = false; xfd->retry = 0;
break;
}
/* parent process */
Notice1("forked off child process "F_pid, pid);
Close(xfd->fd);
Nanosleep(&xfd->intervall, NULL);
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);

View file

@ -9,8 +9,10 @@
#if _WITH_SOCKET
#include "xioopen.h"
#include "xio-ascii.h"
#include "xio-socket.h"
#include "xio-named.h"
#include "xio-unix.h"
#if WITH_IP4
#include "xio-ip4.h"
#endif /* WITH_IP4 */
@ -21,6 +23,15 @@
#include "xio-ipapp.h" /*! not clean */
#include "xio-tcpwrap.h"
static int
xiolog_ancillary_socket(struct cmsghdr *cmsg, int *num,
char *typbuff, int typlen,
char *nambuff, int namlen,
char *envbuff, int envlen,
char *valbuff, int vallen);
const struct optdesc opt_so_debug = { "so-debug", "debug", OPT_SO_DEBUG, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_DEBUG };
#ifdef SO_ACCEPTCONN /* AIX433 */
const struct optdesc opt_so_acceptconn={ "so-acceptconn","acceptconn",OPT_SO_ACCEPTCONN,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_ACCEPTCONN};
@ -73,6 +84,9 @@ const struct optdesc opt_so_bsdcompat= { "so-bsdcompat","bsdcompat",OPT_SO_BSDCO
#ifdef SO_CKSUMRECV
const struct optdesc opt_so_cksumrecv= { "so-cksumrecv","cksumrecv",OPT_SO_CKSUMRECV,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_CKSUMRECV };
#endif /* SO_CKSUMRECV */
#ifdef SO_TIMESTAMP
const struct optdesc opt_so_timestamp= { "so-timestamp","timestamp",OPT_SO_TIMESTAMP,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_TIMESTAMP };
#endif
#ifdef SO_KERNACCEPT /* AIX 4.3.3 */
const struct optdesc opt_so_kernaccept={ "so-kernaccept","kernaccept",OPT_SO_KERNACCEPT,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_KERNACCEPT};
#endif /* SO_KERNACCEPT */
@ -410,30 +424,26 @@ int xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
#if WITH_RETRY
if (dofork) {
pid_t pid;
while ((pid = Fork()) < 0) {
int level = E_ERROR;
if (xfd->forever || --xfd->retry) {
level = E_WARN; /* most users won't expect a problem here,
int level = E_ERROR;
if (xfd->forever || xfd->retry) {
level = E_WARN; /* most users won't expect a problem here,
so Notice is too weak */
}
Msg1(level, "fork(): %s", strerror(errno));
}
while ((pid = xio_fork(false, level)) < 0) {
--xfd->retry;
if (xfd->forever || xfd->retry) {
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
Nanosleep(&xfd->intervall, NULL); continue;
}
return STAT_RETRYLATER;
}
if (pid == 0) { /* child process */
Info1("just born: TCP client process "F_pid, Getpid());
/* drop parents locks, reset FIPS... */
if (xio_forked_inchild() != 0) {
Exit(1);
}
if (pid == 0) { /* child process */
break;
}
/* parent process */
Notice1("forked off child process "F_pid, pid);
Close(xfd->fd);
/* with and without retry */
Nanosleep(&xfd->intervall, NULL);
@ -720,6 +730,8 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
union sockaddr_union *pa = &_peername; /* peer address */
union sockaddr_union *la = &_sockname; /* local address */
socklen_t palen = sizeof(_peername); /* peer address size */
char ctrlbuff[1024]; /* ancillary messages */
struct msghdr msgh = {0};
socket_init(pf, pa);
salen = sizeof(struct sockaddr);
@ -755,14 +767,25 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
return STAT_RETRYLATER;
} while (true);
if (xiogetpacketsrc(xfd->fd, pa, &palen) < 0) {
msgh.msg_name = pa;
msgh.msg_namelen = palen;
#if HAVE_STRUCT_MSGHDR_MSGCONTROL
msgh.msg_control = ctrlbuff;
#endif
#if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
msgh.msg_controllen = sizeof(ctrlbuff);
#endif
if (xiogetpacketsrc(xfd->fd, &msgh) < 0) {
return STAT_RETRYLATER;
}
palen = msgh.msg_namelen;
Notice1("receiving packet from %s"/*"src"*/,
sockaddr_info((struct sockaddr *)pa, palen, peername, sizeof(peername))/*,
sockaddr_info(&la->soa, sockname, sizeof(sockname))*/);
xiodopacketinfo(&msgh, true, true);
if (xiocheckpeer(xfd, pa, la) < 0) {
/* drop packet */
char buff[512];
@ -773,6 +796,10 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
sockaddr_info((struct sockaddr *)pa, palen,
infobuff, sizeof(infobuff)));
/* set the env vars describing the local and remote sockets */
/*xiosetsockaddrenv("SOCK", la, lalen, proto);*/
xiosetsockaddrenv("PEER", pa, palen, proto);
applyopts(xfd->fd, opts, PH_FD);
applyopts(xfd->fd, opts, PH_CONNECTED);
@ -782,8 +809,6 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
if (dofork) {
sigset_t mask_sigchldusr1;
const char *forkwaitstring;
int forkwaitsecs = 0;
/* we must prevent that the current packet triggers another fork;
therefore we wait for a signal from the recent child: USR1
@ -795,17 +820,11 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
sigaddset(&mask_sigchldusr1, SIGUSR1);
Sigprocmask(SIG_BLOCK, &mask_sigchldusr1, NULL);
if ((pid = Fork()) < 0) {
Msg1(level, "fork(): %s", strerror(errno));
if ((pid = xio_fork(false, level)) < 0) {
Close(xfd->fd);
Sigprocmask(SIG_UNBLOCK, &mask_sigchldusr1, NULL);
return STAT_RETRYLATER;
}
/* gdb recommends to have env controlled sleep after fork */
if (forkwaitstring = getenv("SOCAT_FORK_WAIT")) {
forkwaitsecs = atoi(forkwaitstring);
Sleep(forkwaitsecs);
}
if (pid == 0) { /* child */
/* no reason to block SIGCHLD in child process */
@ -820,11 +839,6 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
level = E_ERROR;
#endif /* WITH_RETRY */
/* drop parents locks, reset FIPS... */
if (xio_forked_inchild() != 0) {
Exit(1);
}
#if WITH_UNIX
/* with UNIX sockets: only listening parent is allowed to remove
the socket file */
@ -835,8 +849,6 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
}
/* server: continue loop with listen */
Notice1("forked off child process "F_pid, pid);
xio_waitingfor = pid;
/* now we are ready to handle signals */
Sigprocmask(SIG_UNBLOCK, &mask_sigchldusr1, NULL);
@ -964,65 +976,120 @@ int retropt_socket_pf(struct opt *opts, int *pf) {
}
int xiogetpacketsrc(int fd, union sockaddr_union *pa, socklen_t *palen) {
char infobuff[256];
/* this function calls recvmsg(..., MSG_PEEK, ...) to obtain information about
the arriving packet. in msgh the msg_name pointer must refer to an (empty)
sockaddr storage. */
int xiogetpacketsrc(int fd, struct msghdr *msgh) {
char peekbuff[1];
#if 0
struct msghdr msgh = {0};
#if HAVE_STRUCT_IOVEC
struct iovec iovec;
#endif
char ctrlbuff[5120];
msgh.msg_name = pa;
msgh.msg_namelen = *palen;
#if HAVE_STRUCT_IOVEC
iovec.iov_base = peekbuff;
iovec.iov_len = sizeof(peekbuff);
msgh.msg_iov = &iovec;
msgh.msg_iovlen = 1;
#endif
#if HAVE_STRUCT_MSGHDR_MSGCONTROL
msgh.msg_control = ctrlbuff;
#endif
#if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
msgh.msg_controllen = sizeof(ctrlbuff);
msgh->msg_iov = &iovec;
msgh->msg_iovlen = 1;
#endif
#if HAVE_STRUCT_MSGHDR_MSGFLAGS
msgh.msg_flags = 0;
msgh->msg_flags = 0;
#endif
if (Recvmsg(fd, &msgh, MSG_PEEK
if (Recvmsg(fd, msgh, MSG_PEEK
#ifdef MSG_TRUNC
|MSG_TRUNC
|MSG_TRUNC
#endif
) < 0) {
Notice1("packet from %s",
sockaddr_info(&pa->soa, infobuff, sizeof(infobuff)));
Warn1("recvmsg(): %s", strerror(errno));
return STAT_RETRYLATER;
}
*palen = msgh.msg_namelen;
return STAT_OK;
}
#else
if (Recvfrom(fd, peekbuff, sizeof(peekbuff), MSG_PEEK
#ifdef MSG_TRUNC
|MSG_TRUNC
#endif
,
&pa->soa, palen) < 0) {
Notice1("packet from %s",
sockaddr_info(&pa->soa, *palen, infobuff, sizeof(infobuff)));
Warn1("recvfrom(): %s", strerror(errno));
return STAT_RETRYLATER;
/* works through the ancillary messages found in the given socket header record
and logs the relevant information (E_DEBUG, E_INFO).
calls protocol/layer specific functions for handling the messages
creates appropriate environment vars if withenv is set */
int xiodopacketinfo(struct msghdr *msgh, bool withlog, bool withenv) {
#if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)
struct cmsghdr *cmsg;
/* parse ancillary messages */
cmsg = CMSG_FIRSTHDR(msgh);
while (cmsg != NULL) {
int num = 0; /* number of data components of a ancill.msg */
int i;
char typbuff[16], *typp;
char nambuff[128], *namp;
char valbuff[256], *valp;
char envbuff[256], *envp;
if (withlog) {
xiodump(CMSG_DATA(cmsg),
cmsg->cmsg_len-((char *)CMSG_DATA(cmsg)-(char *)cmsg),
valbuff, sizeof(valbuff)-1, 0);
Debug4("ancillary message: len="F_socklen", level=%d, type=%d, data=%s",
cmsg->cmsg_len, cmsg->cmsg_level, cmsg->cmsg_type,
valbuff);
}
/* try to get the anc.msg. contents in handy components, protocol/level
dependent */
switch (cmsg->cmsg_level) {
case SOL_SOCKET:
xiolog_ancillary_socket(cmsg, &num, typbuff, sizeof(typbuff)-1,
nambuff, sizeof(nambuff)-1,
envbuff, sizeof(envbuff)-1,
valbuff, sizeof(valbuff)-1);
break;
case SOL_IP:
xiolog_ancillary_ip(cmsg, &num, typbuff, sizeof(typbuff)-1,
nambuff, sizeof(nambuff)-1,
envbuff, sizeof(envbuff)-1,
valbuff, sizeof(valbuff)-1);
break;
case SOL_IPV6:
xiolog_ancillary_ip6(cmsg, &num, typbuff, sizeof(typbuff)-1,
nambuff, sizeof(nambuff)-1,
envbuff, sizeof(envbuff)-1,
valbuff, sizeof(valbuff)-1);
break;
default:
num = 1;
snprintf(typbuff, sizeof(typbuff)-1, "LEVEL%u", cmsg->cmsg_level);
snprintf(nambuff, sizeof(nambuff)-1, "type%u", cmsg->cmsg_type);
xiodump(CMSG_DATA(cmsg),
cmsg->cmsg_len-((char *)CMSG_DATA(cmsg)-(char *)cmsg),
valbuff, sizeof(valbuff)-1, 0);
}
/* here the info is in typbuff (one string), nambuff (num consecutive
strings), and valbuff (num consecutive strings) */
i = 0;
typp = typbuff; namp = nambuff; envp = envbuff; valp = valbuff;
while (i < num) {
if (withlog) {
Info3("ancillary message: %s: %s=%s", typp, namp, valp);
}
if (withenv) {
if (*envp) {
xiosetenv(envp, valp, 1);
} else if (!strcasecmp(typp+strlen(typp)-strlen(namp), namp)) {
xiosetenv(typp, valp, 1);
} else {
xiosetenv2(typp, namp, valp, 1);
}
}
if (++i == num) break;
namp = strchr(namp, '\0')+1;
envp = strchr(envp, '\0')+1;
valp = strchr(valp, '\0')+1;
}
cmsg = CMSG_NXTHDR(msgh, cmsg);
}
return STAT_OK;
#endif
return 0;
#else /* !(defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)) */
return -1;
#endif /* !(defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)) */
}
@ -1049,6 +1116,7 @@ int xiocheckpeer(xiosingle_t *xfd,
#if WITH_IP4
if (xfd->para.socket.dorange) {
if (pa == NULL) { return -1; }
if (xiocheckrange(pa, &xfd->para.socket.range) < 0) {
char infobuff[256];
Warn1("refusing connection from %s due to range option",
@ -1064,6 +1132,7 @@ int xiocheckpeer(xiosingle_t *xfd,
#if WITH_TCP || WITH_UDP
if (xfd->para.socket.ip.dosourceport) {
if (pa == NULL) { return -1; }
#if WITH_IP4
if (pa->soa.sa_family == AF_INET &&
ntohs(((struct sockaddr_in *)pa)->sin_port) != xfd->para.socket.ip.sourceport) {
@ -1086,6 +1155,7 @@ int xiocheckpeer(xiosingle_t *xfd,
sockaddr_info((struct sockaddr *)pa, 0,
infobuff, sizeof(infobuff)));
} else if (xfd->para.socket.ip.lowport) {
if (pa == NULL) { return -1; }
if (pa->soa.sa_family == AF_INET &&
ntohs(((struct sockaddr_in *)pa)->sin_port) >= IPPORT_RESERVED) {
Warn1("refusing connection from %s due to lowport option",
@ -1127,4 +1197,177 @@ int xiocheckpeer(xiosingle_t *xfd,
return 0; /* permitted */
}
/* 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 is *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
*/
static int
xiolog_ancillary_socket(struct cmsghdr *cmsg, int *num,
char *typbuff, int typlen,
char *nambuff, int namlen,
char *envbuff, int envlen,
char *valbuff, int vallen) {
const char *cmsgtype, *cmsgname, *cmsgenvn;
size_t msglen;
struct timeval *tv;
#if defined(CMSG_DATA)
msglen = cmsg->cmsg_len-((char *)CMSG_DATA(cmsg)-(char *)cmsg);
switch (cmsg->cmsg_type) {
#ifdef SO_PASSCRED
case SO_PASSCRED: /* this is really a UNIX/LOCAL message */
/*! needs implementation */
#endif /* SO_PASSCRED */
#ifdef SO_RIGHTS
case SO_RIGHTS: /* this is really a UNIX/LOCAL message */
/*! needs implementation */
#endif
default: /* binary data */
snprintf(typbuff, typlen, "SOCKET.%u", cmsg->cmsg_type);
strncpy(nambuff, "data", namlen);
xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
return STAT_OK;
#ifdef SO_TIMESTAMP
# ifdef SCM_TIMESTAMP
case SCM_TIMESTAMP:
# else
case SO_TIMESTAMP:
# endif
tv = (struct timeval *)CMSG_DATA(cmsg);
cmsgtype =
#ifdef SCM_TIMESTAMP
"SCM_TIMESTAMP" /* FreeBSD */
#else
"SO_TIMESTAMP" /* Linux */
#endif
;
cmsgname = "timestamp";
cmsgenvn = "TIMESTAMP";
{ time_t t = tv->tv_sec; ctime_r(&t, valbuff); }
sprintf(strchr(valbuff, '\0')-1/*del \n*/, ", %06ld usecs", tv->tv_usec);
break;
#endif /* defined(SO_TIMESTAMP) */
;
}
/* when we come here we provide a single parameter
with type in cmsgtype, name in cmsgname,
and value already in valbuff */
*num = 1;
if (strlen(cmsgtype) >= typlen) Fatal("buff too short");
strncpy(typbuff, cmsgtype, typlen);
if (strlen(cmsgname) >= namlen) Fatal("buff too short");
strncpy(nambuff, cmsgname, namlen);
if (strlen(cmsgenvn) >= envlen) Fatal("buff too short");
strncpy(envbuff, cmsgenvn, envlen);
return STAT_OK;
#else /* !defined(CMSG_DATA) */
return STAT_NORETRY;
#endif /* !defined(CMSG_DATA) */
}
/* return the name of the interface with given index
or NULL if is fails
The system call requires an arbitrary socket; the calling program may
provide one in parameter ins to avoid creation of a dummy socket. ins must
be <0 if it does not specify a socket fd. */
char *xiogetifname(int ind, char *val, int ins) {
#if 0
int s;
struct ifreq ifr;
if (ins >= 0) {
s = ins;
} else {
if ((s = Socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
Error1("socket(PF_INET, SOCK_DGRAM, IPPROTO_IP): %s", strerror(errno));
return NULL;
}
}
#if HAVE_STRUCT_IFREQ_IFR_INDEX
ifr.ifr_index = ind;
#elif HAVE_STRUCT_IFREQ_IFR_IFINDEX
ifr.ifr_ifindex = ind;
#endif
#ifdef SIOCGIFNAME
if(Ioctl(s, SIOCGIFNAME, &ifr) < 0) {
Info3("ioctl(%d, SIOCGIFNAME, {..., ifr_ifindex=%d, ...}: %s",
s, ifr.ifr_ifindex, strerror(errno));
if (ins < 0) Close(s);
return NULL;
}
#endif /* SIOCGIFNAME */
if (ins < 0) Close(s);
strcpy(val, ifr.ifr_name);
return val;
#else /* ! 0 */
return if_indextoname(ind, val);
#endif
}
/* set environment variables describing (part of) a socket address, e.g.
SOCAT_SOCKADDR. lr (local/remote) specifies a string like "SOCK" or "PEER".
proto should correspond to the third parameter of socket(2) and is used to
determine the presence of port information. */
int xiosetsockaddrenv(const char *lr,
union sockaddr_union *sau, socklen_t salen,
int proto) {
# define XIOSOCKADDRENVLEN 256
char namebuff[XIOSOCKADDRENVLEN];
char valuebuff[XIOSOCKADDRENVLEN];
int idx = 0, result;
strcpy(namebuff, lr);
switch (sau->soa.sa_family) {
case PF_UNIX:
result =
xiosetsockaddrenv_unix(idx, strchr(namebuff, '\0'), XIOSOCKADDRENVLEN-strlen(lr),
valuebuff, XIOSOCKADDRENVLEN,
&sau->un, salen, proto);
xiosetenv(namebuff, valuebuff, 1);
break;
case PF_INET:
do {
result =
xiosetsockaddrenv_ip4(idx, strchr(namebuff, '\0'), XIOSOCKADDRENVLEN-strlen(lr),
valuebuff, XIOSOCKADDRENVLEN,
&sau->ip4, proto);
xiosetenv(namebuff, valuebuff, 1);
namebuff[strlen(lr)] = '\0'; ++idx;
} while (result > 0);
break;
case PF_INET6:
strcpy(namebuff, lr);
do {
result =
xiosetsockaddrenv_ip6(idx, strchr(namebuff, '\0'), XIOSOCKADDRENVLEN-strlen(lr),
valuebuff, XIOSOCKADDRENVLEN,
&sau->ip6, proto);
xiosetenv(namebuff, valuebuff, 1);
namebuff[strlen(lr)] = '\0'; ++idx;
} while (result > 0);
break;
#if LATER
case PF_PACKET:
result = xiosetsockaddrenv_packet(lr, (void *)sau, proto); break;
#endif
default:
result = -1;
break;
}
return result;
# undef XIOSOCKADDRENVLEN
}
#endif /* _WITH_SOCKET */

View file

@ -1,5 +1,5 @@
/* source: xio-socket.h */
/* Copyright Gerhard Rieger 2001-2006 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_socket_h_included
@ -31,6 +31,7 @@ extern const struct optdesc opt_so_detach_filter;
extern const struct optdesc opt_so_bindtodevice;
extern const struct optdesc opt_so_bsdcompat;
extern const struct optdesc opt_so_cksumrecv;
extern const struct optdesc opt_so_timestamp;
extern const struct optdesc opt_so_kernaccept;
extern const struct optdesc opt_so_no_check;
extern const struct optdesc opt_so_noreuseaddr;
@ -51,6 +52,10 @@ extern const struct optdesc opt_siocspgrp;
extern const struct optdesc opt_bind;
extern const struct optdesc opt_protocol_family;
extern
char *xiogetifname(int ind, char *val, int ins);
extern int retropt_socket_pf(struct opt *opts, int *pf);
extern int xioopen_connect(struct single *fd,
@ -81,10 +86,14 @@ int _xioopen_dgram_recv(struct single *xfd, int xioflags,
struct sockaddr *us, socklen_t uslen,
struct opt *opts, int pf, int socktype, int proto,
int level);
extern
int xiodopacketinfo(struct msghdr *msgh, bool withlog, bool withenv);
extern
int xiogetpacketsrc(int fd, union sockaddr_union *pa, socklen_t *palen);
int xiogetpacketsrc(int fd, struct msghdr *msgh);
extern
int xiocheckpeer(xiosingle_t *xfd,
union sockaddr_union *pa, union sockaddr_union *la);
extern
int xiosetsockaddrenv(const char *lr, union sockaddr_union *sau, socklen_t salen, int proto);
#endif /* !defined(__xio_socket_h_included) */

View file

@ -170,30 +170,25 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
#if WITH_RETRY
if (dofork) {
pid_t pid;
while ((pid = Fork()) < 0) {
int level = E_ERROR;
if (xfd->forever || xfd->retry) {
level = E_WARN;
}
Msg1(level, "fork(): %s", strerror(errno));
if (xfd->forever || xfd->retry--) {
int level = E_ERROR;
if (xfd->forever || xfd->retry) {
level = E_WARN; /* most users won't expect a problem here,
so Notice is too weak */
}
while ((pid = xio_fork(false, level)) < 0) {
if (xfd->forever || --xfd->retry) {
Nanosleep(&xfd->intervall, NULL);
continue;
}
return STAT_RETRYLATER;
}
if (pid == 0) { /* child process */
Info1("just born: socks client process "F_pid, Getpid());
/* drop parents locks, reset FIPS... */
if (xio_forked_inchild() != 0) {
Exit(1);
}
if (pid == 0) { /* child process */
xfd->forever = false; xfd->retry = 0;
break;
}
/* parent process */
Notice1("forked off child process "F_pid, pid);
Close(xfd->fd);
Nanosleep(&xfd->intervall, NULL);
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);

View file

@ -1,5 +1,5 @@
/* source: xio-tcpwrap.c */
/* Copyright Gerhard Rieger 2006-2007 */
/* Copyright Gerhard Rieger 2006-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for tcpwrapper handling stuff */
@ -93,6 +93,7 @@ int xio_tcpwrap_check(xiosingle_t *xfd, union sockaddr_union *us,
if (!xfd->para.socket.ip.dolibwrap) {
return 0;
}
if (us == NULL || them == NULL) { return -1; }
#if defined(HAVE_HOSTS_ALLOW_TABLE)
save_hosts_allow_table = hosts_allow_table;

View file

@ -238,26 +238,21 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)));
if (dofork) {
pid = Fork();
pid = xio_fork(false, E_ERROR);
if (pid < 0) {
Error1("fork(): %s", strerror(errno));
return STAT_RETRYLATER;
}
if (pid == 0) { /* child */
/* drop parents locks, reset FIPS... */
if (xio_forked_inchild() != 0) {
Exit(1);
}
if (pid == 0) { /* child */
break;
}
/* server: continue loop with socket()+recvfrom() */
/* when we dont close this we get awkward behaviour on Linux 2.4:
recvfrom gives 0 bytes with invalid socket address */
if (Close(fd->stream.fd) < 0) {
Info2("close(%d): %s", fd->stream.fd, strerror(errno));
}
Notice1("forked off child process "F_pid, pid);
Sleep(1); /*! give child a chance to consume the old packet */
continue;
@ -274,6 +269,14 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
return STAT_RETRYLATER;
}
/* set the env vars describing the local and remote sockets */
if (Getsockname(fd->stream.fd, &us.soa, &uslen) < 0) {
Warn4("getsockname(%d, %p, {%d}): %s",
fd->stream.fd, &us.soa, uslen, strerror(errno));
}
xiosetsockaddrenv("SOCK", &us, uslen, IPPROTO_UDP);
xiosetsockaddrenv("PEER", them, themlen, IPPROTO_UDP);
fd->stream.howtoend = END_SHUTDOWN;
applyopts_fchown(fd->stream.fd, opts);
applyopts(fd->stream.fd, opts, PH_LATE);

View file

@ -1,5 +1,5 @@
/* source: xio-unix.c */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of UNIX socket type */
@ -741,4 +741,25 @@ static int xioopen_abstract_client(int argc, const char *argv[], struct opt *opt
#endif /* WITH_ABSTRACT_UNIXSOCKET */
/* 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 path into
valuebuff, and returns 0 (which means that no more info is there).
if idx is != 0, it returns -1
namelen and valuelen contain the max. allowed length of output chars in the
respective buffer.
on error this function returns -1.
*/
int
xiosetsockaddrenv_unix(int idx, char *namebuff, size_t namelen,
char *valuebuff, size_t valuelen,
struct sockaddr_un *sa, socklen_t salen, int ipproto) {
if (idx != 0) {
return -1;
}
strcpy(namebuff, "ADDR");
sockaddr_unix_info(sa, salen, valuebuff, valuelen);
return 0;
}
#endif /* WITH_UNIX */

View file

@ -1,5 +1,5 @@
/* source: xio-unix.h */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_unix_h_included
@ -25,5 +25,9 @@ xiosetunix(struct sockaddr_un *saun,
const char *path,
bool abstract,
bool tight);
extern int
xiosetsockaddrenv_unix(int idx, char *namebuff, size_t namelen,
char *valuebuff, size_t valuelen,
struct sockaddr_un *sa, socklen_t salen, int ipproto);
#endif /* !defined(__xio_unix_h_included) */

2
xio.h
View file

@ -375,6 +375,8 @@ extern xiofile_t *sock[XIO_MAXSOCK];
not even by external changes correctable */
extern int xioinitialize(void);
extern int xioinitialize2(void);
extern pid_t xio_fork(bool subchild, int level);
extern int xio_forked_inchild(void);
extern int xiosetopt(char what, const char *arg);
extern int xioinqopt(char what, char *arg, size_t n);

View file

@ -107,6 +107,14 @@ int xioinitialize(void) {
return 0;
}
/* call this function when option -lp (reset program name) has been applied */
int xioinitialize2(void) {
pid_t pid = Getpid();
xiosetenvulong("PID", pid, 1);
xiosetenvulong("PPID", pid, 1);
return 0;
}
/* well, this function is not for initialization, but I could not find a better
place for it
@ -162,6 +170,7 @@ static int xio_nokill(xiofile_t *sock) {
returns 0 on success or != 0 if an error occurred */
int xio_forked_inchild(void) {
int result = 0;
xiodroplocks();
#if WITH_FIPS
if (xio_reset_fips_mode() != 0) {
@ -185,3 +194,45 @@ int xio_forked_inchild(void) {
return result;
}
/* subchild != 0 means that the current process is already a child process of
the master process and thus the new sub child process should not set the
SOCAT_PID variable */
pid_t xio_fork(bool subchild, int level) {
pid_t pid;
const char *forkwaitstring;
int forkwaitsecs = 0;
if ((pid = Fork()) < 0) {
Msg1(level, "fork(): %s", strerror(errno));
return pid;
}
if (pid == 0) { /* child process */
pid_t cpid = Getpid();
Info1("just born: client process "F_pid, cpid);
if (!subchild) {
/* set SOCAT_PID to new value */
xiosetenvulong("PID", pid, 1);
}
/* gdb recommends to have env controlled sleep after fork */
if (forkwaitstring = getenv("SOCAT_FORK_WAIT")) {
forkwaitsecs = atoi(forkwaitstring);
Sleep(forkwaitsecs);
}
if (xio_forked_inchild() != 0) {
Exit(1);
}
return 0;
}
/* parent process */
Notice1("forked off child process "F_pid, pid);
/* gdb recommends to have env controlled sleep after fork */
if (forkwaitstring = getenv("SOCAT_FORK_WAIT")) {
forkwaitsecs = atoi(forkwaitstring);
Sleep(forkwaitsecs);
}
return pid;
}

View file

@ -165,6 +165,9 @@ const struct optname optionnames[] = {
#ifdef SO_AUDIT /* AIX 4.3.3 */
IF_SOCKET ("audit", &opt_so_audit)
#endif /* SO_AUDIT */
#ifdef IPV6_AUTHHDR
IF_IP6 ("authhdr", &opt_ipv6_authhdr)
#endif
IF_TUN ("automedia", &opt_iff_automedia)
#ifdef CBAUD
IF_TERMIOS("b0", &opt_b0)
@ -375,6 +378,7 @@ const struct optname optionnames[] = {
IF_SOCKET ("dontlinger", &opt_so_dontlinger)
#endif
IF_SOCKET ("dontroute", &opt_so_dontroute)
IF_IP6 ("dstopts", &opt_ipv6_dstopts)
#ifdef VDSUSP /* HP-UX */
IF_TERMIOS("dsusp", &opt_vdsusp)
#endif
@ -501,6 +505,9 @@ const struct optname optionnames[] = {
IF_ANY ("flock-nb", &opt_flock_ex_nb)
IF_ANY ("flock-sh", &opt_flock_sh)
IF_ANY ("flock-sh-nb", &opt_flock_sh_nb)
#endif
#ifdef IPV4_FLOWINFO
IF_IP6 ("flowinfo", &opt_ipv6_flowinfo)
#endif
IF_TERMIOS("flusho", &opt_flusho)
IF_RETRY ("forever", &opt_forever)
@ -528,6 +535,8 @@ const struct optname optionnames[] = {
#endif
IF_READLINE("history", &opt_history_file)
IF_READLINE("history-file", &opt_history_file)
IF_IP6 ("hoplimit", &opt_ipv6_hoplimit)
IF_IP6 ("hopopts", &opt_ipv6_hopopts)
#if WITH_LIBWRAP && defined(HAVE_HOSTS_ALLOW_TABLE)
IF_IPAPP ("hosts-allow", &opt_tcpwrap_hosts_allow_table)
#endif
@ -614,9 +623,15 @@ const struct optname optionnames[] = {
#ifdef IP_PKTOPTIONS
IF_IP ("ip-pktoptions", &opt_ip_pktoptions)
#endif
#ifdef IP_RECVDSTADDR
IF_IP ("ip-recvdstaddr", &opt_ip_recvdstaddr)
#endif
#ifdef IP_RECVERR
IF_IP ("ip-recverr", &opt_ip_recverr)
#endif
#ifdef IP_RECVIF
IF_IP ("ip-recvif", &opt_ip_recvif)
#endif
#ifdef IP_RECVOPTS
IF_IP ("ip-recvopts", &opt_ip_recvopts)
#endif
@ -657,6 +672,9 @@ const struct optname optionnames[] = {
#ifdef IP_PKTOPTIONS
IF_IP ("ippktoptions", &opt_ip_pktoptions)
#endif
#ifdef IP_RECVDSTADDR
IF_IP ("iprecvdstaddr", &opt_ip_recvdstaddr)
#endif
#ifdef IP_RECVERR
IF_IP ("iprecverr", &opt_ip_recverr)
#endif
@ -678,7 +696,32 @@ const struct optname optionnames[] = {
IF_IP ("iptos", &opt_ip_tos)
IF_IP ("ipttl", &opt_ip_ttl)
IF_IP6 ("ipv6-add-membership", &opt_ipv6_join_group)
#ifdef IPV6_AUTHHDR
IF_IP6 ("ipv6-authhdr", &opt_ipv6_authhdr)
#endif
IF_IP6 ("ipv6-dstopts", &opt_ipv6_dstopts)
#ifdef IPV4_FLOWINFO
IF_IP6 ("ipv6-flowinfo", &opt_ipv6_flowinfo)
#endif
IF_IP6 ("ipv6-hoplimit", &opt_ipv6_hoplimit)
IF_IP6 ("ipv6-hopopts", &opt_ipv6_hopopts)
IF_IP6 ("ipv6-join-group", &opt_ipv6_join_group)
IF_IP6 ("ipv6-pktinfo", &opt_ipv6_pktinfo)
IF_IP6 ("ipv6-recvdstopts", &opt_ipv6_recvdstopts)
#ifdef IPV6_RECVERR
IF_IP6 ("ipv6-recverr", &opt_ipv6_recverr)
#endif
IF_IP6 ("ipv6-recvhoplimit", &opt_ipv6_recvhoplimit)
IF_IP6 ("ipv6-recvhopopts", &opt_ipv6_recvhopopts)
#ifdef IPV6_PATHMTU
IF_IP6 ("ipv6-recvpathmtu", &opt_ipv6_recvpathmtu)
#endif
IF_IP6 ("ipv6-recvpktinfo", &opt_ipv6_recvpktinfo)
IF_IP6 ("ipv6-recvrthdr", &opt_ipv6_recvrthdr)
IF_IP6 ("ipv6-recvtclass", &opt_ipv6_recvtclass)
IF_IP6 ("ipv6-rthdr", &opt_ipv6_rthdr)
IF_IP6 ("ipv6-tclass", &opt_ipv6_tclass)
IF_IP6 ("ipv6-unicast-hops", &opt_ipv6_unicast_hops)
#ifdef IPV6_V6ONLY
IF_IP6 ("ipv6-v6only", &opt_ipv6_v6only)
IF_IP6 ("ipv6only", &opt_ipv6_v6only)
@ -1087,12 +1130,23 @@ const struct optname optionnames[] = {
#if HAVE_RESOLV_H
IF_IP ("recurse", &opt_res_recurse)
#endif /* HAVE_RESOLV_H */
#ifdef IP_RECVDSTADDR
IF_IP ("recvdstaddr", &opt_ip_recvdstaddr)
#endif
IF_IP6 ("recvdstopts", &opt_ipv6_recvdstopts)
#ifdef IP_RECVERR
IF_IP ("recverr", &opt_ip_recverr)
#endif
IF_IP6 ("recvhoplimit", &opt_ipv6_recvhoplimit)
IF_IP6 ("recvhopopts", &opt_ipv6_recvhopopts)
#ifdef IP_RECVIF
IF_IP ("recvif", &opt_ip_recvif)
#endif
#ifdef IP_RECVOPTS
IF_IP ("recvopts", &opt_ip_recvopts)
#endif
IF_IP6 ("recvpktinfo", &opt_ipv6_recvpktinfo)
IF_IP6 ("recvrthdr", &opt_ipv6_recvrthdr)
#ifdef IP_RECVTOS
IF_IP ("recvtos", &opt_ip_recvtos)
#endif
@ -1139,6 +1193,7 @@ const struct optname optionnames[] = {
#ifdef O_RSYNC
IF_OPEN ("rsync", &opt_o_rsync)
#endif
IF_IP6 ("rthdr", &opt_ipv6_rthdr)
IF_TUN ("running", &opt_iff_running)
#ifdef TCP_SACK_DISABLE
IF_TCP ("sack-disable", &opt_tcp_sack_disable)
@ -1297,6 +1352,9 @@ const struct optname optionnames[] = {
#endif
#ifdef SO_SNDTIMEO
IF_SOCKET ("so-sndtimeo", &opt_so_sndtimeo)
#endif
#ifdef SO_TIMESTAMP
IF_SOCKET ("so-timestamp", &opt_so_timestamp)
#endif
IF_SOCKET ("so-type", &opt_so_type)
#ifdef SO_USE_IFBUFS
@ -1446,6 +1504,9 @@ const struct optname optionnames[] = {
#endif
IF_UNIX ("tightsocklen", &opt_unix_tightsocklen)
IF_TERMIOS("time", &opt_vtime)
#ifdef SO_TIMESTAMP
IF_SOCKET ("timestamp", &opt_so_timestamp)
#endif
IF_TERMIOS("tiocsctty", &opt_tiocsctty)
#if WITH_EXT2 && defined(EXT2_TOPDIR_FL)
IF_ANY ("topdir", &opt_ext2_topdir)
@ -1471,6 +1532,7 @@ const struct optname optionnames[] = {
IF_NAMED ("uid-e", &opt_user_early)
IF_ANY ("uid-l", &opt_user_late)
IF_NAMED ("umask", &opt_umask)
IF_IP6 ("unicast-hops", &opt_ipv6_unicast_hops)
IF_UNIX ("unix-tightsocklen", &opt_unix_tightsocklen)
IF_NAMED ("unlink", &opt_unlink)
IF_NAMED ("unlink-close", &opt_unlink_close)
@ -1713,7 +1775,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
(*opts)[i].value.u_bin.b_len = optlen;
break;
case TYPE_BYTE:
{
if (assign) {
unsigned long ul;
char *rest;
ul = strtoul(token, &rest/*!*/, 0);
@ -1722,11 +1784,13 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
a0, ul, UCHAR_MAX);
(*opts)[i].value.u_byte = UCHAR_MAX;
} else {
Info2("setting option \"%s\" to %d", ent->desc->defname,
(*opts)[i].value.u_byte);
(*opts)[i].value.u_byte = ul;
}
} else {
(*opts)[i].value.u_byte = 1;
}
Info2("setting option \"%s\" to %d", ent->desc->defname,
(*opts)[i].value.u_byte);
break;
case TYPE_INT:
if (assign) {

View file

@ -327,7 +327,24 @@ enum e_optcode {
OPT_INLCR, /* termios.c_iflag */
OPT_INPCK, /* termios.c_iflag */
OPT_INTERVALL,
OPT_IPV6_AUTHHDR,
OPT_IPV6_DSTOPTS,
OPT_IPV6_FLOWINFO,
OPT_IPV6_HOPLIMIT,
OPT_IPV6_HOPOPTS,
OPT_IPV6_JOIN_GROUP,
OPT_IPV6_PKTINFO,
OPT_IPV6_RECVDSTOPTS,
OPT_IPV6_RECVERR,
OPT_IPV6_RECVHOPLIMIT,
OPT_IPV6_RECVHOPOPTS,
OPT_IPV6_RECVPATHMTU,
OPT_IPV6_RECVPKTINFO,
OPT_IPV6_RECVRTHDR,
OPT_IPV6_RECVTCLASS,
OPT_IPV6_RTHDR,
OPT_IPV6_TCLASS,
OPT_IPV6_UNICAST_HOPS,
OPT_IPV6_V6ONLY,
#if 0 /* see Linux: man 7 netlink; probably not what we need yet */
OPT_IO_SIOCGIFNAME,
@ -355,9 +372,11 @@ enum e_optcode {
#ifdef IP_PKTOPTIONS
OPT_IP_PKTOPTIONS,
#endif
OPT_IP_RECVDSTADDR,
#ifdef IP_RECVERR
OPT_IP_RECVERR,
#endif
OPT_IP_RECVIF,
#ifdef IP_RECVOPTS
OPT_IP_RECVOPTS,
#endif
@ -628,6 +647,7 @@ enum e_optcode {
#ifdef SO_SNDTIMEO
OPT_SO_SNDTIMEO,
#endif
OPT_SO_TIMESTAMP, /* Linux */
OPT_SO_TYPE,
#ifdef SO_USELOOPBACK
OPT_SO_USELOOPBACK,

View file

@ -113,10 +113,23 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
case XIOREAD_RECV:
if (pipe->dtype & XIOREAD_RECV_FROM) {
#if WITH_RAWIP || WITH_UDP || WITH_UNIX
struct msghdr msgh = {0};
union sockaddr_union from = {{0}};
socklen_t fromlen = sizeof(from);
char infobuff[256];
char ctrlbuff[1024]; /* ancillary messages */
msgh.msg_name = &from;
msgh.msg_namelen = fromlen;
#if HAVE_STRUCT_MSGHDR_MSGCONTROL
msgh.msg_control = ctrlbuff;
#endif
#if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
msgh.msg_controllen = sizeof(ctrlbuff);
#endif
if (xiogetpacketsrc(pipe->fd, &msgh) < 0) {
return -1;
}
do {
bytes =
Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen);
@ -283,12 +296,23 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
} else /* ~XIOREAD_RECV_FROM */ {
union sockaddr_union from; socklen_t fromlen = sizeof(from);
char infobuff[256];
struct msghdr msgh = {0};
char ctrlbuff[1024]; /* ancillary messages */
socket_init(pipe->para.socket.la.soa.sa_family, &from);
/* get source address */
if (xiogetpacketsrc(pipe->fd, &from, &fromlen) < 0) {
return STAT_RETRYNOW;
msgh.msg_name = &from;
msgh.msg_namelen = fromlen;
#if HAVE_STRUCT_MSGHDR_MSGCONTROL
msgh.msg_control = ctrlbuff;
#endif
#if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
msgh.msg_controllen = sizeof(ctrlbuff);
#endif
if (xiogetpacketsrc(pipe->fd, &msgh) < 0) {
return -1;
}
xiodopacketinfo(&msgh, true, false);
if (xiocheckpeer(pipe, &from, &pipe->para.socket.la) < 0) {
Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen); /* drop */
errno = EAGAIN; return -1;