diff --git a/CHANGES b/CHANGES index 84e726d..6014cd2 100644 --- a/CHANGES +++ b/CHANGES @@ -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 diff --git a/EXAMPLES b/EXAMPLES index 8dc0628..60ca020 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -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 diff --git a/VERSION b/VERSION index b15e9b2..0573f31 100644 --- a/VERSION +++ b/VERSION @@ -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" diff --git a/config.h.in b/config.h.in index 0d8c9cc..ec9236a 100644 --- a/config.h.in +++ b/config.h.in @@ -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 diff --git a/configure.in b/configure.in index 013a2c3..8bb4e10 100644 --- a/configure.in +++ b/configure.in @@ -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 diff --git a/dalan.c b/dalan.c index bc475cd..1d7334f 100644 --- a/dalan.c +++ b/dalan.c @@ -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 diff --git a/doc/socat.yo b/doc/socat.yo index d056f46..2644c4d 100644 --- a/doc/socat.yo +++ b/doc/socat.yo @@ -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:::))) + 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::::))) + 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:::))) + 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::::))) + Creates a socket using the three given socket parameters (see man socket(2)) + and binds it to . 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::::))) + Creates a socket using the three given socket parameters (see man socket(2)) + and binds it to . 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::::))) + 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:::))) Connects via [link(IP address)(TYPE_IP_ADDRESS)] to [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=))) + 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=:))) + 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=:))) + 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=:))) + 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()(TYPE_DATA) form. +label(OPTION_IOCTL_STRING)dit(bf(tt(ioctl-string=:))) + Calls tt(ioctl()) with the request value as second argument and a pointer to + the given string as third argument. + link()(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=::))) + 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=::))) + Like tt(setsockopt-int), but 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=::))) + Like tt(setsockopt-int), but 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) diff --git a/fdname.c b/fdname.c index b0d6210..bc15103 100644 --- a/fdname.c +++ b/fdname.c @@ -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 */ diff --git a/filan.c b/filan.c index 3b3d045..376ee79 100644 --- a/filan.c +++ b/filan.c @@ -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) { diff --git a/filan.h b/filan.h index ca02950..bea30f4 100644 --- a/filan.h +++ b/filan.h @@ -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); diff --git a/hostan.c b/hostan.c index 19829b2..9977914 100644 --- a/hostan.c +++ b/hostan.c @@ -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 */ diff --git a/procan-cdefs.c b/procan-cdefs.c index c5a7116..f85ca8a 100644 --- a/procan-cdefs.c +++ b/procan-cdefs.c @@ -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; } diff --git a/readline-test.sh b/readline-test.sh index 569bff6..2242ea9 100755 --- a/readline-test.sh +++ b/readline-test.sh @@ -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 diff --git a/sycls.c b/sycls.c index 4ab902c..f9b4244 100644 --- a/sycls.c +++ b/sycls.c @@ -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); diff --git a/sycls.h b/sycls.h index 03ecff0..5715e6b 100644 --- a/sycls.h +++ b/sycls.h @@ -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) diff --git a/sysutils.c b/sysutils.c index 4a27fe9..472d946 100644 --- a/sysutils.c +++ b/sysutils.c @@ -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'; diff --git a/sysutils.h b/sysutils.h index 33cfc45..e8c8f32 100644 --- a/sysutils.h +++ b/sysutils.h @@ -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 */ diff --git a/test.sh b/test.sh index 5526380..b847500 100755 --- a/test.sh +++ b/test.sh @@ -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; 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 diff --git a/xio-fd.c b/xio-fd.c index 142e5fe..9fc1d57 100644 --- a/xio-fd.c +++ b/xio-fd.c @@ -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 }; diff --git a/xio-fd.h b/xio-fd.h index 25b25d0..a301b4e 100644 --- a/xio-fd.h +++ b/xio-fd.h @@ -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; diff --git a/xio-ip.c b/xio-ip.c index 981b455..27758f2 100644 --- a/xio-ip.c +++ b/xio-ip.c @@ -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, diff --git a/xio-ip.h b/xio-ip.h index 6522f49..5ec9ff6 100644 --- a/xio-ip.h +++ b/xio-ip.h @@ -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, diff --git a/xio-ip4.c b/xio-ip4.c index 27b9128..d40796b 100644 --- a/xio-ip4.c +++ b/xio-ip4.c @@ -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]; diff --git a/xio-ip4.h b/xio-ip4.h index 15aefed..2bd11ce 100644 --- a/xio-ip4.h +++ b/xio-ip4.h @@ -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, diff --git a/xio-ip6.c b/xio-ip6.c index 870e80e..d8ee9bc 100644 --- a/xio-ip6.c +++ b/xio-ip6.c @@ -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]), diff --git a/xio-ip6.h b/xio-ip6.h index 2e86725..c0203ff 100644 --- a/xio-ip6.h +++ b/xio-ip6.h @@ -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, diff --git a/xio-listen.c b/xio-listen.c index dae8396..a0f4759 100644 --- a/xio-listen.c +++ b/xio-listen.c @@ -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'; diff --git a/xio-rawip.c b/xio-rawip.c index 7df1b39..0cbed31 100644 --- a/xio-rawip.c +++ b/xio-rawip.c @@ -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; diff --git a/xio-socket.c b/xio-socket.c index 20be0af..9fbdbbe 100644 --- a/xio-socket.c +++ b/xio-socket.c @@ -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(":::") }; +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(":::") }; +const struct addrdesc xioaddr_socket_sendto = { "socket-sendto", 3, xioopen_socket_sendto, GROUP_FD|GROUP_SOCKET, 0, 0, 0 HELP("::::") }; +const struct addrdesc xioaddr_socket_datagram= { "socket-datagram", 3, xioopen_socket_datagram, GROUP_FD|GROUP_SOCKET|GROUP_RANGE, 0, 0, 0 HELP("::::") }; +const struct addrdesc xioaddr_socket_recvfrom= { "socket-recvfrom", 3, xioopen_socket_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_RANGE|GROUP_CHILD, 0, 0, 0 HELP("::::") }; +const struct addrdesc xioaddr_socket_recv = { "socket-recv", 1, xioopen_socket_recv, GROUP_FD|GROUP_SOCKET|GROUP_RANGE, 0, 0, 0 HELP("::::") }; + + +/* 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 :", 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 diff --git a/xio-socket.h b/xio-socket.h index 860fe5d..40e214d 100644 --- a/xio-socket.h +++ b/xio-socket.h @@ -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) */ diff --git a/xio-tun.c b/xio-tun.c index dbc86cc..bbc090a 100644 --- a/xio-tun.c +++ b/xio-tun.c @@ -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, diff --git a/xio-udp.c b/xio-udp.c index 8913f36..f507e24 100644 --- a/xio-udp.c +++ b/xio-udp.c @@ -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; diff --git a/xio-unix.c b/xio-unix.c index 6f0dacc..e3c7d78 100644 --- a/xio-unix.c +++ b/xio-unix.c @@ -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; } diff --git a/xio.h b/xio.h index 598e8ba..b09c8c3 100644 --- a/xio.h +++ b/xio.h @@ -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; diff --git a/xioclose.c b/xioclose.c index 850e26f..e08666b 100644 --- a/xioclose.c +++ b/xioclose.c @@ -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; diff --git a/xioconfig.h b/xioconfig.h index f474b61..a0379c6 100644 --- a/xioconfig.h +++ b/xioconfig.h @@ -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 diff --git a/xiohelp.c b/xiohelp.c index a994cdb..b37115b 100644 --- a/xiohelp.c +++ b/xiohelp.c @@ -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", } ; diff --git a/xiomodes.h b/xiomodes.h index b48c9b7..90a6745 100644 --- a/xiomodes.h +++ b/xiomodes.h @@ -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" diff --git a/xioopen.c b/xioopen.c index f3a62b3..de42455 100644 --- a/xioopen.c +++ b/xioopen.c @@ -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; diff --git a/xioopts.c b/xioopts.c index 377ca58..f66485f 100644 --- a/xioopts.c +++ b/xioopts.c @@ -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; diff --git a/xioopts.h b/xioopts.h index 9c5bdb6..b5b846d 100644 --- a/xioopts.h +++ b/xioopts.h @@ -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, diff --git a/xioread.c b/xioread.c index d8bb574..34590ea 100644 --- a/xioread.c +++ b/xioread.c @@ -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"); diff --git a/xioshutdown.c b/xioshutdown.c index 0f48639..30d3adf 100644 --- a/xioshutdown.c +++ b/xioshutdown.c @@ -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); diff --git a/xiowrite.c b/xiowrite.c index d02e48b..2bc9379 100644 --- a/xiowrite.c +++ b/xiowrite.c @@ -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 {