merged features ioctl, setsockopt, generic-socket

This commit is contained in:
Gerhard Rieger 2008-09-22 22:52:03 +02:00
commit d78b080ef0
44 changed files with 2035 additions and 263 deletions

19
CHANGES
View file

@ -1,5 +1,20 @@
new features:
added generic socket addresses: SOCKET-CONNECT, SOCKET-LISTEN,
SOCKET-SENDTO, SOCKET-RECVFROM, SOCKET-RECV, SOCKET-DATAGRAM allow
protocol independent socket handling; all parameters are explicitely
specified as numbers or hex data
added address options ioctl-void, ioctl-int, ioctl-intp, ioctl-string,
ioctl-bin for generic ioctl() calls.
added address options setsockopt-int, setsockopt-bin, and
setsockopt-string
so-type now only affect the socket() and socketpair() calls, not the
name resolution. so-type and so-prototype can be applied to all socket
based addresses.
new address option "escape" allows to break a socat instance even when
raw terminal mode prevents ^C etc.
@ -31,10 +46,6 @@ new features:
new address options ipv6-tclass and ipv6-unicast-hops set the related
socket options.
so-type now only affect the socket() and socketpair() calls, not the
name resolution. so-type and so-prototype can be applied to all socket
based addresses.
corrections:
some raw IP and UNIX datagram modes failed on BSD systems

View file

@ -285,6 +285,28 @@ $ socat -d -d -d -d - udp-datagram:224.0.0.2:6666,bind=:6666,ip-add-membership=2
// packets leave via wrong interface (set route: ...)
// socket bound to specific address
//=============================================================================
// GENERIC FUNCTION CALLS
// ioctl(): open CD drive (given value valid on Linux)
// on my Linux system I find in /usr/include/linux/cdrom.h the define:
// #define CDROMEJECT 0x5309 /* Ejects the cdrom media */
// the following command makes something like ioctl(fd, CDROMEJECT, NULL)
$ socat /dev/cdrom,o-nonblock,ioctl-void=0x5309 -
// setsockopt(): SO_REUSEADDR
// the following command performs - beyond lots of overhead - something like:
// myint=1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &myint, sizeof(myint))
$ socat -u udp-recv:7777,setsockopt-int=1:2:1 -
// setsockopt(): SO_BINDTODEVICE
// ways to apply SO_BINDTODEVICE without using the special socat address option
// so-bindtodevice:
// with string argument:
$ sudo ./socat tcp-l:7777,setsockopt-string=1:25:eth0 pipe
// with binary argument:
$ sudo ./socat tcp-l:7777,setsockopt-bin=1:25:x6574683000 pipe
===============================================================================
// not tested, just ideas, or have problems

View file

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

View file

@ -468,6 +468,7 @@
#undef WITH_IP4
#undef WITH_IP6
#undef WITH_RAWIP
#undef WITH_GENERICSOCKET
#undef WITH_TCP
#undef WITH_UDP
#undef WITH_LISTEN

View file

@ -213,6 +213,14 @@ AC_ARG_ENABLE(rawip, [ --disable-rawip disable raw IP support],
esac],
[AC_DEFINE(WITH_RAWIP) AC_MSG_RESULT(yes)])
AC_MSG_CHECKING(whether to include generic socket support)
AC_ARG_ENABLE(rawsocket, [ --disable-genericsocket disable generic socket support],
[case "$enableval" in
no) AC_MSG_RESULT(no);;
*) AC_DEFINE(WITH_GENERICSOCKET) AC_MSG_RESULT(yes);;
esac],
[AC_DEFINE(WITH_GENERICSOCKET) AC_MSG_RESULT(yes)])
AC_MSG_CHECKING(whether to include TCP support)
AC_ARG_ENABLE(tcp, [ --disable-tcp disable TCP support],
[case "$enableval" in

View file

@ -68,6 +68,7 @@ void dalan_init(void) {
/* read data description from line, write result to data; do not write
so much data that *p exceeds n !
p must be initialized to 0.
return 0 on success,
-1 if the data was cut due to n limit,
1 if a syntax error occurred

View file

@ -10,7 +10,7 @@ def(Filan)(0)(bf(Filan))
def(procan)(0)(bf(procan))
def(Procan)(0)(bf(Procan))
manpage(socat)(1)(Jul 2008)(socat)()
manpage(socat)(1)(Sep 2008)(socat)()
whenhtml(
label(CONTENTS)
@ -600,6 +600,145 @@ label(ADDRESS_READLINE)dit(bf(tt(READLINE)))
link(noecho)(OPTION_NOECHO)nl()
See also:
link(STDIO)(ADDRESS_STDIO)
label(ADDRESS_SOCKET_CONNECT)dit(bf(tt(SOCKET-CONNECT:<domain>:<protocol>:<remote-address>)))
Creates a stream socket using the first and second given socket parameters
and tt(SOCK_STREAM) (see man socket(2)) and connects to the remote-address.
The two socket parameters have to be specified by link(int)(TYPE_INT)
numbers. Consult your OS documentation and include files to find the
appropriate values. The remote-address must be the link(data)(TYPE_DATA)
representation of a sockaddr structure without sa_family and (BSD) sa_len
components.nl()
Please note that you can - beyond the options of the specified groups - also
use options of higher level protocols when you apply socat option
link(-g)(option_g).nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(CHILD)(GROUP_CHILD),link(RETRY)(GROUP_RETRY)nl()
Useful options:
link(bind)(OPTION_BIND),
link(setsockopt-int)(OPTION_SETSOCKOPT_INT),
link(setsockopt-bin)(OPTION_SETSOCKOPT_BIN),
link(setsockopt-string)(OPTION_SETSOCKOPT_STRING)
nl()
See also:
link(TCP)(ADDRESS_TCP_CONNECT),
link(UDP-CONNECT)(ADDRESS_UDP_CONNECT),
link(UNIX-CONNECT)(ADDRESS_UNIX_CONNECT),
link(SOCKET-LISTEN)(ADDRESS_SOCKET_LISTEN),
link(SOCKET-SENDTO)(ADDRESS_SOCKET_SENDTO)
label(ADDRESS_SOCKET_DATAGRAM)dit(bf(tt(SOCKET-DATAGRAM:<domain>:<type>:<protocol>:<remote-address>)))
Creates a datagram socket using the first three given socket parameters (see
man socket(2)) and sends outgoing data to the remote-address. The three
socket parameters have to be specified by link(int)(TYPE_INT)
numbers. Consult your OS documentation and include files to find the
appropriate values. The remote-address must be the link(data)(TYPE_DATA)
representation of a sockaddr structure without sa_family and (BSD) sa_len
components.nl()
Please note that you can - beyond the options of the specified groups - also
use options of higher level protocols when you apply socat option
link(-g)(option_g).nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(RANGE)(GROUP_RANGE)
Useful options:
link(bind)(OPTION_BIND),
link(range)(OPTION_RANGE),
link(setsockopt-int)(OPTION_SETSOCKOPT_INT),
link(setsockopt-bin)(OPTION_SETSOCKOPT_BIN),
link(setsockopt-string)(OPTION_SETSOCKOPT_STRING)
nl()
See also:
link(UDP-DATAGRAM)(ADDRESS_UDP_DATAGRAM),
link(IP-DATAGRAM)(ADDRESS_IP_DATAGRAM),
link(SOCKET-SENDTO)(ADDRESS_SOCKET_SENDTO),
link(SOCKET-RECV)(ADDRESS_SOCKET_RECV),
link(SOCKET-RECVFROM)(ADDRESS_SOCKET_RECVFROM)
label(ADDRESS_SOCKET_LISTEN)dit(bf(tt(SOCKET-LISTEN:<domain>:<protocol>:<local-address>)))
Creates a stream socket using the first and second given socket parameters
and tt(SOCK_STREAM) (see man socket(2)) and waits for incoming connections
on local-address. The two socket parameters have to be specified by
link(int)(TYPE_INT) numbers. Consult your OS documentation and include files
to find the appropriate values. The local-address must be the
link(data)(TYPE_DATA) representation of a sockaddr structure without
sa_family and (BSD) sa_len components.nl()
Please note that you can - beyond the options of the specified groups - also
use options of higher level protocols when you apply socat option
link(-g)(option_g).nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(LISTEN)(GROUP_LISTEN),link(RANGE)(GROUP_RANGE),link(CHILD)(GROUP_CHILD),link(RETRY)(GROUP_RETRY)nl()
Useful options:
link(setsockopt-int)(OPTION_SETSOCKOPT_INT),
link(setsockopt-bin)(OPTION_SETSOCKOPT_BIN),
link(setsockopt-string)(OPTION_SETSOCKOPT_STRING)
nl()
See also:
link(TCP)(ADDRESS_TCP_LISTEN),
link(UDP-CONNECT)(ADDRESS_UDP_LISTEN),
link(UNIX-CONNECT)(ADDRESS_UNIX_LISTEN),
link(SOCKET-LISTEN)(ADDRESS_SOCKET_CONNECT),
link(SOCKET-SENDTO)(ADDRESS_SOCKET_RECVFROM),
link(SOCKET-SENDTO)(ADDRESS_SOCKET_RECV)
label(ADDRESS_SOCKET_RECV)dit(bf(tt(SOCKET_RECV:<domain>:<type>:<protocol>:<local-address>)))
Creates a socket using the three given socket parameters (see man socket(2))
and binds it to <local-address>. Receives arriving data. The three
parameters have to be specified by link(int)(TYPE_INT) numbers. Consult your
OS documentation and include files to find the appropriate values. The
local-address must be the link(data)(TYPE_DATA) representation of a sockaddr
structure without sa_family and (BSD) sa_len components.nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(RANGE)(GROUP_RANGE)
Useful options:
link(range)(OPTION_RANGE),
link(setsockopt-int)(OPTION_SETSOCKOPT_INT),
link(setsockopt-bin)(OPTION_SETSOCKOPT_BIN),
link(setsockopt-string)(OPTION_SETSOCKOPT_STRING)
nl()
See also:
link(UDP-RECV)(ADDRESS_UDP_RECV),
link(IP-RECV)(ADDRESS_IP_RECV),
link(UNIX-RECV)(ADDRESS_UNIX_RECV),
link(SOCKET-DATAGRAM)(ADDRESS_SOCKET_DATAGRAM),
link(SOCKET-SENDTO)(ADDRESS_SOCKET_SENDTO),
link(SOCKET-RECVFROM)(ADDRESS_SOCKET_RECVFROM)
label(ADDRESS_SOCKET_RECVFROM)dit(bf(tt(SOCKET_RECVFROM:<domain>:<type>:<protocol>:<local-address>)))
Creates a socket using the three given socket parameters (see man socket(2))
and binds it to <local-address>. Receives arriving data and sends replies
back to the sender. The first three parameters have to be specified as
link(int)(TYPE_INT) numbers. Consult your OS documentation and include files
to find the appropriate values. The local-address must be the
link(data)(TYPE_DATA) representation of a sockaddr structure without
sa_family and (BSD) sa_len components.nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE)
Useful options:
link(fork)(OPTION_FORK),
link(range)(OPTION_RANGE),
link(setsockopt-int)(OPTION_SETSOCKOPT_INT),
link(setsockopt-bin)(OPTION_SETSOCKOPT_BIN),
link(setsockopt-string)(OPTION_SETSOCKOPT_STRING)
nl()
See also:
link(UDP-RECVFROM)(ADDRESS_UDP_RECVFROM),
link(IP-RECVFROM)(ADDRESS_IP_RECVFROM),
link(UNIX-RECVFROM)(ADDRESS_UNIX_RECVFROM),
link(SOCKET-DATAGRAM)(ADDRESS_SOCKET_DATAGRAM),
link(SOCKET-SENDTO)(ADDRESS_SOCKET_SENDTO),
link(SOCKET-RECV)(ADDRESS_SOCKET_RECV)
label(ADDRESS_SOCKET_SENDTO)dit(bf(tt(SOCKET_SENDTO:<domain>:<type>:<protocol>:<remote-address>)))
Creates a socket using the three given socket parameters (see man
socket(2)). Sends outgoing data to the given address and receives replies.
The three parameters have to be specified as link(int)(TYPE_INT)
numbers. Consult your OS documentation and include files to find the
appropriate values. The remote-address must be the link(data)(TYPE_DATA)
representation of a sockaddr structure without sa_family and (BSD) sa_len
components.nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET)
Useful options:
link(bind)(OPTION_BIND),
link(setsockopt-int)(OPTION_SETSOCKOPT_INT),
link(setsockopt-bin)(OPTION_SETSOCKOPT_BIN),
link(setsockopt-string)(OPTION_SETSOCKOPT_STRING)
nl()
See also:
link(UDP-SENDTO)(ADDRESS_UDP_SENDTO),
link(IP-SENDTO)(ADDRESS_IP_SENDTO),
link(UNIX-SENDTO)(ADDRESS_UNIX_SENDTO),
link(SOCKET-DATAGRAM)(ADDRESS_SOCKET_DATAGRAM),
link(SOCKET-RECV)(ADDRESS_SOCKET_RECV)
link(SOCKET-RECVFROM)(ADDRESS_SOCKET_RECVFROM)
label(ADDRESS_SOCKS4)dit(bf(tt(SOCKS4:<socks-server>:<host>:<port>)))
Connects via <socks-server> [link(IP address)(TYPE_IP_ADDRESS)]
to <host> [link(IPv4 address)(TYPE_IPV4_ADDRESS)]
@ -1265,6 +1404,24 @@ label(OPTION_END_CLOSE)dit(bf(tt(end-close)))
Similarly, when an address of type EXEC or SYSTEM is ended, socat usually
will explicitely kill the sub process. With this option, it will just close
the file descriptors.
label(OPTION_IOCTL_VOID)dit(bf(tt(ioctl-void=<request>)))
Calls tt(ioctl()) with the request value as second argument and NULL as
third argument. This option allows to utilize ioctls that are not
explicitely implemented in socat.
label(OPTION_IOCTL_INT)dit(bf(tt(ioctl-int=<reqeust>:<value>)))
Calls tt(ioctl()) with the request value as second argument and the integer
value as third argument.
label(OPTION_IOCTL_INTP)dit(bf(tt(ioctl-intp=<reqeust>:<value>)))
Calls tt(ioctl()) with the request value as second argument and a pointer to
the integer value as third argument.
label(OPTION_IOCTL_BIN)dit(bf(tt(ioctl-bin=<reqeust>:<value>)))
Calls tt(ioctl()) with the request value as second argument and a pointer to
the given data value as third argument. This data must be specified in
link(<dalan>)(TYPE_DATA) form.
label(OPTION_IOCTL_STRING)dit(bf(tt(ioctl-string=<reqeust>:<value>)))
Calls tt(ioctl()) with the request value as second argument and a pointer to
the given string as third argument.
link(<dalan>)(TYPE_DATA) form.
enddit()
startdit()enddit()nl()
@ -1650,6 +1807,24 @@ COMMENT(label(OPTION_USEIFBUFS)dit(bf(tt(useifbufs)))
label(OPTION_SO_TIMESTAMP)dit(bf(tt(so-timestamp)))
Sets the SO_TIMESTAMP socket option. This enables receiving and logging of
timestamp ancillary messages.
label(OPTION_SETSOCKOPT_INT)dit(bf(tt(setsockopt-int=<level>:<optname>:<optval>)))
Invokes tt(setsockopt()) for the socket with the given parameters. tt(level)
[link(int)(TYPE_INT)] is used as second argument to tt(setsockopt()) and
specifies the layer, e.g. SOL_TCP for TCP (6 on Linux), or SOL_SOCKET for
the socket layer (1 on Linux). tt(optname) [link(int)(TYPE_INT)] is the
third argument to tt(setsockopt()) and tells which socket option is to be
set. For the actual numbers you might have to look up the appropriate include
files of your system. The 4th tt(setsockopt()) parameter, tt(value)
[link(int)(TYPE_INT)], is passed to the function per pointer, and for the
length parameter sizeof(int) is taken implicitely.
label(OPTION_SETSOCKOPT_BIN)dit(bf(tt(setsockopt-bin=<level>:<optname>:<optval>)))
Like tt(setsockopt-int), but <optval> must be provided in
link(dalan)(TYPE_DATA) format and specifies an arbitrary sequence of bytes;
the length parameter is automatically derived from the data.
label(OPTION_SETSOCKOPT_STRING)dit(bf(tt(setsockopt-string=<level>:<optname>:<optval>)))
Like tt(setsockopt-int), but <optval> must be a link(string)(TYPE_STRING).
This string is passed to the function with trailing null character, and the
length parameter is automatically derived from the data.
enddit()
startdit()enddit()nl()
@ -2464,8 +2639,9 @@ label(TYPE_COMMAND_LINE)dit(command-line)
A string specifying a program name and its arguments, separated by single
spaces.
label(TYPE_DATA)dit(data)
A raw data specification following em(dalan) syntax. The only documented
form is a string starting with 'x' followed by an even number of hex digits.
A raw data specification following em(dalan) syntax. Currently the only
valid form is a string starting with 'x' followed by an even number of hex
digits, specifying a sequence of bytes.
label(TYPE_DIRECTORY)dit(directory)
A string with usual unix() directory name semantics.
label(TYPE_FACILITY)dit(facility)

View file

@ -142,7 +142,7 @@ int statname(const char *file, int fd, int filetype, FILE *outfile) {
if (file) fprintf(outfile, " %s", file);
break;
case (S_IFSOCK>>12): /* 12, socket */
#if WITH_SOCKET
#if _WITH_SOCKET
if (fd >= 0) {
result = sockname(fd, outfile);
} else if (file) {
@ -153,7 +153,7 @@ int statname(const char *file, int fd, int filetype, FILE *outfile) {
#else
Error("SOCKET support not compiled in");
return -1;
#endif /* !WITH_SOCKET */
#endif /* !_WITH_SOCKET */
break;
}
/* ioctl() */
@ -188,7 +188,7 @@ int cdevname(int fd, FILE *outfile) {
}
#if WITH_SOCKET
#if _WITH_SOCKET
int sockname(int fd, FILE *outfile) {
#define FDNAME_OPTLEN 256
#define FDNAME_NAMELEN 256
@ -323,7 +323,7 @@ int sockname(int fd, FILE *outfile) {
#undef FDNAME_OPTLEN
#undef FDNAME_NAMELEN
}
#endif /* WITH_SOCKET */
#endif /* _WITH_SOCKET */

22
filan.c
View file

@ -1,5 +1,5 @@
/* source: filan.c */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* the subroutine filan makes a "FILe descriptor ANalysis". It checks the
@ -150,7 +150,7 @@ int filan_fd(int fd, FILE *outfile) {
}
}
#endif /* defined(FIONREAD) */
#if WITH_SOCKET && defined(MSG_DONTWAIT)
#if _WITH_SOCKET && defined(MSG_DONTWAIT)
if ((ufds.revents & POLLIN) && isasocket(fd)) {
char _peername[SOCKADDR_MAX];
struct sockaddr *pa = (struct sockaddr *)_peername;
@ -186,7 +186,7 @@ int filan_fd(int fd, FILE *outfile) {
fprintf(outfile, "recvmsg="F_Zd", ", bytes);
}
}
#endif /* WITH_SOCKET && defined(MSG_DONTWAIT) */
#endif /* _WITH_SOCKET && defined(MSG_DONTWAIT) */
}
}
}
@ -371,12 +371,12 @@ int filan_stat(
break;
#ifdef S_IFSOCK
case (S_IFSOCK): /* 12, socket */
#if WITH_SOCKET
#if _WITH_SOCKET
result = sockan(statfd, outfile);
#else
Warn("SOCKET support not compiled in");
return -1;
#endif /* !WITH_SOCKET */
#endif /* !_WITH_SOCKET */
break;
#endif /* S_IFSOCK */
}
@ -462,7 +462,7 @@ int cdevan(int fd, FILE *outfile) {
}
#if WITH_SOCKET
#if _WITH_SOCKET
int sockan(int fd, FILE *outfile) {
#define FILAN_OPTLEN 256
#define FILAN_NAMELEN 256
@ -637,7 +637,7 @@ int sockan(int fd, FILE *outfile) {
#undef FILAN_OPTLEN
#undef FILAN_NAMELEN
}
#endif /* WITH_SOCKET */
#endif /* _WITH_SOCKET */
#if WITH_IP4 || WITH_IP6
@ -826,7 +826,7 @@ int tcpan(int fd, FILE *outfile) {
#endif /* WITH_TCP */
#if WITH_SOCKET
#if _WITH_SOCKET
int sockoptan(int fd, const struct sockopt *optname, int socklay, FILE *outfile) {
#define FILAN_OPTLEN 256
char optval[FILAN_OPTLEN];
@ -862,10 +862,10 @@ int sockoptan(int fd, const struct sockopt *optname, int socklay, FILE *outfile)
return 0;
#undef FILAN_OPTLEN
}
#endif /* WITH_SOCKET */
#endif /* _WITH_SOCKET */
#if WITH_SOCKET
#if _WITH_SOCKET
int isasocket(int fd) {
int retval;
#if HAVE_STAT64
@ -886,7 +886,7 @@ int isasocket(int fd) {
/* note: when S_ISSOCK was undefined, it always gives 0 */
return S_ISSOCK(props.st_mode);
}
#endif /* WITH_SOCKET */
#endif /* _WITH_SOCKET */
const char *getfiletypestring(int st_mode) {

View file

@ -26,12 +26,12 @@ extern int filan_stat(
extern int cdevan(int fd, FILE *outfile);
#if WITH_SOCKET
#if _WITH_SOCKET
extern int isasocket(int fd);
extern int sockan(int fd, FILE *outfile);
extern int ipan(int fd, FILE *outfile);
extern int ip6an(int fd, FILE *outfile);
#endif /* WITH_SOCKET */
#endif /* _WITH_SOCKET */
extern
int fdname(const char *file, int fd, FILE *outfile, const char *numform);

View file

@ -20,14 +20,14 @@
static int iffan(FILE *outfile);
int hostan(FILE *outfile) {
#if WITH_SOCKET
#if _WITH_SOCKET
fprintf(outfile, "\nIP INTERFACES\n");
iffan(outfile);
#endif
return 0;
}
#if WITH_SOCKET
#if _WITH_SOCKET
static int iffan(FILE *outfile) {
/* Linux: man 7 netdevice */
/* FreeBSD, NetBSD: man 4 networking */
@ -81,4 +81,4 @@ static int iffan(FILE *outfile) {
#endif /* defined(SIOCGIFCONF) */
return 0;
}
#endif /* WITH_SOCKET */
#endif /* _WITH_SOCKET */

View file

@ -75,10 +75,25 @@ int procan_cdefs(FILE *outfile) {
#ifdef CSIZE
fprintf(outfile, "#define CSIZE 0%011o\n", CSIZE);
#endif
#ifdef TIOCEXCL
fprintf(outfile, "#define TIOCEXCL 0x%lx\n", (unsigned long)TIOCEXCL);
#endif
/* stdio constants */
#ifdef FOPEN_MAX
fprintf(outfile, "#define FOPEN_MAX %u\n", FOPEN_MAX);
#endif
/* socket constants */
#ifdef SOCK_DGRAM
fprintf(outfile, "#define SOCK_DGRAM %d\n", SOCK_DGRAM);
#endif
#ifdef SOL_SOCKET
fprintf(outfile, "#define SOL_SOCKET 0x%x\n", SOL_SOCKET);
#endif
#ifdef SO_REUSEADDR
fprintf(outfile, "#define SO_REUSEADDR %d\n", SO_REUSEADDR);
#endif
return 0;
}

View file

@ -1,6 +1,6 @@
#! /bin/bash
# source: readline-test.sh
# Copyright Gerhard Rieger 2003
# Copyright Gerhard Rieger 2003-2008
# Published under the GNU General Public License V.2, see file COPYING
# script that simulates a simple program with authentication.
@ -29,8 +29,9 @@ trap "$ECHO $0 got SIGQUIT" QUIT
# print banner
$ECHO "$BANNER"
read -r -p "$($ECHO "$USERPROMPT")" USERNAME
read -rs -p "$PWDPROMPT" PASSWORD
# on (some) ksh read -p does not mean prompt
$ECHO "$USERPROMPT\c"; read -r USERNAME
$ECHO "$PWDPROMPT\c"; read -rs PASSWORD
$ECHO
if [ "$USERNAME" != "$CREDUSER" -o "$PASSWORD" != "$CREDPASS" ]; then
@ -38,7 +39,7 @@ if [ "$USERNAME" != "$CREDUSER" -o "$PASSWORD" != "$CREDPASS" ]; then
exit -1
fi
while read -r -p "$PROMPT" COMMAND; do
while $ECHO "$PROMPT\c"; read -r COMMAND; do
if [ "$COMMAND" = "exit" ]; then
break;
fi

10
sycls.c
View file

@ -593,6 +593,16 @@ int Ioctl(int d, int request, void *argp) {
return retval;
}
int Ioctl_int(int d, int request, int arg) {
int retval, _errno;
Debug3("ioctl(%d, 0x%x, %d)", d, request, arg);
retval = ioctl(d, request, arg);
_errno = errno;
Debug1("ioctl() -> %d", retval);
errno = _errno;
return retval;
}
int Close(int fd) {
int retval, _errno;
Info1("close(%d)", fd);

View file

@ -64,6 +64,7 @@ int Ftruncate64(int fd, off64_t length);
#endif /* HAVE_FTRUNCATE64 */
int Flock(int fd, int operation);
int Ioctl(int d, int request, void *argp);
int Ioctl_int(int d, int request, int arg);
int Close(int fd);
int Fchown(int fd, uid_t owner, gid_t group);
int Fchmod(int fd, mode_t mode);
@ -197,6 +198,7 @@ void Add_history(const char *string);
#define Ftruncate64(f,l) ftruncate64(f,l)
#define Flock(f,o) flock(f,o)
#define Ioctl(d,r,a) ioctl(d,r,a)
#define Ioctl_int(d,r,a) ioctl(d,r,a)
#define Close(f) close(f)
#define Fchown(f,o,g) fchown(f,o,g)
#define Fchmod(f,m) fchmod(f,m)

View file

@ -106,6 +106,7 @@ void socket_in6_init(struct sockaddr_in6 *sa) {
length of the specific socket address, or 0 on error. */
socklen_t socket_init(int af, union sockaddr_union *sa) {
switch (af) {
case AF_UNSPEC: memset(sa, 0, sizeof(*sa)); return sizeof(*sa);
#if WITH_UNIX
case AF_UNIX: socket_un_init(&sa->un); return sizeof(sa->un);
#endif
@ -134,6 +135,14 @@ char *sockaddr_info(const struct sockaddr *sa, socklen_t salen, char *buff, size
char *cp = lbuff;
int n;
#if HAVE_STRUCT_SOCKADDR_SALEN
if ((n = snprintf(cp, blen, "LEN=%d ", sas->soa.sa_len)) < 0) {
Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen);
*buff = '\0';
return buff;
}
cp += n, blen -= n;
#endif
if ((n = snprintf(cp, blen, "AF=%d ", sau->soa.sa_family)) < 0) {
Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen);
*buff = '\0';

View file

@ -15,6 +15,7 @@ union xioin6_u {
} ;
#endif /* WITH_IP6 */
#if _WITH_SOCKET
union sockaddr_union {
struct sockaddr soa;
#if WITH_UNIX
@ -27,29 +28,12 @@ union sockaddr_union {
struct sockaddr_in6 ip6;
#endif /* WITH_IP6 */
} ;
#if _WITH_IP4
struct xiorange_ip4 {
struct in_addr netaddr; /* network byte order */
struct in_addr netmask; /* network byte order */
} ;
#endif /* _WITH_IP4 */
#if _WITH_IP6
struct xiorange_ip6 {
struct in6_addr addr;
struct in6_addr mask;
} ;
#endif /* _WITH_IP4 */
#endif /* _WITH_SOCKET */
#if _WITH_SOCKET
union xiorange_union {
#if _WITH_IP4
struct xiorange_ip4 ip4;
#endif /* _WITH_IP4 */
#if _WITH_IP6
struct xiorange_ip6 ip6;
#endif /* _WITH_IP6 */
struct xiorange {
union sockaddr_union netaddr;
union sockaddr_union netmask;
} ;
#endif /* _WITH_SOCKET */

641
test.sh
View file

@ -144,14 +144,21 @@ SunOS)
BROADCASTIF="$MAINIF"
#BROADCASTIF=hme0
#BROADCASTIF=eri0
SECONDADDR=$($IFCONFIG $BROADCASTIF |grep 'inet ' |awk '{print($2);}')
BCIFADDR="$SECONDADDR"
BCADDR=$($IFCONFIG $BROADCASTIF |grep 'broadcast ' |sed 's/.*broadcast/broadcast/' |awk '{print($2);}') ;;
#SECONDADDR=$($IFCONFIG $BROADCASTIF |grep 'inet ' |awk '{print($2);}')
SECONDADDR=$(expr "$($IFCONFIG -a |grep 'inet ' |fgrep -v ' 127.0.0.1 '| head -n 1)" : '.*inet \([0-9.]*\) .*')
#BCIFADDR="$SECONDADDR"
#BCADDR=$($IFCONFIG $BROADCASTIF |grep 'broadcast ' |sed 's/.*broadcast/broadcast/' |awk '{print($2);}')
;;
#AIX|FreeBSD|Solaris)
*)
SECONDADDR=$(expr "$($IFCONFIG -a |grep 'inet ' |fgrep -v ' 127.0.0.1 '| head -n 1)" : '.*inet \([0-9.]*\) .*')
SECONDADDR=$(expr "$($IFCONFIG -a |grep 'inet ' |fgrep -v ' 127.0.0.1 ' |head -n 1)" : '.*inet \([0-9.]*\) .*')
;;
esac
# for generic sockets we need this address in hex form
if [ "$SECONDADDR" ]; then
SECONDADDRHEX="$(printf "%02x%02x%02x%02x\n" $(echo "$SECONDADDR" |tr '.' '
'))"
fi
# for some tests we need a second local IPv6 address
case "$UNAME" in
@ -187,20 +194,20 @@ vt100|vt320|linux|xterm|cons25|dtterm|aixterm|sun-color|xterm-color)
RED="\0033[31m"
GREEN="\0033[32m"
YELLOW="\0033[33m"
if false && [ "$UNAME" = SunOS ]; then
NORMAL="\0033[30m"
else
# if [ "$UNAME" = SunOS ]; then
# NORMAL="\0033[30m"
# else
NORMAL="\0033[39m"
fi
# fi
else
RED="\033[31m"
GREEN="\033[32m"
YELLOW="\033[33m"
if false && [ "$UNAME" = SunOS ]; then
NORMAL="\033[30m"
else
# if [ "$UNAME" = SunOS ]; then
# NORMAL="\033[30m"
# else
NORMAL="\033[39m"
fi
# fi
fi
OK="${GREEN}OK${NORMAL}"
FAILED="${RED}FAILED${NORMAL}"
@ -1512,9 +1519,11 @@ testod () {
local T="$6"; [ -z "$T" ] && T=0
local tf="$td/test$N.stdout"
local te="$td/test$N.stderr"
local tr="$td/test$N.ref"
local tdiff="$td/test$N.diff"
local dain="$(date) $RANDOM"
local daout="$(echo "$dain" |$OD_C)"
echo "$dain" |$OD_C >"$tr"
# local daout="$(echo "$dain" |$OD_C)"
$PRINTF "test $F_n %s... " $num "$title"
(psleep $T; echo "$dain"; psleep $T) |$SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te"
if [ "$?" != 0 ]; then
@ -1522,7 +1531,8 @@ testod () {
echo "$SOCAT $opts $arg1 $arg2"
cat "$te"
numFAIL=$((numFAIL+1))
elif echo "$daout" |diff - "$tf" >"$tdiff" 2>&1; then
# elif echo "$daout" |diff - "$tf" >"$tdiff" 2>&1; then
elif diff "$tr" "$tf" >"$tdiff" 2>&1; then
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat $te; fi
numOK=$((numOK+1))
@ -1577,7 +1587,8 @@ ifprocess () {
FreeBSD) l="$(ps -faje |grep "^........ $(printf %5u $1)")" ;;
HP-UX) l="$(ps -fade |grep "^........ $(printf %5u $1)")" ;;
Linux) l="$(ps -fade |grep "^........ $(printf %5u $1)")" ;;
NetBSD) l="$(ps -aj |grep "^........ $(printf %4u $1)")" ;;
# NetBSD) l="$(ps -aj |grep "^........ $(printf %4u $1)")" ;;
NetBSD) l="$(ps -aj |grep "^[^ ][^ ]*[ ][ ]*$(printf %5u $1) ")" ;;
OpenBSD) l="$(ps -kaj |grep "^........ $(printf %5u $1)")" ;;
SunOS) l="$(ps -fade |grep "^........ $(printf %5u $1)")" ;;
*) l="$(ps -fade |grep "^[^ ][^ ]*[ ][ ]*$(printf %5u $1) ")" ;;
@ -1599,8 +1610,9 @@ childprocess () {
FreeBSD) l="$(ps -faje |grep "^........ ..... $(printf %5u $1)")" ;;
HP-UX) l="$(ps -fade |grep "^........ ..... $(printf %5u $1)")" ;;
Linux) l="$(ps -fade |grep "^........ ..... $(printf %5u $1)")" ;;
NetBSD) l="$(ps -aj |grep "^........ ..... $(printf %4u $1)")" ;;
OpenBSD) l="$(ps -kaj |grep "^........ ..... $(printf %5u $1)")" ;;
# NetBSD) l="$(ps -aj |grep "^........ ..... $(printf %4u $1)")" ;;
NetBSD) l="$(ps -aj |grep "^[^ ][^ ]*[ ][ ]*..... $(printf %5u $1)")" ;;
OpenBSD) l="$(ps -aj |grep "^........ ..... $(printf %5u $1)")" ;;
SunOS) l="$(ps -fade |grep "^........ ..... $(printf %5u $1)")" ;;
*) l="$(ps -fade |grep "^[^ ][^ ]*[ ][ ]*[0-9][0-9]**[ ][ ]*$(printf %5u $1) ")" ;; esac
if [ -z "$l" ]; then
@ -4399,7 +4411,7 @@ tr="$td/test$N.ref"
tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')"
# the feature that we really want to test is in the readline.sh script:
CMD="$SOCAT $opts open:$tpi,nonblock!!open:$tpo exec:\"./readline.sh -nh ./readline-test.sh\",pty,ctty,setsid,raw,echo=0,isig"
CMD="$SOCAT $opts -t1 open:$tpi,nonblock!!open:$tpo exec:\"./readline.sh -nh ./readline-test.sh\",pty,ctty,setsid,raw,echo=0,isig"
#echo "$CMD" >"$ts"
#chmod a+x "$ts"
printf "test $F_n $TEST... " $N
@ -4471,7 +4483,8 @@ else
if [ -n "$debug" ]; then cat $te; fi
numOK=$((numOK+1))
fi
#kill $pid 2>/dev/null
kill $pid 2>/dev/null # necc on OpenBSD
wait
MICROS=$SAVEMICS
TERM="$SAVETERM"
fi
@ -4869,7 +4882,13 @@ NAME=TCP4RANGEBITS
case "$TESTS" in
*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%range%*|*%$NAME%*)
TEST="$NAME: security of TCP4-L with RANGE option"
if [ -z "$SECONDADDR" ]; then
# we need access to a second addresses
$PRINTF "test $F_n $TEST... ${YELLOW}need a second IPv4 address${NORMAL}\n" $N
numCANT=$((numCANT+1))
else
testserversec "$N" "$TEST" "$opts -s" "tcp4-l:$PORT,reuseaddr,fork,retry=1" "" "range=$SECONDADDR/32" "tcp4:127.0.0.1:$PORT" 4 tcp $PORT 0
fi ;; # $SECONDADDR
esac
PORT=$((PORT+1))
N=$((N+1))
@ -4878,6 +4897,22 @@ NAME=TCP4RANGEMASK
case "$TESTS" in
*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%range%*|*%$NAME%*)
TEST="$NAME: security of TCP4-L with RANGE option"
if [ -z "$SECONDADDR" ]; then
# we need access to a second addresses
$PRINTF "test $F_n $TEST... ${YELLOW}need a second IPv4 address${NORMAL}\n" $N
numCANT=$((numCANT+1))
else
testserversec "$N" "$TEST" "$opts -s" "tcp4-l:$PORT,reuseaddr,fork,retry=1" "" "range=$SECONDADDR:255.255.255.255" "tcp4:127.0.0.1:$PORT" 4 tcp $PORT 0
fi ;; # $SECONDADDR
esac
PORT=$((PORT+1))
N=$((N+1))
# like TCP4RANGEMASK, but the "bad" address is within the same class A network
NAME=TCP4RANGEMASKHAIRY
case "$TESTS" in
*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%range%*|*%$NAME%*)
TEST="$NAME: security of TCP4-L with RANGE option"
if [ "$UNAME" != Linux ]; then
# we need access to more loopback addresses
$PRINTF "test $F_n $TEST... ${YELLOW}only on Linux${NORMAL}\n" $N
@ -5556,7 +5591,7 @@ N=$((N+1))
signum () {
if [ ! "$BASH_VERSION" ]; then
# we expect:
for i in $(kill -l); do echo $i; done |grep -n -i $1 |cut -d: -f1
for i in $(POSIXLY_CORRECT=1 kill -l); do echo $i; done |grep -n -i "^$1$" |cut -d: -f1
else
# expect:
# " 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL"
@ -5578,12 +5613,12 @@ if ! feat=$(testaddrs pty); then
$PRINTF "test $F_n $TEST... ${YELLOW}$(echo $feat |tr a-z A-Z) not available${NORMAL}\n" $N
numCANT=$((numCANT+1))
else
SIG=$(signum $signam)
SIG="$(signum $signam)"
te="$td/test$N.stderr"
tpp="$td/test$N.ppid"
tp="$td/test$N.pid"
$PRINTF "test $F_n $TEST... " $N
(sleep 1; kill -$SIG $(cat "$tpp")) &
(sleep 1; kill -"$SIG" "$(cat "$tpp")") &
# a simple "system:echo $PPID..." does not work on NetBSD, OpenBSD
#$SOCAT $opts echo system:'exec /bin/bash -c "echo \$PPID '">$tpp"'; echo \$$ '">$tp; read x\"",nofork 2>"$te"; stat=$?
tsh="$td/test$N.sh"
@ -5941,10 +5976,13 @@ PORT=$((PORT+1))
N=$((N+1))
# test the UDP4-SENDTO and UDP4-RECVFROM addresses together
NAME=UDP4DGRAM
case "$TESTS" in
*%functions%*|*%udp%*|*%udp4%*|*%ip4%*|*%dgram%*|*%$NAME%*)
TEST="$NAME: UDP/IPv4 datagram"
TEST="$NAME: UDP/IPv4 sendto and recvfrom"
# start a UDP4-RECVFROM process that echoes data, and send test data using
# UDP4-SENDTO. The sent data should be returned.
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
@ -5966,16 +6004,16 @@ kill "$pid1" 2>/dev/null; wait;
if [ "$rc2" -ne 0 ]; then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD1 &"
echo "$CMD2"
cat "${te}1"
echo "$CMD2"
cat "${te}2"
numFAIL=$((numFAIL+1))
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED\n"
cat "$tdiff"
echo "$CMD1 &"
echo "$CMD2"
cat "${te}1"
echo "$CMD2"
cat "${te}2"
numFAIL=$((numFAIL+1))
else
@ -8836,6 +8874,559 @@ UNIX UNIX $td/test\$N.server - , so-timestamp TIMESTAMP
"
# test the SOCKET-CONNECT address (against TCP4-LISTEN)
NAME=SOCKET_CONNECT_TCP4
case "$TESTS" in
*%functions%*|*%generic%*|*%socket%*|*%$NAME%*)
TEST="$NAME: socket connect with TCP/IPv4"
# start a TCP4-LISTEN process that echoes data, and send test data using
# SOCKET-CONNECT, selecting TCP/IPv4. The sent data should be returned.
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
ts0p=$PORT; PORT=$((PORT+1))
ts0a="127.0.0.1"
ts1p=$(printf "%04x" $ts0p);
ts1a="7f000001" # "127.0.0.1"
ts1="x${ts1p}${ts1a}x0000000000000000"
ts1b=$(printf "%04x" $PORT); PORT=$((PORT+1))
da="test$N $(date) $RANDOM"
CMD0="$SOCAT $opts TCP4-LISTEN:$ts0p,reuseaddr,bind=$ts0a PIPE"
CMD1="$SOCAT $opts - SOCKET-CONNECT:2:6:$ts1,bind=x${ts1b}00000000x0000000000000000"
printf "test $F_n $TEST... " $N
$CMD0 2>"${te}0" &
pid0="$!"
waittcp4port $ts0p 1
echo "$da" |$CMD1 >>"$tf" 2>>"${te}1"
rc1="$?"
kill "$pid0" 2>/dev/null; wait;
if [ "$rc1" -ne 0 ]; then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
numFAIL=$((numFAIL+1))
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED\n"
cat "$tdiff"
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
numFAIL=$((numFAIL+1))
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat $te; fi
numOK=$((numOK+1))
fi ;;
esac
PORT=$((PORT+1))
N=$((N+1))
# test the SOCKET-CONNECT address (against TCP6-LISTEN)
NAME=SOCKET_CONNECT_TCP6
case "$TESTS" in
*%functions%*|*%generic%*|*%tcp6%*|*%socket%*|*%$NAME%*)
TEST="$NAME: socket connect with TCP/IPv6"
# start a TCP6-LISTEN process that echoes data, and send test data using
# SOCKET-CONNECT, selecting TCP/IPv6. The sent data should be returned.
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
ts0p=$PORT; PORT=$((PORT+1))
ts0a="[::1]"
ts1p=$(printf "%04x" $ts0p);
ts1a="00000000000000000000000000000001" # "127.0.0.1"
ts1="x${ts1p}x000000000000x${ts1a}"
ts1b=$(printf "%04x" $PORT); PORT=$((PORT+1))
da="test$N $(date) $RANDOM"
CMD0="$SOCAT $opts TCP6-LISTEN:$ts0p,reuseaddr,bind=$ts0a PIPE"
CMD1="$SOCAT $opts - SOCKET-CONNECT:10:6:$ts1,bind=x${ts1b}x000000000000x00000000000000000000000000000000"
printf "test $F_n $TEST... " $N
$CMD0 2>"${te}0" &
pid0="$!"
waittcp6port $ts0p 1
echo "$da" |$CMD1 >>"$tf" 2>>"${te}1"
rc1="$?"
kill "$pid0" 2>/dev/null; wait;
if [ "$rc1" -ne 0 ]; then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
numFAIL=$((numFAIL+1))
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED\n"
cat "$tdiff"
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
numFAIL=$((numFAIL+1))
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat $te; fi
numOK=$((numOK+1))
fi ;;
esac
PORT=$((PORT+1))
N=$((N+1))
# test the SOCKET-CONNECT address (against UNIX-LISTEN)
NAME=SOCKET_CONNECT_UNIX
case "$TESTS" in
*%functions%*|*%generic%*|*%unix%*|*%socket%*|*%$NAME%*)
TEST="$NAME: socket connect with UNIX domain"
# start a UNIX-LISTEN process that echoes data, and send test data using
# SOCKET-CONNECT, selecting UNIX socket. The sent data should be returned.
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
ts0="$td/test$N.server"
ts1="$td/test$N.client"
da="test$N $(date) $RANDOM"
CMD0="$SOCAT $opts UNIX-LISTEN:$ts0,reuseaddr PIPE"
CMD1="$SOCAT $opts - SOCKET-CONNECT:1:0:\\\"$ts0\\\0\\\",bind=\\\"$ts1\\\0\\\""
printf "test $F_n $TEST... " $N
$CMD0 2>"${te}0" &
pid0="$!"
waitfile $ts0 1
echo "$da" |$CMD1 >>"$tf" 2>>"${te}1"
rc1="$?"
kill "$pid0" 2>/dev/null; wait;
if [ "$rc1" -ne 0 ]; then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
numFAIL=$((numFAIL+1))
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED\n"
cat "$tdiff"
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
numFAIL=$((numFAIL+1))
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat $te; fi
numOK=$((numOK+1))
fi ;;
esac
N=$((N+1))
# test the SOCKET-LISTEN address (with TCP4-CONNECT)
NAME=SOCKET_LISTEN
case "$TESTS" in
*%functions%*|*%generic%*|*%socket%*|*%$NAME%*)
TEST="$NAME: socket recvfrom with TCP/IPv4"
# start a SOCKET-LISTEN process that uses TCP/IPv4 and echoes data, and
# send test data using TCP4-CONNECT. The sent data should be returned.
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
ts1p=$PORT; PORT=$((PORT+1))
ts1a="127.0.0.1"
ts0p=$(printf "%04x" $ts1p);
ts0a="7f000001" # "127.0.0.1"
ts0="x${ts0p}${ts0a}x0000000000000000"
ts1b=$PORT; PORT=$((PORT+1))
ts1="$ts1a:$ts1p"
da="test$N $(date) $RANDOM"
CMD0="$SOCAT $opts SOCKET-LISTEN:2:6:$ts0,reuseaddr PIPE"
CMD1="$SOCAT $opts - TCP4-CONNECT:$ts1,bind=:$ts1b"
printf "test $F_n $TEST... " $N
$CMD0 2>"${te}0" &
pid0="$!"
#sleep 1
waittcp4port $ts1p 1
echo "$da" |$CMD1 >>"$tf" 2>>"${te}1"
rc1="$?"
kill "$pid0" 2>/dev/null; wait;
if [ "$rc1" -ne 0 ]; then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
numFAIL=$((numFAIL+1))
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED\n"
cat "$tdiff"
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
numFAIL=$((numFAIL+1))
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat $te; fi
numOK=$((numOK+1))
fi ;;
esac
PORT=$((PORT+1))
N=$((N+1))
SOCK_DGRAM="$($PROCAN -c |grep "^#define[[:space:]]*SOCK_DGRAM[[:space:]]" |cut -d' ' -f3)"
# test the SOCKET-SENDTO address (against UDP4-RECVFROM)
NAME=SOCKET_SENDTO
case "$TESTS" in
*%functions%*|*%generic%*|*%socket%*|*%ip4%*|*%udp%*|*%dgram%*|*%$NAME%*)
TEST="$NAME: socket sendto with UDP/IPv4"
# start a UDP4-RECVFROM process that echoes data, and send test data using
# SOCKET-SENDTO, selecting UDP/IPv4. The sent data should be returned.
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
ts0p=$PORT; PORT=$((PORT+1))
ts0a="127.0.0.1"
ts1p=$(printf "%04x" $ts0p);
ts1a="7f000001" # "127.0.0.1"
ts1="x${ts1p}${ts1a}x0000000000000000"
ts1b=$(printf "%04x" $PORT); PORT=$((PORT+1))
da="test$N $(date) $RANDOM"
CMD0="$SOCAT $opts UDP4-RECVFROM:$ts0p,reuseaddr,bind=$ts0a PIPE"
CMD1="$SOCAT $opts - SOCKET-SENDTO:2:$SOCK_DGRAM:17:$ts1,bind=x${ts1b}x00000000x0000000000000000"
printf "test $F_n $TEST... " $N
$CMD0 2>"${te}0" &
pid0="$!"
waitudp4port $ts0p 1
echo "$da" |$CMD1 >>"$tf" 2>>"${te}1"
rc1="$?"
kill "$pid0" 2>/dev/null; wait;
if [ "$rc1" -ne 0 ]; then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
numFAIL=$((numFAIL+1))
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED\n"
cat "$tdiff"
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
numFAIL=$((numFAIL+1))
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat $te; fi
numOK=$((numOK+1))
fi ;;
esac
PORT=$((PORT+1))
N=$((N+1))
# test the SOCKET-RECVFROM address (with UDP4-SENDTO)
NAME=SOCKET_RECVFROM
case "$TESTS" in
*%functions%*|*%generic%*|*%socket%*|*%ip4%*|*%udp%*|*%dgram%*|*%$NAME%*)
TEST="$NAME: socket recvfrom with UDP/IPv4"
# start a SOCKET-RECVFROM process that uses UDP/IPv4 and echoes data, and
# send test data using UDP4-SENDTO. The sent data should be returned.
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
ts1p=$PORT; PORT=$((PORT+1))
ts1a="127.0.0.1"
ts0p=$(printf "%04x" $ts1p);
ts0a="7f000001" # "127.0.0.1"
ts0="x${ts0p}${ts0a}x0000000000000000"
ts1b=$PORT; PORT=$((PORT+1))
ts1="$ts1a:$ts1p"
da="test$N $(date) $RANDOM"
CMD0="$SOCAT $opts SOCKET-RECVFROM:2:$SOCK_DGRAM:17:$ts0,reuseaddr PIPE"
CMD1="$SOCAT $opts - UDP4-SENDTO:$ts1,bind=:$ts1b"
printf "test $F_n $TEST... " $N
$CMD0 2>"${te}0" &
pid0="$!"
sleep 1 # waitudp4port $ts1p 1
echo "$da" |$CMD1 >>"$tf" 2>>"${te}1"
rc1="$?"
kill "$pid0" 2>/dev/null; wait;
if [ "$rc1" -ne 0 ]; then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
numFAIL=$((numFAIL+1))
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED\n"
cat "$tdiff"
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
numFAIL=$((numFAIL+1))
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat $te; fi
numOK=$((numOK+1))
fi ;;
esac
PORT=$((PORT+1))
N=$((N+1))
# test the SOCKET-RECV address (with UDP4-SENDTO)
NAME=SOCKET_RECV
case "$TESTS" in
*%functions%*|*%generic%*|*%socket%*|*%ip4%*|*%udp%*|*%dgram%*|*%$NAME%*)
TEST="$NAME: socket recv with UDP/IPv4"
# start a SOCKET-RECV process that uses UPD/IPv4 and writes received data to file, and
# send test data using UDP4-SENDTO.
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
ts1p=$PORT; PORT=$((PORT+1))
ts1a="127.0.0.1"
ts0p=$(printf "%04x" $ts1p);
ts0a="7f000001" # "127.0.0.1"
ts0="x${ts0p}${ts0a}x0000000000000000"
ts1b=$PORT; PORT=$((PORT+1))
ts1="$ts1a:$ts1p"
da="test$N $(date) $RANDOM"
CMD0="$SOCAT $opts -u SOCKET-RECV:2:$SOCK_DGRAM:17:$ts0,reuseaddr -"
CMD1="$SOCAT $opts -u - UDP4-SENDTO:$ts1,bind=:$ts1b"
printf "test $F_n $TEST... " $N
$CMD0 2>"${te}0" >"$tf" &
pid0="$!"
sleep 1 # waitudp4port $ts1p 1
echo "$da" |$CMD1 2>>"${te}1"
rc1="$?"
sleep 1
kill "$pid0" 2>/dev/null; wait;
if [ "$rc1" -ne 0 ]; then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
numFAIL=$((numFAIL+1))
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED\n"
cat "$tdiff"
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
numFAIL=$((numFAIL+1))
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat $te; fi
numOK=$((numOK+1))
fi ;;
esac
PORT=$((PORT+1))
N=$((N+1))
# test SOCKET-DATAGRAM (with UDP4-DATAGRAM)
NAME=SOCKET_DATAGRAM
case "$TESTS" in
*%functions%*|*%generic%*|*%socket%*|*%ip4%*|*%udp%*|*%dgram%*|*%$NAME%*)
TEST="$NAME: socket datagram via UDP/IPv4"
# start a UDP4-DATAGRAM process that echoes data, and send test data using
# SOCKET-DATAGRAM, selecting UDP/IPv4. The sent data should be returned.
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
ts0p=$PORT; PORT=$((PORT+1))
ts1p=$PORT; PORT=$((PORT+1))
ts0a="127.0.0.1"
ts1b=$(printf "%04x" $ts0p);
ts1a="7f000001" # "127.0.0.1"
ts0b=$(printf "%04x" $ts0p)
ts1b=$(printf "%04x" $ts1p)
ts1="x${ts0b}${ts1a}x0000000000000000"
da="test$N $(date) $RANDOM"
CMD0="$SOCAT $opts UDP4-DATAGRAM:$ts0a:$ts1p,bind=:$ts0p,reuseaddr PIPE"
CMD1="$SOCAT $opts - SOCKET-DATAGRAM:2:$SOCK_DGRAM:17:$ts1,bind=x${ts1b}x00000000x0000000000000000"
printf "test $F_n $TEST... " $N
$CMD0 2>"${te}0" &
pid0="$!"
waitudp4port $ts0p 1
echo "$da" |$CMD1 2>>"${te}1" >"$tf"
rc1="$?"
kill "$pid0" 2>/dev/null; wait;
if [ "$rc1" -ne 0 ]; then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
numFAIL=$((numFAIL+1))
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED\n"
cat "$tdiff"
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
numFAIL=$((numFAIL+1))
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat $te; fi
numOK=$((numOK+1))
fi ;;
esac
PORT=$((PORT+1))
N=$((N+1))
NAME=SOCKETRANGEMASK
case "$TESTS" in
*%functions%*|*%security%*|*%generic%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%socket%*|*%range%*|*%$NAME%*)
TEST="$NAME: security of generic socket-listen with RANGE option"
if [ -z "$SECONDADDR" ]; then
# we need access to more loopback addresses
$PRINTF "test $F_n $TEST... ${YELLOW}need a second IPv4 address${NORMAL}\n" $N
numCANT=$((numCANT+1))
else
ts1p=$(printf "%04x" $PORT);
testserversec "$N" "$TEST" "$opts -s" "SOCKET-LISTEN:2:6:x${ts1p}x00000000x0000000000000000,reuseaddr,fork,retry=1" "" "range=x0000x7f000000:x0000xffffffff" "SOCKET-CONNECT:2:6:x${ts1p}x${SECONDADDRHEX}x0000000000000000" 4 tcp $PORT 0
fi ;; # $SECONDADDR
esac
PORT=$((PORT+1))
N=$((N+1))
TIOCEXCL="$($PROCAN -c |grep "^#define[[:space:]]*TIOCEXCL[[:space:]]" |cut -d' ' -f3)"
# test the generic ioctl-void option
NAME=IOCTL_VOID
case "$TESTS" in
*%functions%*|*%pty%*|*%generic%*|*%$NAME%*)
TEST="$NAME: test the ioctl-void option"
# there are not many ioctls that apply to non global resources and do not
# require root. TIOCEXCL seems to fit:
# process 0 provides a pty;
# process 1 opens it with the TIOCEXCL ioctl;
# process 2 opens it too and fails with "device or resource busy" only when the
# previous ioctl was successful
if [ -z "$TIOCEXCL" ]; then
# we use the numeric value of TIOCEXL which is system dependent
$PRINTF "test $F_n $TEST... ${YELLOW}no value of TIOCEXCL${NORMAL}\n" $N
numCANT=$((numCANT+1))
else
tp="$td/test$N.pty"
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM"
CMD0="$SOCAT $opts PTY,LINK=$tp pipe"
CMD1="$SOCAT $opts - file:$tp,ioctl-void=$TIOCEXCL,raw,echo=0"
CMD2="$SOCAT $opts - file:$tp,raw,echo=0"
printf "test $F_n $TEST... " $N
$CMD0 >/dev/null 2>"${te}0" &
pid0=$!
waitfile $tp 1
(echo "$da"; sleep 2) |$CMD1 >"$tf" 2>"${te}1" & # this should always work
pid1=$!
usleep 1000000
$CMD2 >/dev/null 2>"${te}2" </dev/null
rc2=$?
kill $pid0 $pid1 2>/dev/null; wait
if ! echo "$da" |diff - "$tf"; then
$PRINTF "${YELLOW}phase 1 failed${NORMAL}\n"
echo "$CMD0 &"
echo "$CMD1"
numCANT=$((numCANT+1))
elif [ $rc2 -eq 0 ]; then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD0 &"
echo "$CMD1"
echo "$CMD2"
cat "${te}0" "${te}1" "${te}2"
numFAIL=$((numFAIL+1))
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat "${te}0" "${te}1" "${te}2"; fi
numOK=$((numOK+1))
fi
fi # !Linux
;;
esac
N=$((N+1))
SOL_SOCKET="$($PROCAN -c |grep "^#define[[:space:]]*SOL_SOCKET[[:space:]]" |cut -d' ' -f3)"
SO_REUSEADDR="$($PROCAN -c |grep "^#define[[:space:]]*SO_REUSEADDR[[:space:]]" |cut -d' ' -f3)"
# test the generic setsockopt-int option
NAME=SETSOCKOPT_INT
case "$TESTS" in
*%functions%*|*%ip4%*|*%tcp%*|*%generic%*|*%$NAME%*)
TEST="$NAME: test the setsockopt-int option"
# there are not many socket options that apply to non global resources, do not
# require root, do not require a network connection, and can easily be
# tested. SO_REUSEADDR seems to fit:
# process 0 provides a tcp listening socket with reuseaddr;
# process 1 connects to this port; thus the port is connected but no longer
# listening
# process 2 tries to listen on this port with SO_REUSEADDR, will fail if the
# (generically specified) SO_REUSEADDR socket options did not work
# process 3 connects to this port; only if it is successful the test is ok
if [ -z "SO_REUSEADDR" ]; then
# we use the numeric value of SO_REUSEADDR which might be system dependent
$PRINTF "test $F_n $TEST... ${YELLOW}value of SO_REUSEADDR not known${NORMAL}\n" $N
numCANT=$((numCANT+1))
else
tp="$PORT"
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM"
CMD0="$SOCAT $opts TCP4-L:$tp,setsockopt-int=$SOL_SOCKET:$SO_REUSEADDR:1 PIPE"
CMD1="$SOCAT $opts - TCP:localhost:$tp"
CMD2="$CMD0"
CMD3="$CMD1"
printf "test $F_n $TEST... " $N
$CMD0 >/dev/null 2>"${te}0" &
pid0=$!
waittcp4port $tp 1
(echo "$da"; sleep 3) |$CMD1 >"$tf" 2>"${te}1" & # this should always work
pid1=$!
usleep 1000000
$CMD2 >/dev/null 2>"${te}2" &
pid2=$!
waittcp4port $tp 1
(echo "$da") |$CMD3 >"${tf}3" 2>"${te}3"
rc3=$?
kill $pid0 $pid1 $pid2 2>/dev/null; wait
if ! echo "$da" |diff - "$tf"; then
$PRINTF "${YELLOW}phase 1 failed${NORMAL}\n"
echo "$CMD0 &"
echo "$CMD1"
numCANT=$((numCANT+1))
elif [ $rc3 -ne 0 ]; then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD2 &"
echo "$CMD3"
cat "${te}2" "${te}3"
numFAIL=$((numFAIL+1))
elif ! echo "$da" |diff - "${tf}3"; then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD2 &"
echo "$CMD3"
echo "$da" |diff - "${tf}3"
numCANT=$((numCANT+1))
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat "${te}0" "${te}1" "${te}2" "${te}3"; fi
numOK=$((numOK+1))
fi
fi # !Linux
;;
esac
PORT=$((PORT+1))
N=$((N+1))
echo "summary: $((N-1)) tests; $numOK ok, $numFAIL failed, $numCANT could not be performed"
if [ "$numFAIL" -gt 0 ]; then

View file

@ -1,5 +1,5 @@
/* source: xio-fd.c */
/* Copyright Gerhard Rieger 2001-2006 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains common file descriptor related option definitions */
@ -75,3 +75,10 @@ const struct optdesc opt_cool_write = { "cool-write", "coolwrite", OPT_COOL_WRIT
/* control closing of connections */
const struct optdesc opt_end_close = { "end-close", "close", OPT_END_CLOSE, GROUP_FD, PH_INIT, TYPE_CONST, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoend, END_CLOSE };
/****** generic ioctl() options ******/
const struct optdesc opt_ioctl_void = { "ioctl-void", "ioctl", OPT_IOCTL_VOID, GROUP_FD, PH_FD, TYPE_INT, OFUNC_IOCTL_GENERIC, 0, 0, 0 };
const struct optdesc opt_ioctl_int = { "ioctl-int", NULL, OPT_IOCTL_INT, GROUP_FD, PH_FD, TYPE_INT_INT, OFUNC_IOCTL_GENERIC, 0, 0, 0 };
const struct optdesc opt_ioctl_intp = { "ioctl-intp", NULL, OPT_IOCTL_INTP, GROUP_FD, PH_FD, TYPE_INT_INTP, OFUNC_IOCTL_GENERIC, 0, 0, 0 };
const struct optdesc opt_ioctl_bin = { "ioctl-bin", NULL, OPT_IOCTL_BIN, GROUP_FD, PH_FD, TYPE_INT_BIN, OFUNC_IOCTL_GENERIC, 0, 0, 0 };
const struct optdesc opt_ioctl_string = { "ioctl-string",NULL, OPT_IOCTL_STRING,GROUP_FD, PH_FD, TYPE_INT_STRING,OFUNC_IOCTL_GENERIC, 0, 0, 0 };

View file

@ -1,10 +1,15 @@
/* source: xio-fd.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_fd_h_included
#define __xio_fd_h_included 1
extern const struct optdesc opt_ioctl_void;
extern const struct optdesc opt_ioctl_int;
extern const struct optdesc opt_ioctl_intp;
extern const struct optdesc opt_ioctl_bin;
extern const struct optdesc opt_ioctl_string;
extern const struct optdesc opt_append;
extern const struct optdesc opt_nonblock;
extern const struct optdesc opt_o_ndelay;

View file

@ -444,92 +444,6 @@ int xiogetaddrinfo(const char *node, const char *service,
}
int xioparsenetwork(const char *rangename, int pf, union xiorange_union *range) {
#if WITH_IP4
struct in_addr *netaddr_in = &range->ip4.netaddr;
struct in_addr *netmask_in = &range->ip4.netmask;
#endif /* WITH_IP4 */
struct hostent *maskaddr;
char *delimpos; /* absolute address of delimiter */
int bits;
switch (pf) {
#if WITH_IP4
char *rangename1; /* a copy of rangename with writing allowed */
case PF_INET:
if ((rangename1 = strdup(rangename)) == NULL) {
Error1("strdup(\"%s\"): out of memory", rangename);
return STAT_RETRYLATER;
}
if (delimpos = strchr(rangename1, '/')) {
bits = strtoul(delimpos+1, NULL, 10);
netmask_in->s_addr = htonl((0xffffffff << (32-bits)));
} else if (delimpos = strchr(rangename1, ':')) {
if ((maskaddr = Gethostbyname(delimpos+1)) == NULL) {
Error2("gethostbyname(\"%s\"): %s", delimpos+1,
h_errno == NETDB_INTERNAL ? strerror(errno) :
hstrerror(h_errno));
return STAT_NORETRY;
}
netmask_in->s_addr = *(uint32_t *)maskaddr->h_addr_list[0];
} else {
Error1("xioparsenetwork(\"%s\",,): missing netmask delimiter", rangename);
free(rangename1);
return STAT_NORETRY;
}
{
struct hostent *nameaddr;
*delimpos = 0;
if ((nameaddr = Gethostbyname(rangename1)) == NULL) {
Error2("gethostbyname(\"%s\"): %s", rangename1,
h_errno == NETDB_INTERNAL ? strerror(errno) :
hstrerror(h_errno));
free(rangename1);
return STAT_NORETRY;
}
netaddr_in->s_addr = *(unsigned long *)nameaddr->h_addr_list[0];
}
free(rangename1);
break;
#endif /* WITH_IP4 */
#if WITH_IP6
case PF_INET6:
return xioparsenetwork_ip6(rangename, &range->ip6);
break;
#endif /* WITH_IP6 */
default:
Error1("range option not supported with address family %d", pf);
return STAT_NORETRY;
}
return STAT_OK;
}
/* parses a string of form address/bits or address:mask, and fills the fields
of the range union. The addr component is masked with mask. */
int parserange(const char *rangename, int pf, union xiorange_union *range) {
if (xioparsenetwork(rangename, pf, range) < 0) {
return -1;
}
switch (pf) {
#if WITH_IP4
case PF_INET:
range->ip4.netaddr.s_addr &= range->ip4.netmask.s_addr;
break;
#endif /* WITH_IP4 */
#if WITH_IP6
case PF_INET6:
return xiorange_ip6andmask(&range->ip6);
break;
#endif /* WITH_IP6 */
default:
Error1("range option not supported with address family %d", pf);
return STAT_NORETRY;
}
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,

View file

@ -42,11 +42,6 @@ extern int xiogetaddrinfo(const char *node, const char *service,
union sockaddr_union *sa, socklen_t *socklen,
unsigned long res_opts0, unsigned long res_opts1);
extern
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,

View file

@ -13,11 +13,57 @@
#include "xio-ip.h"
#include "xio-ip4.h"
int xioparsenetwork_ip4(const char *rangename, struct xiorange *range) {
struct hostent *maskaddr;
struct in_addr *netaddr_in = &range->netaddr.ip4.sin_addr;
struct in_addr *netmask_in = &range->netmask.ip4.sin_addr;
char *rangename1; /* a copy of rangename with writing allowed */
char *delimpos; /* absolute address of delimiter */
int bits;
if ((rangename1 = strdup(rangename)) == NULL) {
Error1("strdup(\"%s\"): out of memory", rangename);
return STAT_RETRYLATER;
}
if (delimpos = strchr(rangename1, '/')) {
bits = strtoul(delimpos+1, NULL, 10);
netmask_in->s_addr = htonl((0xffffffff << (32-bits)));
} else if (delimpos = strchr(rangename1, ':')) {
if ((maskaddr = Gethostbyname(delimpos+1)) == NULL) {
Error2("gethostbyname(\"%s\"): %s", delimpos+1,
h_errno == NETDB_INTERNAL ? strerror(errno) :
hstrerror(h_errno));
return STAT_NORETRY;
}
netmask_in->s_addr = *(uint32_t *)maskaddr->h_addr_list[0];
} else {
Error1("xioparsenetwork_ip4(\"%s\",,): missing netmask delimiter", rangename);
free(rangename1);
return STAT_NORETRY;
}
{
struct hostent *nameaddr;
*delimpos = 0;
if ((nameaddr = Gethostbyname(rangename1)) == NULL) {
Error2("gethostbyname(\"%s\"): %s", rangename1,
h_errno == NETDB_INTERNAL ? strerror(errno) :
hstrerror(h_errno));
free(rangename1);
return STAT_NORETRY;
}
netaddr_in->s_addr = *(unsigned long *)nameaddr->h_addr_list[0];
}
free(rangename1);
return STAT_OK;
}
/* check if peer address is within permitted range.
return >= 0 if so. */
int xiocheckrange_ip4(struct sockaddr_in *pa, struct xiorange_ip4 *range) {
struct in_addr *netaddr_in = &range->netaddr;
struct in_addr *netmask_in = &range->netmask;
int xiocheckrange_ip4(struct sockaddr_in *pa, struct xiorange *range) {
struct in_addr *netaddr_in = &range->netaddr.ip4.sin_addr;
struct in_addr *netmask_in = &range->netmask.ip4.sin_addr;
char addrbuf[256], maskbuf[256];
char peername[256];

View file

@ -7,8 +7,9 @@
extern const struct optdesc opt_ip4_add_membership;
int xioparsenetwork_ip4(const char *rangename, struct xiorange *range);
extern
int xiocheckrange_ip4(struct sockaddr_in *pa, struct xiorange_ip4 *range);
int xiocheckrange_ip4(struct sockaddr_in *pa, struct xiorange *range);
extern int
xiosetsockaddrenv_ip4(int idx, char *namebuff, size_t namelen,
char *valuebuff, size_t valuelen,

View file

@ -51,15 +51,15 @@ const struct optdesc opt_ipv6_recvtclass = { "ipv6-recvtclass", "recvtclass", OP
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) {
int xioparsenetwork_ip6(const char *rangename, struct xiorange *range) {
char *delimpos; /* absolute address of delimiter */
size_t delimind; /* index of delimiter in string */
int bits;
char *baseaddr;
union sockaddr_union sockaddr;
socklen_t sockaddrlen = sizeof(sockaddr);
union xioin6_u *rangeaddr = (union xioin6_u *)&range->addr;
union xioin6_u *rangemask = (union xioin6_u *)&range->mask;
union xioin6_u *rangeaddr = (union xioin6_u *)&range->netaddr.ip6.sin6_addr;
union xioin6_u *rangemask = (union xioin6_u *)&range->netmask.ip6.sin6_addr;
union xioin6_u *nameaddr = (union xioin6_u *)&sockaddr.ip6.sin6_addr;
if (rangename[0] != '[' || rangename[strlen(rangename)-1] != ']') {
@ -117,7 +117,7 @@ int xioparsenetwork_ip6(const char *rangename, struct xiorange_ip6 *range) {
return 0;
}
int xiorange_ip6andmask(struct xiorange_ip6 *range) {
int xiorange_ip6andmask(struct xiorange *range) {
int i;
#if 0
range->addr.s6_addr32[0] &= range->mask.s6_addr32[0];
@ -126,7 +126,8 @@ int xiorange_ip6andmask(struct xiorange_ip6 *range) {
range->addr.s6_addr32[3] &= range->mask.s6_addr32[3];
#else
for (i = 0; i < 16; ++i) {
range->addr.s6_addr[i] &= range->mask.s6_addr[i];
range->netaddr.ip6.sin6_addr.s6_addr[i] &=
range->netmask.ip6.sin6_addr.s6_addr[i];
}
#endif
return 0;
@ -134,12 +135,12 @@ int xiorange_ip6andmask(struct xiorange_ip6 *range) {
/* check if peer address is within permitted range.
return >= 0 if so. */
int xiocheckrange_ip6(struct sockaddr_in6 *pa, struct xiorange_ip6 *range) {
int xiocheckrange_ip6(struct sockaddr_in6 *pa, struct xiorange *range) {
union xioin6_u masked;
int i;
char peername[256];
union xioin6_u *rangeaddr = (union xioin6_u *)&range->addr;
union xioin6_u *rangemask = (union xioin6_u *)&range->mask;
union xioin6_u *rangeaddr = (union xioin6_u *)&range->netaddr.ip6.sin6_addr;
union xioin6_u *rangemask = (union xioin6_u *)&range->netmask.ip6;
Debug16("permitted client subnet: [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
htons(rangeaddr->u6_addr16[0]), htons(rangeaddr->u6_addr16[1]),

View file

@ -28,11 +28,11 @@ 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);
extern int xiorange_ip6andmask(struct xiorange_ip6 *range);
int xioparsenetwork_ip6(const char *rangename, struct xiorange *range);
extern int xiorange_ip6andmask(struct xiorange *range);
extern
int xiocheckrange_ip6(struct sockaddr_in6 *pa, struct xiorange_ip6 *range);
int xiocheckrange_ip6(struct sockaddr_in6 *pa, struct xiorange *range);
extern
int xiolog_ancillary_ip6(struct cmsghdr *cmsg, int *num,
char *typbuff, int typlen,

View file

@ -91,13 +91,16 @@ int
/* creates the listening socket, bind, applies options; waits for incoming
connection, checks its source address and port. Depending on fork option, it
may fork a subprocess.
pf specifies the syntax expected for range option. In the case of generic
socket it is 0 (expecting raw binary data), and the real pf can be obtained
from us->af_family; for other socket types pf == us->af_family
Returns 0 if a connection was accepted; with fork option, this is always in
a subprocess!
Other return values indicate a problem; this can happen in the master
process or in a subprocess.
This function does not retry. If you need retries, handle this in a
loop in the calling function (and always provide the options...)
after fork, we set the forever/retry of the child process to 0
After fork, we set the forever/retry of the child process to 0
applies and consumes the following option:
PH_INIT, PH_PASTSOCKET, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_EARLY,
PH_PREOPEN, PH_FD, PH_CONNECTED, PH_LATE, PH_LATE2
@ -137,7 +140,7 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
xiosetchilddied(); /* set SIGCHLD handler */
}
if ((xfd->fd = xiosocket(opts, pf, socktype, proto, level)) < 0) {
if ((xfd->fd = xiosocket(opts, us->sa_family, socktype, proto, level)) < 0) {
return STAT_RETRYLATER;
}
@ -177,15 +180,10 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
}
#endif /* WITH_UNIX */
retropt_int(opts, OPT_BACKLOG, &backlog);
if (Listen(xfd->fd, backlog) < 0) {
Error3("listen(%d, %d): %s", xfd->fd, backlog, strerror(errno));
return STAT_RETRYLATER;
}
#if WITH_IP4 /*|| WITH_IP6*/
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
if (parserange(rangename, us->sa_family, &xfd->para.socket.range) < 0) {
if (xioparserange(rangename, pf, &xfd->para.socket.range)
< 0) {
free(rangename);
return STAT_NORETRY;
}
@ -205,6 +203,12 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
retropt_bool(opts, OPT_LOWPORT, &xfd->para.socket.ip.lowport);
#endif /* WITH_TCP || WITH_UDP */
retropt_int(opts, OPT_BACKLOG, &backlog);
if (Listen(xfd->fd, backlog) < 0) {
Error3("listen(%d, %d): %s", xfd->fd, backlog, strerror(errno));
return STAT_RETRYLATER;
}
if (xioopts.logopt == 'm') {
Info("starting accept loop, switching to syslog");
diag_set('y', xioopts.syslogfac); xioopts.logopt = 'y';

View file

@ -176,7 +176,7 @@ int xioopen_rawip_datagram(int argc, const char *argv[], struct opt *opts,
/* which reply packets will be accepted - determine by range option */
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
if (parserange(rangename, pf, &xfd->para.socket.range) < 0) {
if (xioparserange(rangename, pf, &xfd->para.socket.range) < 0) {
free(rangename);
return STAT_NORETRY;
}
@ -291,7 +291,8 @@ int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts,
#endif
}
if (retropt_bind(opts, pf, socktype, ipproto, &/*us.soa*/xfd->stream.para.socket.la.soa, &uslen, 1,
if (retropt_bind(opts, pf, socktype, ipproto,
&/*us.soa*/xfd->stream.para.socket.la.soa, &uslen, 1,
xfd->stream.para.socket.ip.res_opts[0],
xfd->stream.para.socket.ip.res_opts[1]) ==
STAT_OK) {
@ -304,7 +305,8 @@ int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts,
xfd->stream.dtype = XIODATA_RECV_SKIPIP;
result =
_xioopen_dgram_recv(&xfd->stream, xioflags,
needbind?&xfd->stream.para.socket.la.soa:NULL, uslen,
needbind?&/*us.soa*/xfd->stream.para.socket.la.soa:NULL,
uslen,
opts, pf, socktype, ipproto, E_ERROR);
_xio_openlate(&xfd->stream, opts);
return result;

View file

@ -2,7 +2,8 @@
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for socket related functions */
/* this file contains the source for socket related functions, and the
implementation of generic socket addresses */
#include "xiosysincludes.h"
@ -20,10 +21,42 @@
#include "xio-ip6.h"
#endif /* WITH_IP6 */
#include "xio-ip.h"
#include "xio-listen.h"
#include "xio-ipapp.h" /*! not clean */
#include "xio-tcpwrap.h"
static
int xioopen_socket_connect(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups,
int dummy1, int dummy2, int dummy3);
static
int xioopen_socket_listen(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups,
int dummy1, int dummy2, int dummy3);
static
int xioopen_socket_sendto(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups,
int dummy1, int dummy2, int dummy3);
static
int xioopen_socket_datagram(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups,
int dummy1, int dummy2, int dummy3);
static
int xioopen_socket_recvfrom(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups,
int dummy1, int socktype, int dummy3);
static
int xioopen_socket_recv(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups,
int dumy1, int dummy2, int dummy3);
static
int _xioopen_socket_sendto(const char *pfname, const char *type,
const char *proto, const char *address,
struct opt *opts, int xioflags, xiofile_t *xxfd,
unsigned groups);
static int
xiolog_ancillary_socket(struct cmsghdr *cmsg, int *num,
char *typbuff, int typlen,
@ -32,6 +65,17 @@ xiolog_ancillary_socket(struct cmsghdr *cmsg, int *num,
char *valbuff, int vallen);
/* generic socket addresses */
const struct addrdesc xioaddr_socket_connect = { "socket-connect", 1, xioopen_socket_connect, GROUP_FD|GROUP_SOCKET|GROUP_CHILD|GROUP_RETRY, 0, 0, 0 HELP(":<domain>:<protocol>:<remote-address>") };
const struct addrdesc xioaddr_socket_listen = { "socket-listen", 1, xioopen_socket_listen, GROUP_FD|GROUP_SOCKET|GROUP_LISTEN|GROUP_RANGE|GROUP_CHILD|GROUP_RETRY, 0, 0, 0 HELP(":<domain>:<protocol>:<local-address>") };
const struct addrdesc xioaddr_socket_sendto = { "socket-sendto", 3, xioopen_socket_sendto, GROUP_FD|GROUP_SOCKET, 0, 0, 0 HELP(":<domain>:<type>:<protocol>:<remote-address>") };
const struct addrdesc xioaddr_socket_datagram= { "socket-datagram", 3, xioopen_socket_datagram, GROUP_FD|GROUP_SOCKET|GROUP_RANGE, 0, 0, 0 HELP(":<domain>:<type>:<protocol>:<remote-address>") };
const struct addrdesc xioaddr_socket_recvfrom= { "socket-recvfrom", 3, xioopen_socket_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_RANGE|GROUP_CHILD, 0, 0, 0 HELP(":<domain>:<type>:<protocol>:<local-address>") };
const struct addrdesc xioaddr_socket_recv = { "socket-recv", 1, xioopen_socket_recv, GROUP_FD|GROUP_SOCKET|GROUP_RANGE, 0, 0, 0 HELP(":<domain>:<type>:<protocol>:<local-address>") };
/* the following options apply not only to generic socket addresses but to all
addresses that have anything to do with sockets */
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};
@ -143,6 +187,504 @@ const struct optdesc opt_connect_timeout = { "connect-timeout", NULL, OPT_CONNEC
const struct optdesc opt_protocol_family = { "protocol-family", "pf", OPT_PROTOCOL_FAMILY, GROUP_SOCKET, PH_PRESOCKET, TYPE_STRING, OFUNC_SPEC };
const struct optdesc opt_protocol = { "protocol", NULL, OPT_PROTOCOL, GROUP_SOCKET, PH_PRESOCKET, TYPE_STRING, OFUNC_SPEC };
/* generic setsockopt() options */
const struct optdesc opt_setsockopt_int = { "setsockopt-int", "sockopt-int", OPT_SETSOCKOPT_INT, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_INT, OFUNC_SOCKOPT_GENERIC, 0, 0 };
const struct optdesc opt_setsockopt_bin = { "setsockopt-bin", "sockopt-bin", OPT_SETSOCKOPT_BIN, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_BIN, OFUNC_SOCKOPT_GENERIC, 0, 0 };
const struct optdesc opt_setsockopt_string = { "setsockopt-string", "sockopt-string", OPT_SETSOCKOPT_STRING, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_STRING, OFUNC_SOCKOPT_GENERIC, 0, 0 };
static
int xioopen_socket_connect(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd, unsigned groups,
int dummy1, int dummy2, int dummy3) {
struct single *xfd = &xxfd->stream;
const char *pfname = argv[1];
const char *protname = argv[2];
const char *address = argv[3];
char *garbage;
int pf;
int proto;
int socktype = SOCK_STREAM;
int needbind = 0;
union sockaddr_union them; socklen_t themlen;
union sockaddr_union us; socklen_t uslen = sizeof(us);
int result;
if (argc != 4) {
Error2("%s: wrong number of parameters (%d instead of 3)",
argv[0], argc-1);
return STAT_NORETRY;
}
pf = strtoul(pfname, &garbage, 0);
if (*garbage != '\0') {
Warn1("garbage in parameter: \"%s\"", garbage);
}
proto = strtoul(protname, &garbage, 0);
if (*garbage != '\0') {
Warn1("garbage in parameter: \"%s\"", garbage);
}
retropt_socket_pf(opts, &pf);
retropt_int(opts, OPT_SO_TYPE, &socktype);
/*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
xfd->howtoend = END_SHUTDOWN;
applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_EARLY);
themlen = 0;
if ((result =
dalan(address, (char *)&them.soa.sa_data, &themlen, sizeof(them)))
< 0) {
Error1("data too long: \"%s\"", address);
} else if (result > 0) {
Error1("syntax error in \"%s\"", address);
}
them.soa.sa_family = pf;
themlen +=
#if HAVE_STRUCT_SOCKADDR_SALEN
sizeof(them.soa.sa_len) +
#endif
sizeof(them.soa.sa_family);
xfd->dtype = XIOREAD_STREAM|XIOWRITE_STREAM;
socket_init(0, &us);
if (retropt_bind(opts, 0 /*pf*/, socktype, proto, (struct sockaddr *)&us, &uslen, 3,
0, 0)
!= STAT_NOACTION) {
needbind = true;
us.soa.sa_family = pf;
}
if ((result =
xioopen_connect(xfd,
needbind?(struct sockaddr *)&us:NULL, uslen,
(struct sockaddr *)&them, themlen,
opts, pf, socktype, proto, false)) != 0) {
return result;
}
if ((result = _xio_openlate(xfd, opts)) < 0) {
return result;
}
return STAT_OK;
}
static
int xioopen_socket_listen(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd, unsigned groups,
int dummy1, int dummy2, int dummy3) {
struct single *xfd = &xxfd->stream;
const char *pfname = argv[1];
const char *protname = argv[2];
const char *usname = argv[3];
char *garbage;
int pf;
int proto;
int socktype = SOCK_STREAM;
union sockaddr_union us; socklen_t uslen;
struct opt *opts0;
int result;
if (argc != 4) {
Error2("%s: wrong number of parameters (%d instead of 3)",
argv[0], argc-1);
return STAT_NORETRY;
}
pf = strtoul(pfname, &garbage, 0);
if (*garbage != '\0') {
Warn1("garbage in parameter: \"%s\"", garbage);
}
proto = strtoul(protname, &garbage, 0);
if (*garbage != '\0') {
Warn1("garbage in parameter: \"%s\"", garbage);
}
retropt_socket_pf(opts, &pf);
retropt_int(opts, OPT_SO_TYPE, &socktype);
/*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
xfd->howtoend = END_SHUTDOWN;
socket_init(0, &us);
uslen = 0;
if ((result =
dalan(usname, (char *)&us.soa.sa_data, &uslen, sizeof(us)))
< 0) {
Error1("data too long: \"%s\"", usname);
} else if (result > 0) {
Error1("syntax error in \"%s\"", usname);
}
uslen += sizeof(us.soa.sa_family)
#if HAVE_STRUCT_SOCKADDR_SALEN
+ sizeof(us.soa.sa_len)
#endif
;
us.soa.sa_family = pf;
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT);
applyopts(-1, opts, PH_EARLY);
opts0 = copyopts(opts, GROUP_ALL);
if ((result =
xioopen_listen(xfd, xioflags,
(struct sockaddr *)&us, uslen,
opts, opts0, 0/*instead of pf*/, socktype, proto))
!= STAT_OK)
return result;
return STAT_OK;
}
/* we expect the form: ...:domain:type:protocol:remote-address */
static
int xioopen_socket_sendto(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd, unsigned groups,
int dummy1, int dummy2, int dummy3) {
int result;
if (argc != 5) {
Error2("%s: wrong number of parameters (%d instead of 4)",
argv[0], argc-1);
return STAT_NORETRY;
}
if ((result =
_xioopen_socket_sendto(argv[1], argv[2], argv[3], argv[4],
opts, xioflags, xxfd, groups))
!= STAT_OK) {
return result;
}
_xio_openlate(&xxfd->stream, opts);
return STAT_OK;
}
static
int _xioopen_socket_sendto(const char *pfname, const char *type,
const char *protname, const char *address,
struct opt *opts, int xioflags, xiofile_t *xxfd,
unsigned groups) {
xiosingle_t *xfd = &xxfd->stream;
char *garbage;
union sockaddr_union us = {{0}};
socklen_t uslen = 0;
socklen_t themlen = 0;
int pf;
int socktype = SOCK_RAW;
int proto;
bool needbind = false;
char *bindstring = NULL;
int result;
pf = strtoul(pfname, &garbage, 0);
if (*garbage != '\0') {
Warn1("garbage in parameter: \"%s\"", garbage);
}
socktype = strtoul(type, &garbage, 0);
if (*garbage != '\0') {
Warn1("garbage in parameter: \"%s\"", garbage);
}
proto = strtoul(protname, &garbage, 0);
if (*garbage != '\0') {
Warn1("garbage in parameter: \"%s\"", garbage);
}
retropt_socket_pf(opts, &pf);
retropt_int(opts, OPT_SO_TYPE, &socktype);
/*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
xfd->howtoend = END_SHUTDOWN;
xfd->peersa.soa.sa_family = pf;
themlen = 0;
if ((result =
dalan(address, (char *)&xfd->peersa.soa.sa_data, &themlen,
sizeof(xfd->peersa)))
< 0) {
Error1("data too long: \"%s\"", address);
} else if (result > 0) {
Error1("syntax error in \"%s\"", address);
}
xfd->salen = themlen + sizeof(sa_family_t)
#if HAVE_STRUCT_SOCKADDR_SALEN
+ sizeof(xfd->peersa.soa.sa_len)
#endif
;
#if HAVE_STRUCT_SOCKADDR_SALEN
xfd->peersa.soa.sa_len =
sizeof(xfd->peersa.soa.sa_len) + sizeof(xfd->peersa.soa.sa_family) +
themlen;
#endif
/* ...res_opts[] */
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT);
if (pf == PF_UNSPEC) {
pf = xfd->peersa.soa.sa_family;
}
xfd->dtype = XIODATA_RECVFROM;
if (retropt_string(opts, OPT_BIND, &bindstring) == 0) {
uslen = 0;
if ((result =
dalan(bindstring, (char *)&us.soa.sa_data, &uslen, sizeof(us)))
< 0) {
Error1("data too long: \"%s\"", bindstring);
} else if (result > 0) {
Error1("syntax error in \"%s\"", bindstring);
}
us.soa.sa_family = pf;
uslen += sizeof(sa_family_t)
#if HAVE_STRUCT_SOCKADDR_SALEN
+ sizeof(us.soa.sa_len)
#endif
;
needbind = true;
}
return
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
opts, xioflags, xfd, groups, pf, socktype, proto);
}
/* we expect the form: ...:domain:socktype:protocol:local-address */
static
int xioopen_socket_recvfrom(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd, unsigned groups,
int dummy, int summy2, int dummy3) {
struct single *xfd = &xxfd->stream;
const char *pfname = argv[1];
const char *typename = argv[2];
const char *protname = argv[3];
const char *address = argv[4];
char *garbage;
union sockaddr_union *us = &xfd->para.socket.la;
socklen_t uslen = sizeof(*us);
int pf, socktype, proto;
char *rangename;
int result;
if (argc != 5) {
Error2("%s: wrong number of parameters (%d instead of 4)",
argv[0], argc-1);
return STAT_NORETRY;
}
pf = strtoul(pfname, &garbage, 0);
if (*garbage != '\0') {
Warn1("garbage in parameter: \"%s\"", garbage);
}
socktype = strtoul(typename, &garbage, 0);
if (*garbage != '\0') {
Warn1("garbage in parameter: \"%s\"", garbage);
}
proto = strtoul(protname, &garbage, 0);
if (*garbage != '\0') {
Warn1("garbage in parameter: \"%s\"", garbage);
}
retropt_socket_pf(opts, &pf);
retropt_int(opts, OPT_SO_TYPE, &socktype);
/*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
xfd->howtoend = END_NONE;
uslen = 0;
if ((result =
dalan(address, (char *)&us->soa.sa_data, &uslen, sizeof(*us)))
< 0) {
Error1("data too long: \"%s\"", address);
} else if (result > 0) {
Error1("syntax error in \"%s\"", address);
}
us->soa.sa_family = pf;
uslen += sizeof(us->soa.sa_family)
#if HAVE_STRUCT_SOCKADDR_SALEN
+ sizeof(us->soa.sa_len);
#endif
;
xfd->dtype = XIOREAD_RECV|XIOWRITE_SENDTO;
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
if (xioparserange(rangename, 0, &xfd->para.socket.range) < 0) {
return STAT_NORETRY;
}
xfd->para.socket.dorange = true;
free(rangename);
}
if ((result =
_xioopen_dgram_recvfrom(xfd, xioflags, &us->soa, uslen,
opts, pf, socktype, proto, E_ERROR))
!= STAT_OK) {
return result;
}
_xio_openlate(xfd, opts);
return STAT_OK;
}
/* we expect the form: ...:domain:type:protocol:local-address */
static
int xioopen_socket_recv(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd, unsigned groups,
int dummy1, int dummy2, int dummy3) {
struct single *xfd = &xxfd->stream;
const char *pfname = argv[1];
const char *typename = argv[2];
const char *protname = argv[3];
const char *address = argv[4];
char *garbage;
union sockaddr_union us;
socklen_t uslen = sizeof(us);
int pf, socktype, proto;
char *rangename;
int result;
if (argc != 5) {
Error2("%s: wrong number of parameters (%d instead of 4)",
argv[0], argc-1);
return STAT_NORETRY;
}
pf = strtoul(pfname, &garbage, 0);
if (*garbage != '\0') {
Warn1("garbage in parameter: \"%s\"", garbage);
}
socktype = strtoul(typename, &garbage, 0);
if (*garbage != '\0') {
Warn1("garbage in parameter: \"%s\"", garbage);
}
proto = strtoul(protname, &garbage, 0);
if (*garbage != '\0') {
Warn1("garbage in parameter: \"%s\"", garbage);
}
retropt_socket_pf(opts, &pf);
retropt_int(opts, OPT_SO_TYPE, &socktype);
/*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
xfd->howtoend = END_NONE;
uslen = 0;
if ((result =
dalan(address, (char *)&us.soa.sa_data, &uslen, sizeof(us)))
< 0) {
Error1("data too long: \"%s\"", address);
} else if (result > 0) {
Error1("syntax error in \"%s\"", address);
}
us.soa.sa_family = pf;
uslen += sizeof(sa_family_t)
#if HAVE_STRUCT_SOCKADDR_SALEN
+sizeof(us.soa.sa_len)
#endif
;
xfd->dtype = XIOREAD_RECV;
xfd->para.socket.la.soa.sa_family = pf;
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
if (xioparserange(rangename, 0, &xfd->para.socket.range) < 0) {
return STAT_NORETRY;
}
xfd->para.socket.dorange = true;
free(rangename);
}
if ((result =
_xioopen_dgram_recv(xfd, xioflags, &us.soa,
uslen, opts, pf, socktype, proto, E_ERROR))
!= STAT_OK) {
return result;
}
_xio_openlate(xfd, opts);
return STAT_OK;
}
/* we expect the form: ...:domain:type:protocol:remote-address */
static
int xioopen_socket_datagram(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd, unsigned groups,
int dummy1, int dummy2, int dummy3) {
xiosingle_t *xfd = &xxfd->stream;
const char *pfname = argv[1];
const char *typename = argv[2];
const char *protname = argv[3];
const char *address = argv[4];
char *garbage;
char *rangename;
socklen_t themlen;
int pf;
int result;
if (argc != 5) {
Error2("%s: wrong number of parameters (%d instead of 4)",
argv[0], argc-1);
return STAT_NORETRY;
}
pf = strtoul(pfname, &garbage, 0);
if (*garbage != '\0') {
Warn1("garbage in parameter: \"%s\"", garbage);
}
retropt_socket_pf(opts, &pf);
/*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
xfd->howtoend = END_SHUTDOWN;
xfd->peersa.soa.sa_family = pf;
themlen = 0;
if ((result =
dalan(address, (char *)&xfd->peersa.soa.sa_data, &themlen,
sizeof(xfd->peersa)))
< 0) {
Error1("data too long: \"%s\"", address);
} else if (result > 0) {
Error1("syntax error in \"%s\"", address);
}
xfd->salen = themlen + sizeof(sa_family_t);
#if HAVE_STRUCT_SOCKADDR_SALEN
xfd->peersa.soa.sa_len =
sizeof(xfd->peersa.soa.sa_len) + sizeof(xfd->peersa.soa.sa_family) +
themlen;
#endif
if ((result =
_xioopen_socket_sendto(pfname, typename, protname, address,
opts, xioflags, xxfd, groups))
!= STAT_OK) {
return result;
}
xfd->dtype = XIOREAD_RECV|XIOWRITE_SENDTO;
xfd->para.socket.la.soa.sa_family = xfd->peersa.soa.sa_family;
/* which reply sockets will accept - determine by range option */
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
if (xioparserange(rangename, 0, &xfd->para.socket.range) < 0) {
free(rangename);
return STAT_NORETRY;
}
xfd->para.socket.dorange = true;
xfd->dtype |= XIOREAD_RECV_CHECKRANGE;
free(rangename);
}
_xio_openlate(xfd, opts);
return STAT_OK;
}
/* a subroutine that is common to all socket addresses that want to connect
to a peer address.
might fork.
@ -675,9 +1217,9 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
}
#endif /* WITH_UNIX */
#if WITH_IP4 /*|| WITH_IP6*/
/* for generic sockets, this has already been retrieved */
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
if (parserange(rangename, pf, &xfd->para.socket.range)
if (xioparserange(rangename, pf, &xfd->para.socket.range)
< 0) {
free(rangename);
return STAT_NORETRY;
@ -685,7 +1227,6 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
free(rangename);
xfd->para.socket.dorange = true;
}
#endif
#if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP
xio_retropt_tcpwrap(xfd, opts);
@ -930,7 +1471,7 @@ int _xioopen_dgram_recv(struct single *xfd, int xioflags,
#if WITH_IP4 /*|| WITH_IP6*/
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
if (parserange(rangename, pf, &xfd->para.socket.range)
if (xioparserange(rangename, pf, &xfd->para.socket.range)
< 0) {
free(rangename);
return STAT_NORETRY;
@ -1104,17 +1645,17 @@ int xiodopacketinfo(struct msghdr *msgh, bool withlog, bool withenv) {
}
int xiocheckrange(union sockaddr_union *sa, union xiorange_union *range) {
int xiocheckrange(union sockaddr_union *sa, struct xiorange *range) {
switch (sa->soa.sa_family) {
#if WITH_IP4
case PF_INET:
return
xiocheckrange_ip4(&sa->ip4, &range->ip4);
xiocheckrange_ip4(&sa->ip4, range);
#endif /* WITH_IP4 */
#if WITH_IP6
case PF_INET6:
return
xiocheckrange_ip6(&sa->ip6, &range->ip6);
xiocheckrange_ip6(&sa->ip6, range);
#endif /* WITH_IP6 */
}
return -1;
@ -1208,6 +1749,7 @@ 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
@ -1327,6 +1869,111 @@ char *xiogetifname(int ind, char *val, int ins) {
}
/* parses a network specification consisting of an address and a mask. */
int xioparsenetwork(const char *rangename, int pf, struct xiorange *range) {
size_t addrlen = 0, masklen = 0;
int result;
switch (pf) {
#if WITH_IP4
case PF_INET:
return xioparsenetwork_ip4(rangename, range);
break;
#endif /* WITH_IP4 */
#if WITH_IP6
case PF_INET6:
return xioparsenetwork_ip6(rangename, range);
break;
#endif /* WITH_IP6 */
case PF_UNSPEC:
{
char *addrname;
const char *maskname;
if ((maskname = strchr(rangename, ':')) == NULL) {
Error1("syntax error in range \"%s\": use <addr>:<mask>", rangename);
return STAT_NORETRY;
}
++maskname; /* skip ':' */
if ((addrname = Malloc(maskname-rangename)) == NULL) {
return STAT_NORETRY;
}
strncpy(addrname, rangename, maskname-rangename-1);
addrname[maskname-rangename-1] = '\0';
result =
dalan(addrname, (char *)&range->netaddr.soa.sa_data, &addrlen,
sizeof(range->netaddr)-(size_t)(&((struct sockaddr *)0)->sa_data)
/* data length */);
if (result < 0) {
Error1("data too long: \"%s\"", addrname);
free(addrname); return STAT_NORETRY;
} else if (result > 0) {
Error1("syntax error in \"%s\"", addrname);
free(addrname); return STAT_NORETRY;
}
free(addrname);
result =
dalan(maskname, (char *)&range->netmask.soa.sa_data, &masklen,
sizeof(range->netaddr)-(size_t)(&((struct sockaddr *)0)->sa_data)
/* data length */);
if (result < 0) {
Error1("data too long: \"%s\"", maskname);
return STAT_NORETRY;
} else if (result > 0) {
Error1("syntax error in \"%s\"", maskname);
return STAT_NORETRY;
}
if (addrlen != masklen) {
Error2("network address is "F_Zu" bytes long, mask is "F_Zu" bytes long",
addrlen, masklen);
/* recover by padding the shorter component with 0 */
memset((char *)&range->netaddr.soa.sa_data+addrlen, 0,
MAX(0, addrlen-masklen));
memset((char *)&range->netmask.soa.sa_data+masklen, 0,
MAX(0, masklen-addrlen));
}
}
break;
default:
Error1("range option not supported with address family %d", pf);
return STAT_NORETRY;
}
return STAT_OK;
}
/* parses a string of form address/bits or address:mask, and fills the fields
of the range union. The addr component is masked with mask. */
int xioparserange(const char *rangename, int pf, struct xiorange *range) {
int i;
if (xioparsenetwork(rangename, pf, range) < 0) {
return -1;
}
/* we have parsed the address and mask; now we make sure that the stored
address has 0 where mask is 0, to simplify comparisions */
switch (pf) {
#if WITH_IP4
case PF_INET:
range->netaddr.ip4.sin_addr.s_addr &= range->netmask.ip4.sin_addr.s_addr;
break;
#endif /* WITH_IP4 */
#if WITH_IP6
case PF_INET6:
return xiorange_ip6andmask(range);
break;
#endif /* WITH_IP6 */
case PF_UNSPEC:
for (i = 0; i < sizeof(range->netaddr); ++i) {
((char *)&range->netaddr)[i] &= ((char *)&range->netmask)[i];
}
break;
default:
Error1("range option not supported with address family %d", pf);
return STAT_NORETRY;
}
return 0;
}
/* 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

View file

@ -11,6 +11,13 @@
#define SO_PROTOTYPE 0x9999
#endif
extern const struct addrdesc xioaddr_socket_connect;
extern const struct addrdesc xioaddr_socket_listen;
extern const struct addrdesc xioaddr_socket_sendto;
extern const struct addrdesc xioaddr_socket_datagram;
extern const struct addrdesc xioaddr_socket_recvfrom;
extern const struct addrdesc xioaddr_socket_recv;
extern const struct optdesc opt_connect_timeout;
extern const struct optdesc opt_so_debug;
extern const struct optdesc opt_so_acceptconn;
@ -57,6 +64,9 @@ extern const struct optdesc opt_fiosetown;
extern const struct optdesc opt_siocspgrp;
extern const struct optdesc opt_bind;
extern const struct optdesc opt_protocol_family;
extern const struct optdesc opt_setsockopt_int;
extern const struct optdesc opt_setsockopt_bin;
extern const struct optdesc opt_setsockopt_string;
extern
@ -101,11 +111,18 @@ 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);
extern
int xioparsenetwork(const char *rangename, int pf,
struct xiorange *range);
extern
int xioparserange(const char *rangename, int pf, struct xiorange *range);
extern int
xiosocket(struct opt *opts, int pf, int socktype, int proto, int level);
extern int
xiosocketpair(struct opt *opts, int pf, int socktype, int proto, int sv[2]);
extern
int xiosetsockaddrenv(const char *lr, union sockaddr_union *sau, socklen_t salen, int proto);
#endif /* !defined(__xio_socket_h_included) */

View file

@ -68,7 +68,7 @@ static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xiofl
char *tundevice = NULL;
char *tunname = NULL, *tuntype = NULL;
int pf = /*! PF_UNSPEC*/ PF_INET;
union xiorange_union network;
struct xiorange network;
bool no_pi = false;
const char *namedargv[] = { "tun", NULL, NULL };
int rw = (xioflags & XIO_ACCMODE);
@ -155,12 +155,14 @@ static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xiofl
return result;
}
socket_init(pf, (union sockaddr_union *)&ifr.ifr_addr);
((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr = network.ip4.netaddr;
((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr =
network.netaddr.ip4.sin_addr;
if (Ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) {
Error4("ioctl(%d, SIOCSIFADDR, {\"%s\", \"%s\"}: %s",
sockfd, ifr.ifr_name, ifaddr, strerror(errno));
}
((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr = network.ip4.netmask;
((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr =
network.netmask.ip4.sin_addr;
if (Ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) {
Error4("ioctl(%d, SIOCSIFNETMASK, {\"0x%08u\", \"%s\"}, %s",
sockfd, ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr,

View file

@ -144,7 +144,7 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
#if WITH_IP4 /*|| WITH_IP6*/
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
if (parserange(rangename, pf, &fd->stream.para.socket.range) < 0) {
if (xioparserange(rangename, pf, &fd->stream.para.socket.range) < 0) {
free(rangename);
return STAT_NORETRY;
}
@ -433,7 +433,7 @@ int xioopen_udp_datagram(int argc, const char *argv[], struct opt *opts,
/* which reply packets will be accepted - determine by range option */
if (retropt_string(opts, OPT_RANGE, &rangename)
>= 0) {
if (parserange(rangename, pf, &xfd->para.socket.range) < 0) {
if (xioparserange(rangename, pf, &xfd->para.socket.range) < 0) {
free(rangename);
return STAT_NORETRY;
}
@ -591,7 +591,7 @@ int xioopen_udp_recv(int argc, const char *argv[], struct opt *opts,
#if WITH_IP4 /*|| WITH_IP6*/
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
if (parserange(rangename, pf, &xfd->stream.para.socket.range) < 0) {
if (xioparserange(rangename, pf, &xfd->stream.para.socket.range) < 0) {
return STAT_NORETRY;
}
xfd->stream.para.socket.dorange = true;

View file

@ -105,6 +105,9 @@ xiosetunix(int pf,
if (tight) {
len = sizeof(struct sockaddr_un)-sizeof(saun->sun_path)+
MIN(pathlen, sizeof(saun->sun_path));
#if HAVE_STRUCT_SOCKADDR_SALEN
saun->sun_len = len;
#endif
} else {
len = sizeof(struct sockaddr_un);
}
@ -238,7 +241,7 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts,
if ((result = _xio_openlate(xfd, opts)) < 0) {
return result;
}
return 0;
return STAT_OK;
}

4
xio.h
View file

@ -179,7 +179,7 @@ typedef struct single {
union sockaddr_union la; /* local socket address */
bool emptyiseof; /* with dgram: empty packet means EOF */
bool dorange;
union xiorange_union range; /* restrictions for peer address */
struct xiorange range; /* restrictions for peer address */
#if _WITH_IP4 || _WITH_IP6
struct {
unsigned int res_opts[2]; /* bits to be set in _res.options are
@ -357,6 +357,8 @@ union integral {
struct opt {
const struct optdesc *desc;
union integral value;
union integral value2;
union integral value3;
} ;
extern const char *PIPESEP;

View file

@ -66,12 +66,12 @@ int xioclose1(struct single *pipe) {
case END_CLOSE: case END_CLOSE_KILL:
if (Close(pipe->fd) < 0) {
Info2("close(%d): %s", pipe->fd, strerror(errno)); } break;
#if WITH_SOCKET
#if _WITH_SOCKET
case END_SHUTDOWN: case END_SHUTDOWN_KILL:
if (Shutdown(pipe->fd, 2) < 0) {
Info3("shutdown(%d, %d): %s", pipe->fd, 2, strerror(errno)); }
break;
#endif /* WITH_SOCKET */
#endif /* _WITH_SOCKET */
case END_UNLINK: if (Unlink((const char *)pipe->name) < 0) {
Warn2("unlink(\"%s\"): %s", pipe->name, strerror(errno)); }
break;

View file

@ -47,13 +47,13 @@
# endif
#endif
#if WITH_UNIX || WITH_IP4 || WITH_IP6 || WITH_SOCKS4 || WITH_RAWIP
# define WITH_SOCKET 1
#if WITH_UNIX || WITH_IP4 || WITH_IP6 || WITH_SOCKS4 || WITH_RAWIP || WITH_GENERICSOCKET
# define _WITH_SOCKET 1
#else
# undef WITH_SOCKET
# undef _WITH_SOCKET
#endif
#if !WITH_SOCKET
#if !_WITH_SOCKET
# undef WITH_LISTEN
#endif
@ -61,7 +61,7 @@
# undef WITH_LIBWRAP
#endif
#if WITH_SOCKET || WITH_TUN
#if WITH_GENERICSOCKET || WITH_TUN
# define _WITH_SOCKET 1
#endif

View file

@ -29,6 +29,8 @@ static const char *optiontypenames[] = {
"STRUCT-IP_MREQ",
#endif
"IP4NAME",
"INT:INT", "INT:INTP", "INT:BIN", "INT:STRING",
"INT:INT:INT", "INT:INT:BIN", "INT:INT:STRING",
} ;

View file

@ -1,5 +1,5 @@
/* source: xiomodes.h */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xiomodes_h_included
@ -15,7 +15,7 @@
#include "xio-creat.h"
#include "xio-gopen.h"
#include "xio-pipe.h"
#if WITH_SOCKET
#if _WITH_SOCKET
#include "xio-socket.h"
#include "xio-listen.h"
#include "xio-unix.h"
@ -30,7 +30,7 @@
#include "xio-udp.h"
#include "xio-socks.h"
#include "xio-proxy.h"
#endif /* WITH_SOCKET */
#endif /* _WITH_SOCKET */
#include "xio-progcall.h"
#include "xio-exec.h"
#include "xio-system.h"

View file

@ -37,6 +37,10 @@ const struct addrname addressnames[] = {
{ "creat", &addr_creat },
{ "create", &addr_creat },
#endif
#if WITH_GENERICSOCKET
{ "datagram", &xioaddr_socket_datagram },
{ "dgram", &xioaddr_socket_datagram },
#endif
#if WITH_PIPE
{ "echo", &addr_pipe },
#endif
@ -131,6 +135,17 @@ const struct addrname addressnames[] = {
#if WITH_READLINE
{ "readline", &addr_readline },
#endif
#if WITH_GENERICSOCKET
{ "sendto", &xioaddr_socket_sendto },
#endif
#if WITH_GENERICSOCKET
{ "socket-connect", &xioaddr_socket_connect },
{ "socket-datagram", &xioaddr_socket_datagram },
{ "socket-listen", &xioaddr_socket_listen },
{ "socket-recv", &xioaddr_socket_recv },
{ "socket-recvfrom", &xioaddr_socket_recvfrom },
{ "socket-sendto", &xioaddr_socket_sendto },
#endif
#if WITH_SOCKS4
{ "socks", &addr_socks4_connect },
{ "socks4", &addr_socks4_connect },
@ -296,9 +311,9 @@ static xiofile_t *xioallocfd(void) {
fd->stream.fd = -1;
fd->stream.dtype = XIODATA_STREAM;
#if WITH_SOCKET
#if _WITH_SOCKET
/* fd->stream.salen = 0; */
#endif /* WITH_SOCKET */
#endif /* _WITH_SOCKET */
fd->stream.howtoend = END_UNSPEC;
/* fd->stream.name = NULL; */
fd->stream.escape = -1;

295
xioopts.c
View file

@ -40,7 +40,7 @@ bool xioopts_ignoregroups;
# define IF_EXEC(a,b)
#endif
#if WITH_SOCKET
#if _WITH_SOCKET
# define IF_SOCKET(a,b) {a,b},
#else
# define IF_SOCKET(a,b)
@ -593,6 +593,12 @@ const struct optname optionnames[] = {
IF_RETRY ("interval", &opt_intervall)
IF_RETRY ("intervall", &opt_intervall)
IF_TERMIOS("intr", &opt_vintr)
IF_ANY ("ioctl", &opt_ioctl_void)
IF_ANY ("ioctl-bin", &opt_ioctl_bin)
IF_ANY ("ioctl-int", &opt_ioctl_int)
IF_ANY ("ioctl-intp", &opt_ioctl_intp)
IF_ANY ("ioctl-string", &opt_ioctl_string)
IF_ANY ("ioctl-void", &opt_ioctl_void)
#ifdef IP_ADD_MEMBERSHIP
IF_IP ("ip-add-membership", &opt_ip_add_membership)
#endif
@ -1246,6 +1252,9 @@ const struct optname optionnames[] = {
#if WITH_EXEC || WITH_SYSTEM
IF_EXEC ("setsid", &opt_setsid)
#endif
IF_SOCKET ("setsockopt-bin", &opt_setsockopt_bin)
IF_SOCKET ("setsockopt-int", &opt_setsockopt_int)
IF_SOCKET ("setsockopt-string", &opt_setsockopt_string)
IF_ANY ("setuid", &opt_setuid)
IF_ANY ("setuid-early", &opt_setuid_early)
#if WITH_EXEC || WITH_SYSTEM
@ -1363,6 +1372,9 @@ const struct optname optionnames[] = {
#ifdef SO_USELOOPBACK /* AIX433, Solaris */
IF_SOCKET ("so-useloopback", &opt_so_useloopback)
#endif /* SO_USELOOPBACK */
IF_SOCKET ("sockopt-bin", &opt_setsockopt_bin)
IF_SOCKET ("sockopt-int", &opt_setsockopt_int)
IF_SOCKET ("sockopt-string", &opt_setsockopt_string)
IF_SOCKS4 ("socksport", &opt_socksport)
IF_SOCKS4 ("socksuser", &opt_socksuser)
IF_IPAPP ("sourceport", &opt_sourceport)
@ -2032,6 +2044,155 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
(*opts)[i].value.u_linger.l_linger);
break;
#endif /* HAVE_STRUCT_LINGER */
case TYPE_INT_INT:
if (!assign) {
Error1("option \"%s\": values required", a0);
continue;
}
{
char *rest;
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
if (*rest != ':') {
Error1("option \"%s\": 2 arguments required",
ent->desc->defname);
}
++rest;
(*opts)[i].value2.u_int = strtoul(rest, &rest, 0);
}
Info3("setting option \"%s\" to %d:%d", ent->desc->defname,
(*opts)[i].value.u_int, (*opts)[i].value2.u_int);
break;
case TYPE_INT_BIN:
if (!assign) {
Error1("option \"%s\": values required", a0);
continue;
}
{
char *rest;
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
if (*rest != ':') {
Error1("option \"%s\": 2 arguments required",
ent->desc->defname);
}
++rest;
optlen = 0;
if ((result = dalan(rest, optbuf, &optlen, sizeof(optbuf))) != 0) {
Error1("parseopts(): problem with \"%s\" data", rest);
continue;
}
if (((*opts)[i].value2.u_bin.b_data = memdup(optbuf, optlen)) == NULL) {
Error1("memdup(, "F_Zu"): out of memory", optlen);
return -1;
}
(*opts)[i].value2.u_bin.b_len = optlen;
}
Info2("setting option \"%s\" to %d:..."/*!!!*/, ent->desc->defname,
(*opts)[i].value.u_int);
break;
case TYPE_INT_STRING:
if (!assign) {
Error1("option \"%s\": values required", a0);
continue;
}
{
char *rest;
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
if (*rest != ':') {
Error1("option \"%s\": 2 arguments required",
ent->desc->defname);
}
++rest;
if (((*opts)[i].value2.u_string = strdup(rest)) == NULL) {
Error("out of memory"); return -1;
}
}
Info3("setting option \"%s\" to %d:\"%s\"", ent->desc->defname,
(*opts)[i].value.u_int, (*opts)[i].value2.u_string);
break;
case TYPE_INT_INT_INT:
if (!assign) {
Error1("option \"%s\": values required", a0);
continue;
}
{
char *rest;
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
if (*rest != ':') {
Error1("option \"%s\": 3 arguments required",
ent->desc->defname);
}
++rest;
(*opts)[i].value2.u_int = strtoul(rest, &rest, 0);
if (*rest != ':') {
Error1("option \"%s\": 3 arguments required",
ent->desc->defname);
}
++rest;
(*opts)[i].value3.u_int = strtoul(rest, &rest, 0);
}
Info4("setting option \"%s\" to %d:%d:%d", ent->desc->defname,
(*opts)[i].value.u_int, (*opts)[i].value2.u_int, (*opts)[i].value3.u_int);
break;
case TYPE_INT_INT_BIN:
if (!assign) {
Error1("option \"%s\": values required", a0);
continue;
}
{
char *rest;
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
if (*rest != ':') {
Error1("option \"%s\": 3 arguments required",
ent->desc->defname);
}
++rest;
(*opts)[i].value2.u_int = strtoul(rest, &rest, 0);
if (*rest != ':') {
Error1("option \"%s\": 3 arguments required",
ent->desc->defname);
}
++rest;
optlen = 0;
if ((result = dalan(rest, optbuf, &optlen, sizeof(optbuf))) != 0) {
Error1("parseopts(): problem with \"%s\" data", rest);
continue;
}
if (((*opts)[i].value3.u_bin.b_data = memdup(optbuf, optlen)) == NULL) {
Error1("memdup(, "F_Zu"): out of memory", optlen);
return -1;
}
(*opts)[i].value3.u_bin.b_len = optlen;
}
Info3("setting option \"%s\" to %d:%d:..."/*!!!*/, ent->desc->defname,
(*opts)[i].value.u_int, (*opts)[i].value2.u_int);
break;
case TYPE_INT_INT_STRING:
if (!assign) {
Error1("option \"%s\": values required", a0);
continue;
}
{
char *rest;
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
if (*rest != ':') {
Error1("option \"%s\": 3 arguments required",
ent->desc->defname);
}
++rest;
(*opts)[i].value2.u_int = strtoul(rest, &rest, 0);
if (*rest != ':') {
Error1("option \"%s\": 3 arguments required",
ent->desc->defname);
}
++rest;
if (((*opts)[i].value3.u_string = strdup(rest)) == NULL) {
Error("out of memory"); return -1;
}
}
Info4("setting option \"%s\" to %d:%d:\"%s\"", ent->desc->defname,
(*opts)[i].value.u_int, (*opts)[i].value2.u_int,
(*opts)[i].value3.u_int);
break;
#if defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)
case TYPE_IP_MREQN:
{
@ -2520,13 +2681,13 @@ int retropt_string(struct opt *opts, int optcode, char **result) {
}
#if WITH_SOCKET
#if _WITH_SOCKET
/* looks for an bind option and, if found, overwrites the complete contents of
sa with the appropriate value(s).
returns STAT_OK if option exists and could be resolved,
STAT_NORETRY if option exists but had error,
or STAT_NOACTION if it does not exist */
/* currently only for IP (v4, v6) */
/* currently only for IP (v4, v6) and raw (PF_UNSPEC) */
int retropt_bind(struct opt *opts,
int af,
int socktype,
@ -2548,22 +2709,26 @@ int retropt_bind(struct opt *opts,
if (retropt_string(opts, OPT_BIND, &bindname) < 0) {
return STAT_NOACTION;
}
addrallowed = true;
portallowed = (feats>=2);
bindp = bindname;
nestlex((const char **)&bindp, &hostp, &hostlen, ends, NULL, NULL, nests,
true, false, false);
*hostp++ = '\0';
if (!strncmp(bindp, portsep, strlen(portsep))) {
if (!portallowed) {
Error("port specification not allowed in this bind option");
return STAT_NORETRY;
} else {
portp = bindp + strlen(portsep);
}
}
switch (af) {
case AF_UNSPEC:
{
size_t p = 0;
dalan(bindname, (char *)sa->sa_data, &p, *salen-sizeof(sa->sa_family));
*salen = p + sizeof(sa->sa_family);
*salen = p +
#if HAVE_STRUCT_SOCKADDR_SALEN
sizeof(sa->sa_len) +
#endif
sizeof(sa->sa_family);
#if HAVE_STRUCT_SOCKADDR_SALEN
sa->sa_len = *salen;
#endif
}
break;
#if WITH_IP4 || WITH_IP6
#if WITH_IP4
case AF_INET:
@ -2571,6 +2736,19 @@ int retropt_bind(struct opt *opts,
#if WITH_IP6
case AF_INET6:
#endif /*WITH_IP6 */
addrallowed = true;
portallowed = (feats>=2);
nestlex((const char **)&bindp, &hostp, &hostlen, ends, NULL, NULL, nests,
true, false, false);
*hostp++ = '\0';
if (!strncmp(bindp, portsep, strlen(portsep))) {
if (!portallowed) {
Error("port specification not allowed in this bind option");
return STAT_NORETRY;
} else {
portp = bindp + strlen(portsep);
}
}
if ((result =
xiogetaddrinfo(hostname[0]!='\0'?hostname:NULL, portp,
af, socktype, ipproto,
@ -2599,7 +2777,7 @@ int retropt_bind(struct opt *opts,
}
return STAT_OK;
}
#endif /* WITH_SOCKET */
#endif /* _WITH_SOCKET */
/* applies to fd all options belonging to phase */
@ -2676,7 +2854,49 @@ int applyopts(int fd, struct opt *opts, unsigned int phase) {
opt->desc = ODESC_ERROR; ++opt; continue;
}
#if WITH_SOCKET
} else if (opt->desc->func == OFUNC_IOCTL_GENERIC) {
switch (opt->desc->type) {
case TYPE_INT:
if (Ioctl(fd, opt->value.u_int, NULL) < 0) {
Error3("ioctl(%d, 0x%x, NULL): %s",
fd, opt->value.u_int, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue;
}
break;
case TYPE_INT_INT:
if (Ioctl_int(fd, opt->value.u_int, opt->value2.u_int) < 0) {
Error4("ioctl(%d, %d, %p): %s",
fd, opt->value.u_int, opt->value2.u_int, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue;
}
break;
case TYPE_INT_INTP:
if (Ioctl(fd, opt->value.u_int, (void *)&opt->value2.u_int) < 0) {
Error4("ioctl(%d, 0x%x, %p): %s",
fd, opt->value.u_int, (void *)&opt->value2.u_int, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue;
}
break;
case TYPE_INT_BIN:
if (Ioctl(fd, opt->value.u_int, (void *)opt->value2.u_bin.b_data) < 0) {
Error4("ioctl(%d, 0x%x, %p): %s",
fd, opt->value.u_int, (void *)opt->value2.u_bin.b_data, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue;
}
break;
case TYPE_INT_STRING:
if (Ioctl(fd, opt->value.u_int, (void *)opt->value2.u_string) < 0) {
Error4("ioctl(%d, 0x%x, %p): %s",
fd, opt->value.u_int, (void *)opt->value2.u_string, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue;
}
break;
default:
Error1("ioctl() data type %d not implemented",
opt->desc->type);
}
#if _WITH_SOCKET
} else if (opt->desc->func == OFUNC_SOCKOPT) {
if (0) {
;
@ -2853,7 +3073,39 @@ int applyopts(int fd, struct opt *opts, unsigned int phase) {
opt->desc->defname, opt->desc->type);
break;
}
#endif /* WITH_SOCKET */
} else if (opt->desc->func == OFUNC_SOCKOPT_GENERIC) {
switch (opt->desc->type) {
case TYPE_INT_INT_INT:
if (Setsockopt(fd, opt->value.u_int, opt->value2.u_int,
&opt->value3.u_int, sizeof(int)) < 0) {
Error6("setsockopt(%d, %d, %d, {%d}, "F_Zu"): %s",
fd, opt->value.u_int, opt->value2.u_int,
opt->value3.u_int, sizeof(int), strerror(errno));
}
break;
case TYPE_INT_INT_BIN:
if (Setsockopt(fd, opt->value.u_int, opt->value2.u_int,
opt->value3.u_bin.b_data, opt->value3.u_bin.b_len) < 0) {
Error5("setsockopt(%d, %d, %d, {...}, "F_Zu"): %s",
fd, opt->value.u_int, opt->value2.u_int,
opt->value3.u_bin.b_len, strerror(errno));
}
break;
case TYPE_INT_INT_STRING:
if (Setsockopt(fd, opt->value.u_int, opt->value2.u_int,
opt->value3.u_string,
strlen(opt->value3.u_string)+1) < 0) {
Error6("setsockopt(%d, %d, %d, \"%s\", "F_Zu"): %s",
fd, opt->value.u_int, opt->value2.u_int,
opt->value3.u_string, strlen(opt->value3.u_string)+1,
strerror(errno));
}
break;
default:
Error1("setsockopt() data type %d not implemented",
opt->desc->type);
}
#endif /* _WITH_SOCKET */
#if HAVE_FLOCK
} else if (opt->desc->func == OFUNC_FLOCK) {
@ -3071,6 +3323,7 @@ int applyopts(int fd, struct opt *opts, unsigned int phase) {
}
}
break;
default: Error1("applyopts(): option \"%s\" not implemented",
opt->desc->defname);
opt->desc = ODESC_ERROR; ++opt; continue;
@ -3567,7 +3820,7 @@ int applyopts_single(struct single *xfd, struct opt *opts, enum e_phase phase) {
}
break;
#if WITH_SOCKET
#if _WITH_SOCKET
case OFUNC_SOCKOPT:
switch (opt->desc->optcode) {
#if WITH_IP4 && (defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN))
@ -3718,7 +3971,7 @@ mc:addr
++opt; continue;
}
break;
#endif /* WITH_SOCKET */
#endif /* _WITH_SOCKET */
default:
++opt;

View file

@ -24,39 +24,53 @@ enum e_types {
TYPE_BIN, /* raw binary data, length determined by data */
TYPE_BOOL, /* value is 0 or 1 (no-value is interpreted as 1) */
TYPE_BYTE, /* unsigned char */
TYPE_INT, /* int */
TYPE_LONG, /* long */
TYPE_STRING, /* char * */
TYPE_NAME = TYPE_STRING,
TYPE_FILENAME = TYPE_STRING,
TYPE_PTRDIFF, /* ptrdiff_t */
TYPE_SHORT, /* short */
TYPE_SIZE_T, /* size_t */
TYPE_SOCKADDR, /* struct sockaddr * */
TYPE_UINT, /* unsigned int */
TYPE_ULONG, /* unsigned long */
TYPE_USHORT, /* unsigned short */
TYPE_2BYTE = TYPE_USHORT,
TYPE_MODET, /* representation of mode_t */
TYPE_GIDT, /* representation of gid_t */
TYPE_UIDT, /* representation of uid_t */
/*TYPE_FLAG,*/
TYPE_INT3, /* int[3] */
TYPE_TIMEVAL, /* struct timeval: {long;long;}, seconds and microsec. */
TYPE_TIMESPEC, /* struct timespec: {time_t;long;}, seconds and nanosec. */
#if HAVE_STRUCT_LINGER
TYPE_LINGER, /* struct linger */
#endif /* HAVE_STRUCT_LINGER */
TYPE_DOUBLE, /* double */
TYPE_STRING_NULL, /* char *; string or NULL */
TYPE_LONGLONG, /* long long */
TYPE_OFF32, /* off_t */
TYPE_OFF64, /* off64_t */
TYPE_INT_INT, /* 2 parameters: first is int, second is int */
TYPE_INT_INTP, /* 2 parameters: first is int, second is int* */
TYPE_INT_BIN, /* 2 parameters: first is int, second is binary */
TYPE_INT_STRING, /* 2 parameters: first is int, second is req string */
TYPE_INT_INT_INT, /* 3 params: first and second are int, 3rd is int */
TYPE_INT_INT_BIN, /* 3 params: first and second are int, 3rd is binary */
TYPE_INT_INT_STRING, /* 3 params: first and second are int, 3rd is string */
TYPE_IP4NAME, /* IPv4 hostname or address */
#if HAVE_STRUCT_LINGER
TYPE_LINGER, /* struct linger */
#endif /* HAVE_STRUCT_LINGER */
#if HAVE_STRUCT_IP_MREQ || HAVE_STRUCT_IP_MREQN
TYPE_IP_MREQN, /* for struct ip_mreq or struct ip_mreqn */
#endif
TYPE_IP4NAME, /* IPv4 hostname or address */
TYPE_2BYTE = TYPE_USHORT
} ;
enum e_func {
@ -66,11 +80,14 @@ enum e_func {
OFUNC_SEEK32, /* lseek(): arg1 is whence (SEEK_SET etc.) */
OFUNC_SEEK64, /* lseek64(): arg1 is whence (SEEK_SET etc.) */
OFUNC_FCNTL, /* fcntl(, ): arg1 is cmd */
OFUNC_IOCTL, /* ioctl(): arg1 is request */
OFUNC_IOCTL, /* ioctl(): arg1 of option description is request, arg2
is int setrequest */
OFUNC_IOCTL_MASK_LONG, /* arg1 is getrequest, arg2 is setrequest:
ioctl(arg1, ); |= arg3; ioctl(arg2, ); */
OFUNC_IOCTL_GENERIC, /* generic ioctl() (request on cmdline) */
OFUNC_SOCKOPT, /* setsockopt() */
OFUNC_SOCKOPT_APPEND,/* getsockopt(), append data, setsockopt() */
OFUNC_SOCKOPT_GENERIC,/* generic setsockopt() (level, optname on cmdline) */
OFUNC_FLOCK, /* flock() */
OFUNC_TERMIO, /* termio() ? */
OFUNC_SPEC, /* special, i.e. no generalizable function call */
@ -349,6 +366,11 @@ enum e_optcode {
#if 0 /* see Linux: man 7 netlink; probably not what we need yet */
OPT_IO_SIOCGIFNAME,
#endif
OPT_IOCTL_BIN, /* generic ioctl with binary value (pointed to) */
OPT_IOCTL_INT, /* generic ioctl with integer value */
OPT_IOCTL_INTP, /* generic ioctl with integer value (pointed to) */
OPT_IOCTL_STRING, /* generic ioctl with integer value (pointed to) */
OPT_IOCTL_VOID, /* generic ioctl without value */
OPT_IP_ADD_MEMBERSHIP,
#ifdef IP_HDRINCL
OPT_IP_HDRINCL,
@ -556,6 +578,9 @@ enum e_optcode {
OPT_SETGID_EARLY,
OPT_SETPGID,
OPT_SETSID,
OPT_SETSOCKOPT_BIN,
OPT_SETSOCKOPT_INT,
OPT_SETSOCKOPT_STRING,
OPT_SETUID,
OPT_SETUID_EARLY,
OPT_SIGHUP,

View file

@ -109,7 +109,7 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
break;
#endif /* WITH_OPENSSL */
#if WITH_SOCKET
#if _WITH_SOCKET
case XIOREAD_RECV:
if (pipe->dtype & XIOREAD_RECV_FROM) {
#if WITH_RAWIP || WITH_UDP || WITH_UNIX
@ -378,7 +378,7 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
}
break;
#endif /* WITH_SOCKET */
#endif /* _WITH_SOCKET */
default:
Error("internal: undefined read operation");

View file

@ -1,5 +1,5 @@
/* source: xioshutdown.c */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this is the source of the extended shutdown function */
@ -65,7 +65,7 @@ int xioshutdown(xiofile_t *sock, int how) {
sock->stream.para.exec.fdout, strerror(errno));
}
}
#if WITH_SOCKET
#if _WITH_SOCKET
} else if (sock->stream.howtoend == END_SHUTDOWN) {
if ((result = Shutdown(sock->stream.fd, how)) < 0) {
Info3("shutdown(%d, %d): %s",
@ -107,7 +107,7 @@ int xioshutdown(xiofile_t *sock, int how) {
sock->stream.eof = 2;
sock->stream.fd = -1;
}
#endif /* WITH_SOCKET */
#endif /* _WITH_SOCKET */
#if 0
} else {
Error1("xioshutdown(): bad data type specification %d", sock->stream.dtype);

View file

@ -76,7 +76,7 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
}
break;
#if WITH_SOCKET
#if _WITH_SOCKET
case XIOWRITE_SENDTO:
/*union {
char space[sizeof(struct sockaddr_un)];
@ -117,7 +117,7 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)));
}
break;
#endif /* WITH_SOCKET */
#endif /* _WITH_SOCKET */
case XIOWRITE_PIPE:
do {