diff --git a/CHANGES b/CHANGES
index 042c977..f402c88 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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
diff --git a/README b/README
index 6baad77..d92eb4a 100644
--- a/README
+++ b/README
@@ -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.
diff --git a/VERSION b/VERSION
index f509df5..f881903 100644
--- a/VERSION
+++ b/VERSION
@@ -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"
diff --git a/config.h.in b/config.h.in
index 2e330da..0d8c9cc 100644
--- a/config.h.in
+++ b/config.h.in
@@ -224,6 +224,15 @@
/* Define if you have the header file. */
#undef HAVE_NET_IF_H
+/* Define if you have the header file. */
+#undef HAVE_NET_IF_DL_H
+
+/* Define if you have the header file. */
+#undef HAVE_LINUX_TYPES_H
+
+/* Define if you have the header file. */
+#undef HAVE_LINUX_ERRQUEUE_H
+
/* Define if you have the 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
diff --git a/configure.in b/configure.in
index a0a3d80..013a2c3 100644
--- a/configure.in
+++ b/configure.in
@@ -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
+#include
+#include ],[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,
diff --git a/doc/socat-multicast.html b/doc/socat-multicast.html
index fc31f7b..829eba3 100644
--- a/doc/socat-multicast.html
+++ b/doc/socat-multicast.html
@@ -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.
+to a unicast, multicast, or broadcast address.
Authentication or encryption are not available.
diff --git a/doc/socat.yo b/doc/socat.yo
index d422aef..a432e90 100644
--- a/doc/socat.yo
+++ b/doc/socat.yo
@@ -127,7 +127,8 @@ dit(bf(tt(-lf))tt( ))
dit(bf(tt(-ls)))
Writes messages to stderr (this is the default).
label(option_lp)dit(bf(tt(-lp))tt())
- Overrides the program name printed in error messages.
+ 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::)))
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::)))
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::)))
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::)))
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=)))
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=)))
Forces the use of the specified IP version. 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=)))
label(OPTION_TTL)dit(bf(tt(ttl=)))
Sets the TTL (time to live) field of outgoing packets to
[link(byte)(TYPE_BYTE)].
-label(OPTION_IPOPTIONS)dit(bf(tt(ipoptions=)))
+label(OPTION_IPOPTIONS)dit(bf(tt(ip-options=)))
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=)))
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)())))
+ 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.
diff --git a/hostan.c b/hostan.c
index 8862bf5..19829b2 100644
--- a/hostan.c
+++ b/hostan.c
@@ -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 */
diff --git a/socat.c b/socat.c
index 3ff3d17..28698bf 100644
--- a/socat.c
+++ b/socat.c
@@ -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);
diff --git a/sycls.c b/sycls.c
index 347a7cb..4ab902c 100644
--- a/sycls.c
+++ b/sycls.c
@@ -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) {
diff --git a/sycls.h b/sycls.h
index 8166d96..03ecff0 100644
--- a/sycls.h
+++ b/sycls.h
@@ -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()
diff --git a/sysincludes.h b/sysincludes.h
index f233358..6d053b9 100644
--- a/sysincludes.h
+++ b/sysincludes.h
@@ -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 /* req for resolv.h (esp. on MacOSX) */
#endif
#include
+#if HAVE_NET_IF_DL_H
+#include /* FreeBSD: struct sockaddr_dl */
+#endif
#if HAVE_RESOLV_H
#include /* _res */
#endif
@@ -116,6 +119,12 @@
#if HAVE_NET_IF_H
#include
#endif /* HAVE_NET_IF_H */
+#if HAVE_LINUX_TYPES_H
+#include /* __u32 for linux/errqueue.h */
+#endif
+#if HAVE_LINUX_ERRQUEUE_H
+#include /* struct sock_extended_err */
+#endif
#if HAVE_LINUX_IF_TUN_H
#include
#endif
diff --git a/sysutils.c b/sysutils.c
index 28ccae9..4a27fe9 100644
--- a/sysutils.c
+++ b/sysutils.c
@@ -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
+}
diff --git a/sysutils.h b/sysutils.h
index b9074b3..33cfc45 100644
--- a/sysutils.h
+++ b/sysutils.h
@@ -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) */
diff --git a/test.sh b/test.sh
index 054673f..61455f8 100755
--- a/test.sh
+++ b/test.sh
@@ -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
diff --git a/utils.c b/utils.c
index eeca60c..57904d9 100644
--- a/utils.c
+++ b/utils.c
@@ -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;
+}
+
diff --git a/utils.h b/utils.h
index 4488358..f942db1 100644
--- a/utils.h
+++ b/utils.h
@@ -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) */
-
diff --git a/xio-ascii.c b/xio-ascii.c
index 88909dc..7cd8103 100644
--- a/xio-ascii.c
+++ b/xio-ascii.c
@@ -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;
+}
diff --git a/xio-ascii.h b/xio-ascii.h
index 875623d..bcb760f 100644
--- a/xio-ascii.h
+++ b/xio-ascii.h
@@ -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) */
diff --git a/xio-ip.c b/xio-ip.c
index 77dd71d..f04d1fa 100644
--- a/xio-ip.c
+++ b/xio-ip.c
@@ -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 */
diff --git a/xio-ip.h b/xio-ip.h
index 4d68012..6522f49 100644
--- a/xio-ip.h
+++ b/xio-ip.h
@@ -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) */
diff --git a/xio-ip4.c b/xio-ip4.c
index 6e8ff23..27b9128 100644
--- a/xio-ip4.c
+++ b/xio-ip4.c
@@ -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 */
diff --git a/xio-ip4.h b/xio-ip4.h
index 9357dcc..15aefed 100644
--- a/xio-ip4.h
+++ b/xio-ip4.h
@@ -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) */
diff --git a/xio-ip6.c b/xio-ip6.c
index 0bf8577..870e80e 100644
--- a/xio-ip6.c
+++ b/xio-ip6.c
@@ -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 */
diff --git a/xio-ip6.h b/xio-ip6.h
index 431d4d1..2e86725 100644
--- a/xio-ip6.h
+++ b/xio-ip6.h
@@ -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 */
diff --git a/xio-ipapp.c b/xio-ipapp.c
index 1a3effd..213a76f 100644
--- a/xio-ipapp.c
+++ b/xio-ipapp.c
@@ -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;
diff --git a/xio-listen.c b/xio-listen.c
index 38a65c6..0acb3dd 100644
--- a/xio-listen.c
+++ b/xio-listen.c
@@ -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;
}
diff --git a/xio-openssl.c b/xio-openssl.c
index 4fa17bc..d03f291 100644
--- a/xio-openssl.c
+++ b/xio-openssl.c
@@ -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;
diff --git a/xio-progcall.c b/xio-progcall.c
index 0c9f8ed..a9f151e 100644
--- a/xio-progcall.c
+++ b/xio-progcall.c
@@ -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;
diff --git a/xio-proxy.c b/xio-proxy.c
index 23ab032..f5d1f38 100644
--- a/xio-proxy.c
+++ b/xio-proxy.c
@@ -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);
diff --git a/xio-socket.c b/xio-socket.c
index d93bb98..669925c 100644
--- a/xio-socket.c
+++ b/xio-socket.c
@@ -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 */
diff --git a/xio-socket.h b/xio-socket.h
index 04734f9..6277bd9 100644
--- a/xio-socket.h
+++ b/xio-socket.h
@@ -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) */
diff --git a/xio-socks.c b/xio-socks.c
index 71c0ded..9efa675 100644
--- a/xio-socks.c
+++ b/xio-socks.c
@@ -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);
diff --git a/xio-tcpwrap.c b/xio-tcpwrap.c
index 2029ed2..20d482b 100644
--- a/xio-tcpwrap.c
+++ b/xio-tcpwrap.c
@@ -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;
diff --git a/xio-udp.c b/xio-udp.c
index 293b8be..f2bff42 100644
--- a/xio-udp.c
+++ b/xio-udp.c
@@ -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);
diff --git a/xio-unix.c b/xio-unix.c
index b0c6b95..acfc6a6 100644
--- a/xio-unix.c
+++ b/xio-unix.c
@@ -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 */
diff --git a/xio-unix.h b/xio-unix.h
index 9b09efe..8050bab 100644
--- a/xio-unix.h
+++ b/xio-unix.h
@@ -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) */
diff --git a/xio.h b/xio.h
index 930d6bd..598e8ba 100644
--- a/xio.h
+++ b/xio.h
@@ -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);
diff --git a/xioinitialize.c b/xioinitialize.c
index 81c6a29..d04ad71 100644
--- a/xioinitialize.c
+++ b/xioinitialize.c
@@ -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;
+}
diff --git a/xioopts.c b/xioopts.c
index dfbb1ef..2ac62c8 100644
--- a/xioopts.c
+++ b/xioopts.c
@@ -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) {
diff --git a/xioopts.h b/xioopts.h
index 81ff412..0f11223 100644
--- a/xioopts.h
+++ b/xioopts.h
@@ -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,
diff --git a/xioread.c b/xioread.c
index 5db886c..d8bb574 100644
--- a/xioread.c
+++ b/xioread.c
@@ -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;