From 13b73776e7547c393f52ce1ffc41fffabddba4f6 Mon Sep 17 00:00:00 2001 From: Gerhard Rieger Date: Sun, 17 Aug 2008 23:28:11 +0200 Subject: [PATCH] ported generic socket to *BSD; minor improvements --- CHANGES | 5 + VERSION | 2 +- config.h.in | 1 + configure.in | 8 + dalan.c | 1 + doc/socat.yo | 138 ++++++++++ fdname.c | 8 +- filan.c | 22 +- filan.h | 6 +- hostan.c | 6 +- procan-cdefs.c | 15 ++ readline-test.sh | 9 +- sysutils.c | 9 + sysutils.h | 26 +- test.sh | 432 ++++++++++++++++++++++++++++--- xio-ip.c | 86 ------- xio-ip.h | 7 +- xio-ip4.c | 54 +++- xio-ip4.h | 6 +- xio-ip6.c | 19 +- xio-ip6.h | 8 +- xio-listen.c | 22 +- xio-rawip.c | 8 +- xio-socket.c | 656 ++++++++++++++++++++++++++++++++++++++++++++++- xio-socket.h | 12 + xio-tun.c | 8 +- xio-udp.c | 6 +- xio-unix.c | 5 +- xio.h | 2 +- xioclose.c | 4 +- xioconfig.h | 10 +- xiomodes.h | 6 +- xioopen.c | 19 +- xioopts.c | 59 +++-- xioread.c | 4 +- xioshutdown.c | 6 +- xiowrite.c | 4 +- 37 files changed, 1441 insertions(+), 258 deletions(-) diff --git a/CHANGES b/CHANGES index 8b50c67..d21a958 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,10 @@ 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. diff --git a/VERSION b/VERSION index 0b595f8..a877d7d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock+ioctl+ioctl+setsockopt" +"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock+ioctl+setsockopt+genericsocket" diff --git a/config.h.in b/config.h.in index 2e330da..dfe0c36 100644 --- a/config.h.in +++ b/config.h.in @@ -456,6 +456,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 f3161ce..e094ffc 100644 --- a/configure.in +++ b/configure.in @@ -196,6 +196,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 4df8cd2..741461a 100644 --- a/doc/socat.yo +++ b/doc/socat.yo @@ -599,6 +599,144 @@ 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 as numbers of type + link(int)(TYPE_INT). Consult your OS documentation and include files to find + the desired values. The remote-address must be the link(data)(TYPE_DATA) + representation of a sockaddr structure without the sa_family component.nl() + Please note that you can - beyond the options of the specified groups - also + apply options of higher level protocols when you use socat option + link(-s)(option_s).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 as numbers of type + link(int)(TYPE_INT). Consult your OS documentation and include files to find + the desired values. The remote-address must be the link(data)(TYPE_DATA) + representation of a sockaddr structure without the sa_family component.nl() + Please note that you can - beyond the options of the specified groups - also + apply options of higher level protocols when you use socat option + link(-s)(option_s).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 as numbers of type + link(int)(TYPE_INT). Consult your OS documentation and include files to find + the desired values. The local-address must be the link(data)(TYPE_DATA) + representation of a sockaddr structure without the sa_family component.nl() + Please note that you can - beyond the options of the specified groups - also + apply options of higher level protocols when you use socat option + link(-s)(option_s).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 as numbers of type + link(int)(TYPE_INT). Consult your OS documentation and include files to find + the desired values. The local-address must be the link(data)(TYPE_DATA) + representation of a sockaddr structure without the sa_family component.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 + numbers of type link(int)(TYPE_INT). Consult your OS documentation and + include files to find the desired values. The local-address must be the + link(data)(TYPE_DATA) + representation of a sockaddr structure without the sa_family component.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 + numbers of type link(int)(TYPE_INT). Consult your OS documentation and + include files to find the desired values. The remote-address must be the + link(data)(TYPE_DATA) representation of a sockaddr structure without the + sa_family component.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)] diff --git a/fdname.c b/fdname.c index 8ede9fe..5309360 100644 --- a/fdname.c +++ b/fdname.c @@ -139,7 +139,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) { @@ -150,7 +150,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() */ @@ -185,7 +185,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 @@ -320,7 +320,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 e0477d1..fe5e63e 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 @@ -634,7 +634,7 @@ int sockan(int fd, FILE *outfile) { #undef FILAN_OPTLEN #undef FILAN_NAMELEN } -#endif /* WITH_SOCKET */ +#endif /* _WITH_SOCKET */ #if WITH_IP4 || WITH_IP6 @@ -823,7 +823,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]; @@ -859,10 +859,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 @@ -883,7 +883,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 8ed3484..1abff1b 100644 --- a/filan.h +++ b/filan.h @@ -1,5 +1,5 @@ /* source: filan.h */ -/* Copyright Gerhard Rieger 2001-2007 */ +/* Copyright Gerhard Rieger 2001-2008 */ /* Published under the GNU General Public License V.2, see file COPYING */ @@ -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); diff --git a/hostan.c b/hostan.c index 8862bf5..8033dc0 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: man 4 networking */ @@ -80,4 +80,4 @@ static int iffan(FILE *outfile) { #endif /* defined(SIOCGIFINDEX) */ 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/sysutils.c b/sysutils.c index 28ccae9..43629c3 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 ", sa->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 ", sa->sa_family)) < 0) { Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen); *buff = '\0'; diff --git a/sysutils.h b/sysutils.h index b9074b3..6cbe1fe 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 dee3739..4255347 100755 --- a/test.sh +++ b/test.sh @@ -141,14 +141,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 @@ -184,20 +191,20 @@ vt100|vt320|linux|xterm|cons25|dtterm|aixterm|sun-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}" @@ -1509,9 +1516,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 @@ -1519,7 +1528,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)) @@ -1574,7 +1584,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) ")" ;; @@ -1596,8 +1607,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 @@ -4387,7 +4399,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 @@ -4459,7 +4471,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 @@ -4857,7 +4870,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)) @@ -4866,6 +4885,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 @@ -5544,7 +5579,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" @@ -5566,12 +5601,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" @@ -5929,10 +5964,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" @@ -5954,16 +5992,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 @@ -8447,6 +8485,334 @@ esac N=$((N+1)) +# test the SOCKET-CONNECT address (against TCP4-LISTEN) +NAME=SOCKET_CONNECT +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="$(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-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="$(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="$(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="$(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="$(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="$(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 @@ -8458,9 +8824,9 @@ TEST="$NAME: test the ioctl-void option" # 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 [ "$UNAME" != Linux ]; then +if [ -z "$TIOCEXCL" ]; then # we use the numeric value of TIOCEXL which is system dependent - $PRINTF "test $F_n $TEST... ${YELLOW}only on Linux${NORMAL}\n" $N + $PRINTF "test $F_n $TEST... ${YELLOW}no value of TIOCEXCL${NORMAL}\n" $N numCANT=$((numCANT+1)) else tp="$td/test$N.pty" @@ -8469,7 +8835,7 @@ te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="$(date)" CMD0="$SOCAT $opts PTY,LINK=$tp pipe" -CMD1="$SOCAT $opts - file:$tp,ioctl-void=0x540c,raw,echo=0" +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" & @@ -8504,6 +8870,9 @@ 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 @@ -8518,9 +8887,9 @@ TEST="$NAME: test the setsockopt-int option" # 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 [ "$UNAME" != Linux ]; then +if [ -z "SO_REUSEADDR" ]; then # we use the numeric value of SO_REUSEADDR which might be system dependent - $PRINTF "test $F_n $TEST... ${YELLOW}only on Linux${NORMAL}\n" $N + $PRINTF "test $F_n $TEST... ${YELLOW}value of SO_REUSEADDR not known${NORMAL}\n" $N numCANT=$((numCANT+1)) else tp="$PORT" @@ -8528,8 +8897,7 @@ tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="$(date)" -# level=SOL_SOCKET=1, optname=SO_REUSEADDR=2, value=1 -CMD0="$SOCAT $opts TCP4-L:$tp,setsockopt-int=1:2:1 PIPE" +CMD0="$SOCAT $opts TCP4-L:$tp,setsockopt-int=$SOL_SOCKET:$SO_REUSEADDR:1 PIPE" CMD1="$SOCAT $opts - TCP:localhost:$tp" CMD2="$CMD0" CMD3="$CMD1" diff --git a/xio-ip.c b/xio-ip.c index 77dd71d..6adb86e 100644 --- a/xio-ip.c +++ b/xio-ip.c @@ -423,90 +423,4 @@ int xiogetaddrinfo(const char *node, const char *service, return STAT_OK; } - -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; -} - #endif /* _WITH_IP4 || _WITH_IP6 */ diff --git a/xio-ip.h b/xio-ip.h index 4d68012..9b4aab2 100644 --- a/xio-ip.h +++ b/xio-ip.h @@ -1,5 +1,5 @@ /* source: xio-ip.h */ -/* Copyright Gerhard Rieger 2001-2007 */ +/* Copyright Gerhard Rieger 2001-2008 */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __xio_ip_h_included @@ -39,10 +39,5 @@ extern int xiogetaddrinfo(const char *node, const char *service, int family, int socktype, int protocol, 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); #endif /* !defined(__xio_ip_h_included) */ diff --git a/xio-ip4.c b/xio-ip4.c index 6e8ff23..6cdaf60 100644 --- a/xio-ip4.c +++ b/xio-ip4.c @@ -1,5 +1,5 @@ /* source: xio-ip4.c */ -/* Copyright Gerhard Rieger 2001-2007 */ +/* Copyright Gerhard Rieger 2001-2008 */ /* Published under the GNU General Public License V.2, see file COPYING */ /* this file contains the source for IP4 related functions */ @@ -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 9357dcc..bbc855b 100644 --- a/xio-ip4.h +++ b/xio-ip4.h @@ -1,5 +1,5 @@ /* source: xio-ip4.h */ -/* Copyright Gerhard Rieger 2001-2007 */ +/* Copyright Gerhard Rieger 2001-2008 */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __xio_ip4_h_included @@ -8,6 +8,8 @@ extern const struct optdesc opt_ip4_add_membership; extern -int xiocheckrange_ip4(struct sockaddr_in *pa, struct xiorange_ip4 *range); +int xioparsenetwork_ip4(const char *rangename, struct xiorange *range); +extern +int xiocheckrange_ip4(struct sockaddr_in *pa, struct xiorange *range); #endif /* !defined(__xio_ip4_h_included) */ diff --git a/xio-ip6.c b/xio-ip6.c index 0bf8577..b56facc 100644 --- a/xio-ip6.c +++ b/xio-ip6.c @@ -1,5 +1,5 @@ /* source: xio-ip6.c */ -/* Copyright Gerhard Rieger 2001-2007 */ +/* Copyright Gerhard Rieger 2001-2008 */ /* Published under the GNU General Public License V.2, see file COPYING */ /* this file contains the source for IP6 related functions */ @@ -21,15 +21,15 @@ const struct optdesc opt_ipv6_v6only = { "ipv6-v6only", "ipv6only", OPT_IPV6_V6O const struct optdesc opt_ipv6_join_group = { "ipv6-join-group", "join-group", OPT_IPV6_JOIN_GROUP, GROUP_SOCK_IP6, PH_PASTBIND, TYPE_IP_MREQN, OFUNC_SOCKOPT, SOL_IPV6, IPV6_JOIN_GROUP }; #endif -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] != ']') { @@ -87,7 +87,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]; @@ -96,7 +96,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; @@ -104,12 +105,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 431d4d1..5b03eb8 100644 --- a/xio-ip6.h +++ b/xio-ip6.h @@ -1,5 +1,5 @@ /* source: xio-ip6.h */ -/* Copyright Gerhard Rieger 2001-2007 */ +/* Copyright Gerhard Rieger 2001-2008 */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __xio_ip6_h_included @@ -11,11 +11,11 @@ extern const struct optdesc opt_ipv6_v6only; extern const struct optdesc opt_ipv6_join_group; 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); #endif /* WITH_IP6 */ diff --git a/xio-listen.c b/xio-listen.c index 38a65c6..225beaf 100644 --- a/xio-listen.c +++ b/xio-listen.c @@ -83,6 +83,9 @@ int /* 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 (expcting 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 @@ -119,9 +122,9 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl xiosetchilddied(); /* set SIGCHLD handler */ } - if ((xfd->fd = Socket(pf, socktype, proto)) < 0) { + if ((xfd->fd = Socket(us->sa_family, socktype, proto)) < 0) { Msg4(level, - "socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno)); + "socket(%d, %d, %d): %s", us->sa_family, socktype, proto, strerror(errno)); return STAT_RETRYLATER; } @@ -161,15 +164,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; } @@ -189,6 +187,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 a1a0e09..df54555 100644 --- a/xio-rawip.c +++ b/xio-rawip.c @@ -170,7 +170,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; } @@ -287,7 +287,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) { @@ -300,7 +301,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 2bb3b47..4c83f18 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" @@ -18,9 +19,54 @@ #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); + + +/* 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}; @@ -133,6 +179,498 @@ const struct optdesc opt_setsockopt_int = { "setsockopt-int", "sockopt-int 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. @@ -658,9 +1196,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; @@ -668,7 +1206,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); @@ -913,7 +1450,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; @@ -1032,17 +1569,17 @@ int xiogetpacketsrc(int fd, union sockaddr_union *pa, socklen_t *palen) { } -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; @@ -1133,4 +1670,107 @@ int xiocheckpeer(xiosingle_t *xfd, return 0; /* permitted */ } + +/* 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); + 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; +} + #endif /* _WITH_SOCKET */ diff --git a/xio-socket.h b/xio-socket.h index 5a68920..7f8ac0c 100644 --- a/xio-socket.h +++ b/xio-socket.h @@ -5,6 +5,13 @@ #ifndef __xio_socket_h_included #define __xio_socket_h_included 1 +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; @@ -89,5 +96,10 @@ int xiogetpacketsrc(int fd, union sockaddr_union *pa, socklen_t *palen); extern int xiocheckpeer(xiosingle_t *xfd, union sockaddr_union *pa, union sockaddr_union *la); +extern +int xioparsenetwork(const char *rangename, int pf, + struct xiorange *range); +extern +int xioparserange(const char *rangename, int pf, struct xiorange *range); #endif /* !defined(__xio_socket_h_included) */ diff --git a/xio-tun.c b/xio-tun.c index 1bc8709..3729d5b 100644 --- a/xio-tun.c +++ b/xio-tun.c @@ -70,7 +70,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); @@ -157,12 +157,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 293b8be..101adca 100644 --- a/xio-udp.c +++ b/xio-udp.c @@ -145,7 +145,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; } @@ -424,7 +424,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; } @@ -582,7 +582,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 b0c6b95..c8d8510 100644 --- a/xio-unix.c +++ b/xio-unix.c @@ -84,6 +84,9 @@ xiosetunix(struct sockaddr_un *saun, } else { len = sizeof(struct sockaddr_un); } +#if HAVE_STRUCT_SOCKADDR_SALEN + saun->sun_len = len; +#endif } else { if ((pathlen = strlen(path)) >= sizeof(saun->sun_path)) { Warn2("socket address "F_Zu" characters long, truncating to "F_Zu"", @@ -225,7 +228,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 4dc1464..eea9db6 100644 --- a/xio.h +++ b/xio.h @@ -177,7 +177,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 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/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 f944740..e178231 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.para.exec.pid = 0; */ diff --git a/xioopts.c b/xioopts.c index 4022ca2..674b901 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) @@ -2608,13 +2608,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, @@ -2636,22 +2636,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: @@ -2659,6 +2663,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, @@ -2687,7 +2704,7 @@ int retropt_bind(struct opt *opts, } return STAT_OK; } -#endif /* WITH_SOCKET */ +#endif /* _WITH_SOCKET */ /* applies to fd all options belonging to phase */ @@ -2806,7 +2823,7 @@ int applyopts(int fd, struct opt *opts, unsigned int phase) { opt->desc->type); } -#if WITH_SOCKET +#if _WITH_SOCKET } else if (opt->desc->func == OFUNC_SOCKOPT) { if (0) { ; @@ -3015,7 +3032,7 @@ int applyopts(int fd, struct opt *opts, unsigned int phase) { Error1("setsockopt() data type %d not implemented", opt->desc->type); } -#endif /* WITH_SOCKET */ +#endif /* _WITH_SOCKET */ #if HAVE_FLOCK } else if (opt->desc->func == OFUNC_FLOCK) { @@ -3728,7 +3745,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)) @@ -3879,7 +3896,7 @@ mc:addr ++opt; continue; } break; -#endif /* WITH_SOCKET */ +#endif /* _WITH_SOCKET */ default: ++opt; diff --git a/xioread.c b/xioread.c index 5db886c..039401f 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 @@ -354,7 +354,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 {