mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 15:32:35 +00:00
merged features ancillary, envvar
This commit is contained in:
parent
bd3810642b
commit
2ffe5a324e
42 changed files with 1898 additions and 287 deletions
33
CHANGES
33
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
|
||||
|
|
12
README
12
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.
|
||||
|
|
2
VERSION
2
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"
|
||||
|
|
12
config.h.in
12
config.h.in
|
@ -224,6 +224,15 @@
|
|||
/* Define if you have the <net/if.h> header file. */
|
||||
#undef HAVE_NET_IF_H
|
||||
|
||||
/* Define if you have the <net/if_dl.h> header file. */
|
||||
#undef HAVE_NET_IF_DL_H
|
||||
|
||||
/* Define if you have the <linux/types.h> header file. */
|
||||
#undef HAVE_LINUX_TYPES_H
|
||||
|
||||
/* Define if you have the <linux/errqueue.h> header file. */
|
||||
#undef HAVE_LINUX_ERRQUEUE_H
|
||||
|
||||
/* Define if you have the <linux/if_tun.h> header file. */
|
||||
#undef HAVE_LINUX_IF_TUN_H
|
||||
|
||||
|
@ -334,6 +343,9 @@
|
|||
/* define if your struct msghdr has msg_flag */
|
||||
#undef HAVE_STRUCT_MSGHDR_MSGFLAGS
|
||||
|
||||
/* define if you have struct cmsghdr */
|
||||
#undef HAVE_STRUCT_CMSGHDR
|
||||
|
||||
/* define if your struct ip has ip_hl; otherwise assume ip_vhl */
|
||||
#undef HAVE_STRUCT_IP_IP_HL
|
||||
|
||||
|
|
15
configure.in
15
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 <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>],[struct cmsghdr s;],
|
||||
[sc_cv_struct_cmsghdr=yes],
|
||||
[sc_cv_struct_cmsghdr=no])])
|
||||
if test $sc_cv_struct_cmsghdr = yes; then
|
||||
AC_DEFINE(HAVE_STRUCT_CMSGHDR)
|
||||
fi
|
||||
AC_MSG_RESULT($sc_cv_struct_cmsghdr)
|
||||
|
||||
dnl check for ip_hl in struct ip
|
||||
AC_MSG_CHECKING(for struct ip.ip_hl)
|
||||
AC_CACHE_VAL(sc_cv_struct_ip_ip_hl,
|
||||
|
|
|
@ -240,8 +240,7 @@ interfaces. This membership cannot be dropped on Linux.
|
|||
sockets without exception accept packets that are directly addressed to them;
|
||||
the multi- and broadcast receiving features are just extensions to the normal
|
||||
functionality. socat has no way to find out if an incoming packet is addressed
|
||||
to a unicast, multicast or broadcast address. Please contact the author if you
|
||||
know how the target address can be determined.</p>
|
||||
to a unicast, multicast, or broadcast address.</p>
|
||||
|
||||
<p>Authentication or encryption are not available.</p>
|
||||
|
||||
|
|
177
doc/socat.yo
177
doc/socat.yo
|
@ -127,7 +127,8 @@ dit(bf(tt(-lf))tt( <logfile>))
|
|||
dit(bf(tt(-ls)))
|
||||
Writes messages to stderr (this is the default).
|
||||
label(option_lp)dit(bf(tt(-lp))tt(<progname>))
|
||||
Overrides the program name printed in error messages.
|
||||
Overrides the program name printed in error messages and used for
|
||||
constructing environment variable names.
|
||||
dit(bf(tt(-lu)))
|
||||
Extends the timestamp of error messages to microsecond resolution. Does not
|
||||
work when logging to syslog.
|
||||
|
@ -364,6 +365,7 @@ label(ADDRESS_IP_DATAGRAM)dit(bf(tt(IP-DATAGRAM:<address>:<protocol>)))
|
|||
Option groups: link(FD)(GROUP_FD), link(SOCKET)(GROUP_SOCKET),
|
||||
link(IP4)(GROUP_IP4), link(IP6)(GROUP_IP6), link(RANGE)(GROUP_RANGE) nl()
|
||||
Useful options:
|
||||
link(bind)(OPTION_BIND),
|
||||
link(range)(OPTION_RANGE),
|
||||
link(tcpwrap)(OPTION_TCPWRAPPERS),
|
||||
link(broadcast)(OPTION_SO_BROADCAST),
|
||||
|
@ -373,7 +375,6 @@ label(ADDRESS_IP_DATAGRAM)dit(bf(tt(IP-DATAGRAM:<address>:<protocol>)))
|
|||
link(ip-add-membership)(OPTION_IP_ADD_MEMBERSHIP),
|
||||
link(ttl)(OPTION_TTL),
|
||||
link(tos)(OPTION_TOS),
|
||||
link(bind)(OPTION_BIND),
|
||||
link(pf)(OPTION_PROTOCOL_FAMILY)nl()
|
||||
See also:
|
||||
link(IP4-DATAGRAM)(ADDRESS_IP4_DATAGRAM),
|
||||
|
@ -783,7 +784,8 @@ label(ADDRESS_UDP_DATAGRAM)dit(bf(tt(UDP-DATAGRAM:<address>:<port>)))
|
|||
options. This address type can for example be used for implementing
|
||||
symmetric or asymmetric broadcast or multicast communications.nl()
|
||||
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(RANGE)(GROUP_RANGE) nl()
|
||||
Useful options:
|
||||
Useful options:
|
||||
link(bind)(OPTION_BIND),
|
||||
link(range)(OPTION_RANGE),
|
||||
link(tcpwrap)(OPTION_TCPWRAPPERS),
|
||||
link(broadcast)(OPTION_SO_BROADCAST),
|
||||
|
@ -793,7 +795,6 @@ label(ADDRESS_UDP_DATAGRAM)dit(bf(tt(UDP-DATAGRAM:<address>:<port>)))
|
|||
link(ip-add-membership)(OPTION_IP_ADD_MEMBERSHIP),
|
||||
link(ttl)(OPTION_TTL),
|
||||
link(tos)(OPTION_TOS),
|
||||
link(bind)(OPTION_BIND),
|
||||
link(sourceport)(OPTION_SOURCEPORT),
|
||||
link(pf)(OPTION_PROTOCOL_FAMILY)nl()
|
||||
See also:
|
||||
|
@ -1543,8 +1544,8 @@ label(OPTION_INTERFACE)dit(bf(tt(interface=<interface>)))
|
|||
label(OPTION_SO_BROADCAST)dit(bf(tt(broadcast)))
|
||||
For datagram sockets, allows sending to broadcast addresses and receiving
|
||||
packets addressed to broadcast addresses.
|
||||
label(OPTION_BSDCOMPAT)dit(bf(tt(bsdcompat)))
|
||||
Emulates some (old?) bugs of the BSD socket implementation.
|
||||
COMMENT(label(OPTION_BSDCOMPAT)dit(bf(tt(bsdcompat)))
|
||||
Emulates some (old?) bugs of the BSD socket implementation.)
|
||||
label(OPTION_DEBUG)dit(bf(tt(debug)))
|
||||
Enables socket debugging.
|
||||
label(OPTION_DONTROUTE)dit(bf(tt(dontroute)))
|
||||
|
@ -1639,6 +1640,9 @@ COMMENT(label(OPTION_USEIFBUFS)dit(bf(tt(useifbufs)))
|
|||
label(OPTION_PROTOCOL_FAMILY)dit(bf(tt(pf=<string>)))
|
||||
Forces the use of the specified IP version. <string> can be
|
||||
something like "ip4" or "ip6".
|
||||
label(OPTION_SO_TIMESTAMP)dit(bf(tt(so-timestamp)))
|
||||
Sets the SO_TIMESTAMP socket option. This enables receiving and logging of
|
||||
timestamp ancillary messages.
|
||||
enddit()
|
||||
|
||||
startdit()enddit()nl()
|
||||
|
@ -1665,13 +1669,13 @@ label(OPTION_TOS)dit(bf(tt(tos=<tos>)))
|
|||
label(OPTION_TTL)dit(bf(tt(ttl=<ttl>)))
|
||||
Sets the TTL (time to live) field of outgoing packets to <ttl>
|
||||
[link(byte)(TYPE_BYTE)].
|
||||
label(OPTION_IPOPTIONS)dit(bf(tt(ipoptions=<data>)))
|
||||
label(OPTION_IPOPTIONS)dit(bf(tt(ip-options=<data>)))
|
||||
Sets IP options like source routing. Must be given in binary form,
|
||||
recommended format is a leading "x" followed by an even number of hex
|
||||
digits. This option may be used multiple times, data are appended.
|
||||
E.g., to connect to host 10.0.0.1 via some gateway using a loose source
|
||||
route, use the gateway as address parameter and set a loose source route
|
||||
using the option code(ipoptions=x8307040a000001).nl()
|
||||
using the option code(ip-options=x8307040a000001).nl()
|
||||
IP options are defined in RFC 791. COMMENT(, RFC 2113)nl()
|
||||
COMMENT( x00 end of option list
|
||||
x01 no operation (nop)
|
||||
|
@ -1690,20 +1694,32 @@ COMMENT(label(OPTION_IP_MULTICAST_LOOP)dit(bf(tt(multicastloop)))
|
|||
Allow looping back outgoing multicast to the local interface.)
|
||||
COMMENT(label(OPTION_IP_MULTICAST_TTL)dit(bf(tt(multicastttl)))
|
||||
Set the TTL for outgoing multicast packets.)
|
||||
COMMENT(label(OPTION_PKTINFO)dit(bf(tt(pktinfo)))
|
||||
Set the IP_PKTINFO socket option.)
|
||||
label(OPTION_IP_PKTINFO)dit(bf(tt(pktinfo)))
|
||||
Sets the IP_PKTINFO socket option. This enables receiving and logging of
|
||||
ancillary messages containing destination address and interface (Linux).
|
||||
COMMENT(label(OPTION_PKTOPTS)dit(bf(tt(pktopts)))
|
||||
Set the IP_PKTOPTIONS socket option.)
|
||||
COMMENT(label(OPTION_RECVERR)dit(bf(tt(recverr)))
|
||||
Set the IP_RECVERR socket option.)
|
||||
COMMENT(label(OPTION_RECVOPTS)dit(bf(tt(recvopts)))
|
||||
Set the IP_RECVOPTS socket option.)
|
||||
COMMENT(label(OPTION_RECVTOS)dit(bf(tt(recvtos)))
|
||||
Set the IP_RECVTOS socket option.)
|
||||
COMMENT(label(OPTION_RECVTTL)dit(bf(tt(recvttl)))
|
||||
Set the IP_RECVTTL socket option.)
|
||||
label(OPTION_IP_RECVERR)dit(bf(tt(recverr)))
|
||||
Sets the IP_RECVERR socket option. This enables receiving and logging of
|
||||
ancillary messages containing detailled error information.
|
||||
label(OPTION_IP_RECVOPTS)dit(bf(tt(recvopts)))
|
||||
Sets the IP_RECVOPTS socket option. This enables receiving and logging of IP
|
||||
options ancillary messages (Linux, *BSD).
|
||||
label(OPTION_IP_RECVTOS)dit(bf(tt(recvtos)))
|
||||
Sets the IP_RECVTOS socket option. This enables receiving and logging of TOS
|
||||
(type of service) ancillary messages (Linux).
|
||||
label(OPTION_IP_RECVTTL)dit(bf(tt(recvttl)))
|
||||
Sets the IP_RECVTTL socket option. This enables receiving and logging of TTL
|
||||
(time to live) ancillary messages (Linux, *BSD).
|
||||
COMMENT(label(OPTION_RETOPTS)dit(bf(tt(retopts)))
|
||||
Set the IP_RETOPTS socket option.)
|
||||
label(OPTION_IP_RECVDSTADDR)dit(bf(tt(recvdstaddr)))
|
||||
Sets the IP_RECVDSTADDR socket option. This enables receiving and logging of
|
||||
ancillary messages containing destination address
|
||||
(*BSD).
|
||||
label(OPTION_IP_RECVIF)dit(bf(tt(recvif)))
|
||||
Sets the IP_RECVIF socket option. This enables receiving and logging of
|
||||
interface ancillary messages (*BSD).
|
||||
COMMENT(label(OPTION_ROUTERALERT)dit(bf(tt(routeralert)))
|
||||
Set the IP_ROUTER_ALERT socket option.)
|
||||
label(OPTION_IP_ADD_MEMBERSHIP)
|
||||
|
@ -1758,6 +1774,30 @@ label(OPTION_IPV6_V6ONLY)dit(bf(tt(ipv6only=<bool>)))
|
|||
Sets the IPV6_V6ONLY socket option. If 0, the TCP stack will also accept
|
||||
connections using IPv4 protocol on the same port. The default is system
|
||||
dependent.
|
||||
label(OPTION_IPV6_RECVDSTOPTS)dit(bf(tt(ipv6-recvdstopts)))
|
||||
Sets the IPV6_RECVDSTOPTS socket option. This enables receiving and logging
|
||||
of ancillary messages containing the destination options.
|
||||
label(OPTION_IPV6_RECVHOPLIMIT)dit(bf(tt(ipv6-recvhoplimit)))
|
||||
Sets the IPV6_RECVHOPLIMIT socket option. This enables receiving and logging
|
||||
of ancillary messages containing the hoplimit.
|
||||
label(OPTION_IPV6_RECVHOPOPTS)dit(bf(tt(ipv6-recvhopopts)))
|
||||
Sets the IPV6_RECVHOPOPTS socket option. This enables receiving and logging
|
||||
of ancillary messages containing the hop options.
|
||||
label(OPTION_IPV6_RECVPKTINFO)dit(bf(tt(ipv6-recvpktinfo)))
|
||||
Sets the IPV6_RECVPKTINFO socket option. This enables receiving and logging
|
||||
of ancillary messages containing destination address and interface.
|
||||
label(OPTION_IPV6_UNICAST_HOPS)dit(bf(tt(ipv6-unicast-hops=link(TYPE_INT)(<int>))))
|
||||
Sets the IPV6_UNICAST_HOPS socket option. This sets the hop count limit
|
||||
(TTL) for outgoing unicast packets.
|
||||
label(OPTION_IPV6_RECVRTHDR)dit(bf(tt(ipv6-recvrthdr)))
|
||||
Sets the IPV6_RECVRTHDR socket option. This enables receiving and logging
|
||||
of ancillary messages containing routing information.
|
||||
label(OPTION_IPV6_TCLASS)dit(bf(tt(ipv6-tclass)))
|
||||
Sets the IPV6_TCLASS socket option. This sets the transfer class of outgoing
|
||||
packets.
|
||||
label(OPTION_IPV6_RECVTCLASS)dit(bf(tt(ipv6-recvtclass)))
|
||||
Sets the IPV6_RECVTCLASS socket option. This enables receiving and logging
|
||||
of ancillary messages containing the transfer class.
|
||||
enddit()
|
||||
|
||||
startdit()enddit()nl()
|
||||
|
@ -2932,45 +2972,126 @@ manpagefiles()
|
|||
label(ENVIRONMENT_VARIABLES)
|
||||
manpagesection(ENVIRONMENT VARIABLES)
|
||||
|
||||
Input variables carry information from the environment to socat, output
|
||||
variables are set by socat for use in executed scripts and programs.
|
||||
|
||||
In the output variables beginning with "SOCAT" this prefix is actually replaced
|
||||
by the upper case name of the executable or the value of option
|
||||
link(-lp)(option_lp).
|
||||
|
||||
startdit()
|
||||
dit(bf(SOCAT_DEFAULT_LISTEN_IP)) (Values 4 or 6) Sets the IP version to be used
|
||||
dit(bf(SOCAT_DEFAULT_LISTEN_IP) (input)) (Values 4 or 6) Sets the IP version to
|
||||
be used
|
||||
for listen, recv, and recvfrom addresses if no link(pf)(OPTION_PROTOCOL_FAMILY)
|
||||
(protocol-family) option is given. Is overridden by socat options
|
||||
link(-4)(option_4) or link(-6)(option_6).
|
||||
|
||||
dit(bf(SOCAT_PREFERRED_RESOLVE_IP)) (Values 0, 4, or 6) Sets the IP version to
|
||||
dit(bf(SOCAT_PREFERRED_RESOLVE_IP) (input)) (Values 0, 4, or 6) Sets the IP
|
||||
version to
|
||||
be used when resolving target host names when version is not specified by
|
||||
address type, option link(pf)(OPTION_PROTOCOL_FAMILY) (protocol-family), or
|
||||
address format. If name resolution does not return a matching entry, the first
|
||||
result (with differing IP version) is taken. With value 0, socat always selects
|
||||
the first record and its IP version.
|
||||
|
||||
dit(bf(SOCAT_FORK_WAIT)) Specifies the time (seconds) to sleep the parent and
|
||||
child processes after successful fork(). Useful for debugging.
|
||||
dit(bf(SOCAT_FORK_WAIT) (input)) Specifies the time (seconds) to sleep the
|
||||
parent and child processes after successful fork(). Useful for debugging.
|
||||
|
||||
dit(bf(HOSTNAME)) Is used to determine the hostname for logging (see
|
||||
dit(bf(SOCAT_VERSION) (output)) Socat sets this variable to its version string,
|
||||
e.g. tt("1.6.1.0") for released versions or e.g. tt("1.6.0.1+envvar") for
|
||||
temporary versions; can be used in scripts invoked by socat.
|
||||
|
||||
dit(bf(SOCAT_PID) (output)) Socat sets this variable to its process id. In case
|
||||
of link(fork)(OPTION_FORK) address option, SOCAT_PID gets the child processes
|
||||
id. Forking for link(exec)(ADDRESS_EXEC) and link(system)(ADDRESS_SYSTEM) does
|
||||
not change SOCAT_PID.
|
||||
|
||||
dit(bf(SOCAT_PPID) (output)) Socat sets this variable to its process id. In
|
||||
case of link(fork)(OPTION_FORK), SOCAT_PPID keeps the pid of the master process.
|
||||
|
||||
dit(bf(SOCAT_PEERADDR) (output)) With passive socket addresses (all LISTEN and
|
||||
RECVFROM addresses), this variable is set to a string describing the peers
|
||||
socket address. Port information is not included.
|
||||
|
||||
dit(bf(SOCAT_PEERPORT) (output)) With appropriate passive socket addresses (TCP
|
||||
and UDP - LISTEN and RECVFROM), this variable is set to a string containing the
|
||||
number of the peer port.
|
||||
|
||||
dit(bf(SOCAT_SOCKADDR) (output)) With all LISTEN addresses, this variable is
|
||||
set to a string describing the local socket address. Port information is not
|
||||
included.
|
||||
|
||||
dit(bf(SOCAT_SOCKPORT) (output)) With TCP-LISTEN and UDP-LISTEN addresses, this
|
||||
variable is set to the local port.
|
||||
|
||||
dit(bf(SOCAT_TIMESTAMP) (output)) With all RECVFROM addresses where address
|
||||
option link(so-timestamp)(OPTION_SO_TIMESTAMP) is applied, socat sets this
|
||||
variable to the resulting timestamp.
|
||||
|
||||
dit(bf(SOCAT_IP_OPTIONS) (output)) With all IPv4 based RECVFROM addresses where
|
||||
address option link(ip-recvopts)(OPTION_IP_RECVOPTS) is applied, socat fills
|
||||
this variable with the IP options of the received packet.
|
||||
|
||||
dit(bf(SOCAT_IP_DSTADDR) (output)) With all IPv4 based RECVFROM addresses where
|
||||
address option link(ip-recvdstaddr)(OPTION_IP_RECVDSTADDR) (BSD) or
|
||||
link(ip-pktinfo)(OPTION_IP_PKTINFO) (other platforms) is applied, socat sets
|
||||
this variable to the destination address of the received packet. This is
|
||||
particularly useful to identify broadcast and multicast addressed packets.
|
||||
|
||||
dit(bf(SOCAT_IP_IF) (output)) With all IPv4 based RECVFROM addresses where
|
||||
address option link(ip-recvif)(OPTION_IP_RECVIF) (BSD) or
|
||||
link(ip-pktinfo)(OPTION_IP_PKTINFO) (other platforms) is applied, socat sets
|
||||
this variable to the name of the interface where the packet was received.
|
||||
|
||||
dit(bf(SOCAT_IP_LOCADDR) (output)) With all IPv4 based RECVFROM
|
||||
addresses where address option link(ip-pktinfo)(OPTION_IP_PKTINFO) is applied,
|
||||
socat sets this variable to the address of the interface where the packet was
|
||||
received.
|
||||
|
||||
dit(bf(SOCAT_IP_TOS) (output)) With all IPv4 based RECVFROM addresses where
|
||||
address option link(ip-recvtos)(OPTION_IP_RECVTOS) is applied, socat sets this
|
||||
variable to the TOS (type of service) of the received packet.
|
||||
|
||||
dit(bf(SOCAT_IP_TTL) (output)) With all IPv4 based RECVFROM addresses where
|
||||
address option link(ip-recvttl)(OPTION_IP_RECVTTL) is applied, socat sets this
|
||||
variable to the TTL (time to live) of the received packet.
|
||||
|
||||
dit(bf(SOCAT_IPV6_HOPLIMIT) (output)) With all IPv6 based RECVFROM addresses
|
||||
where address option link(ipv6-recvhoplimit)(OPTION_IPV6_RECVHOPLIMIT) is
|
||||
applied, socat sets this variable to the hoplimit value of the received packet.
|
||||
|
||||
dit(bf(SOCAT_IPV6_DSTADDR) (output)) With all IPv6 based RECVFROM
|
||||
addresses where address option link(ipv6-recvpktinfo)(OPTION_IPV6_RECVPKTINFO)
|
||||
is applied, socat sets this variable to the destination address of the received
|
||||
packet.
|
||||
|
||||
dit(bf(SOCAT_IPV6_TCLASS) (output)) With all IPv6 based RECVFROM addresses
|
||||
where address option link(ipv6-recvtclass)(OPTION_IPV6_RECVTCLASS) is applied,
|
||||
socat sets this variable to the transfer class of the received packet.
|
||||
|
||||
dit(bf(HOSTNAME) (input)) Is used to determine the hostname for logging (see
|
||||
link(-lh)(option_lh)).
|
||||
|
||||
dit(bf(LOGNAME)) Is used as name for the socks client user name if no
|
||||
dit(bf(LOGNAME) (input)) Is used as name for the socks client user name if no
|
||||
link(socksuser)(OPTION_SOCKSUSER) is given.nl()
|
||||
With options link(su)(OPTION_SUBSTUSER) and
|
||||
link(su-d)(OPTION_SUBSTUSER_DELAYED), LOGNAME is set to the given user name.
|
||||
|
||||
dit(bf(USER)) Is used as name for the socks client user name if no
|
||||
dit(bf(USER) (input)) Is used as name for the socks client user name if no
|
||||
link(socksuser)(OPTION_SOCKSUSER) is given and LOGNAME is empty.nl()
|
||||
With options link(su)(OPTION_SUBSTUSER) and
|
||||
link(su-d)(OPTION_SUBSTUSER_DELAYED), USER is set to the given user name.
|
||||
|
||||
dit(bf(SHELL))
|
||||
dit(bf(SHELL) (output))
|
||||
With options link(su)(OPTION_SUBSTUSER) and
|
||||
link(su-d)(OPTION_SUBSTUSER_DELAYED), SHELL is set to the login shell of the
|
||||
given user.
|
||||
|
||||
dit(bf(PATH))
|
||||
dit(bf(PATH) (output))
|
||||
Can be set with option link(path)(OPTION_PATH) for link(exec)(ADDRESS_EXEC) and
|
||||
link(system)(ADDRESS_SYSTEM) addresses.
|
||||
|
||||
dit(bf(HOME))
|
||||
dit(bf(HOME) (output))
|
||||
With options link(su)(OPTION_SUBSTUSER) and
|
||||
link(su-d)(OPTION_SUBSTUSER_DELAYED), HOME is set to the home directory of the
|
||||
given user.
|
||||
|
|
9
hostan.c
9
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 */
|
||||
|
|
2
socat.c
2
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);
|
||||
|
|
31
sycls.c
31
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) {
|
||||
|
|
6
sycls.h
6
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()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* source: sysincludes.h */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Copyright Gerhard Rieger 2001-2008 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __sysincludes_h_included
|
||||
|
@ -108,6 +108,9 @@
|
|||
#include <arpa/nameser.h> /* req for resolv.h (esp. on MacOSX) */
|
||||
#endif
|
||||
#include <net/if.h>
|
||||
#if HAVE_NET_IF_DL_H
|
||||
#include <net/if_dl.h> /* FreeBSD: struct sockaddr_dl */
|
||||
#endif
|
||||
#if HAVE_RESOLV_H
|
||||
#include <resolv.h> /* _res */
|
||||
#endif
|
||||
|
@ -116,6 +119,12 @@
|
|||
#if HAVE_NET_IF_H
|
||||
#include <net/if.h>
|
||||
#endif /* HAVE_NET_IF_H */
|
||||
#if HAVE_LINUX_TYPES_H
|
||||
#include <linux/types.h> /* __u32 for linux/errqueue.h */
|
||||
#endif
|
||||
#if HAVE_LINUX_ERRQUEUE_H
|
||||
#include <linux/errqueue.h> /* struct sock_extended_err */
|
||||
#endif
|
||||
#if HAVE_LINUX_IF_TUN_H
|
||||
#include <linux/if_tun.h>
|
||||
#endif
|
||||
|
|
154
sysutils.c
154
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
|
||||
}
|
||||
|
|
11
sysutils.h
11
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) */
|
||||
|
|
415
test.sh
415
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
|
||||
|
|
16
utils.c
16
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;
|
||||
}
|
||||
|
||||
|
|
5
utils.h
5
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) */
|
||||
|
||||
|
|
51
xio-ascii.c
51
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;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* source: xio-ascii.h */
|
||||
/* Copyright Gerhard Rieger 2002-2006 */
|
||||
/* Copyright Gerhard Rieger 2002-2008 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_ascii_h_included
|
||||
|
@ -17,4 +17,8 @@ extern char *xiosanitize(const char *data, /* input data */
|
|||
extern char *
|
||||
xiohexdump(const unsigned char *data, size_t bytes, char *coded);
|
||||
|
||||
extern char *
|
||||
xiodump(const unsigned char *data, size_t bytes, char *coded, size_t codlen,
|
||||
int coding);
|
||||
|
||||
#endif /* !defined(__xio_ascii_h_included) */
|
||||
|
|
122
xio-ip.c
122
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 */
|
||||
|
|
10
xio-ip.h
10
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) */
|
||||
|
|
39
xio-ip4.c
39
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 */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* source: xio-ip4.h */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Copyright Gerhard Rieger 2001-2008 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_ip4_h_included
|
||||
|
@ -9,5 +9,9 @@ extern const struct optdesc opt_ip4_add_membership;
|
|||
|
||||
extern
|
||||
int xiocheckrange_ip4(struct sockaddr_in *pa, struct xiorange_ip4 *range);
|
||||
extern int
|
||||
xiosetsockaddrenv_ip4(int idx, char *namebuff, size_t namelen,
|
||||
char *valuebuff, size_t valuelen,
|
||||
struct sockaddr_in *sa, int ipproto);
|
||||
|
||||
#endif /* !defined(__xio_ip4_h_included) */
|
||||
|
|
228
xio-ip6.c
228
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 */
|
||||
|
|
29
xio-ip6.h
29
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 */
|
||||
|
||||
|
|
25
xio-ipapp.c
25
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;
|
||||
|
|
46
xio-listen.c
46
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
25
xio-proxy.c
25
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);
|
||||
|
|
379
xio-socket.c
379
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 */
|
||||
|
|
13
xio-socket.h
13
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) */
|
||||
|
|
23
xio-socks.c
23
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);
|
||||
|
|
|
@ -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;
|
||||
|
|
19
xio-udp.c
19
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);
|
||||
|
|
23
xio-unix.c
23
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 */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* source: xio-unix.h */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Copyright Gerhard Rieger 2001-2008 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_unix_h_included
|
||||
|
@ -25,5 +25,9 @@ xiosetunix(struct sockaddr_un *saun,
|
|||
const char *path,
|
||||
bool abstract,
|
||||
bool tight);
|
||||
extern int
|
||||
xiosetsockaddrenv_unix(int idx, char *namebuff, size_t namelen,
|
||||
char *valuebuff, size_t valuelen,
|
||||
struct sockaddr_un *sa, socklen_t salen, int ipproto);
|
||||
|
||||
#endif /* !defined(__xio_unix_h_included) */
|
||||
|
|
2
xio.h
2
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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
70
xioopts.c
70
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) {
|
||||
|
|
20
xioopts.h
20
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,
|
||||
|
|
28
xioread.c
28
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;
|
||||
|
|
Loading…
Reference in a new issue