diff --git a/CHANGES b/CHANGES index 19006c7..9de7304 100644 --- a/CHANGES +++ b/CHANGES @@ -78,6 +78,12 @@ Features: configure option --with-default-ipv allows to specify at build time if IPv4, IPv6, or none of these is the preferred default. + Socat options -4 and -6 have been reworked. + Tests: TCP_ENV6 TCP_DASH6 + + New option ai-addrconfig disables name resolution to protocol families + that are not configured on the computer (e.g. IPv6) + Corrections: When a sub process (EXEC, SYSTEM) terminated with exit code other than 0, its last sent data might have been lost depending on timing of read/ diff --git a/VERSION b/VERSION index ceaf471..576e205 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -"1.7.4.5+" +"1.7.4.5+conn-over" diff --git a/doc/socat.yo b/doc/socat.yo index 6ca5159..38dc481 100644 --- a/doc/socat.yo +++ b/doc/socat.yo @@ -218,10 +218,10 @@ label(option_W)dit(bf(tt(-W))tt()) If lockfile exists, waits until it disappears. When lockfile does not exist, creates it and continues, unlinks lockfile on exit. label(option_4)dit(bf(tt(-4))) - Use IP version 4 in case that the addresses do not implicitly or explicitly + Use IP version 4 in case the addresses do not implicitly or explicitly specify a version; this is the default. label(option_6)dit(bf(tt(-6))) - Use IP version 6 in case that the addresses do not implicitly or explicitly + Use IP version 6 in case the addresses do not implicitly or explicitly specify a version. label(option_statistics)dit(bf(tt(--statistics))) Logs transfer statistics (bytes and blocks counters for both directions) @@ -2240,6 +2240,11 @@ label(OPTOIN_IP_TRANSPARENT) dit(bf(tt(ip-transparent))) Sets the IP_TRANSPARENT socket option. This option might require root privilege. +label(OPTION_AI_ADDRCONFIG) +dit(bf(tt(ai-addrconfig[=0|1]))), dit(bf(tt(addrconfig[=0|1]))) + Sets or unsets the AI_ADDRCONFIG flag to prevent name resolution to address + families that are not configured (e.g. IPv6). Default value is 1 in case the + resolver does not get an address family hint. label(OPTION_RES_DEBUG)dit(bf(tt(res-debug))) label(OPTION_RES_AAONLY)dit(bf(tt(res-aaonly))) label(OPTION_RES_USEVC)dit(bf(tt(res-usevc))) @@ -2249,10 +2254,10 @@ label(OPTION_RES_RECURSE)dit(bf(tt(res-recurse))) label(OPTION_RES_DEFNAMES)dit(bf(tt(res-defnames))) label(OPTION_RES_STAYOPEN)dit(bf(tt(res-stayopen))) label(OPTION_RES_DNSRCH)dit(bf(tt(res-dnsrch))) - These options set the corresponding resolver (name resolution) option flags. - Append "=0" to clear a default option. See man NOEXPAND(resolver(5)) for more - information on these options. Note: these options are valid only for the - address they are applied to. + These options temporarily set the corresponding resolver (name resolution) + option flags. Append "=0" to clear a default option. See man + NOEXPAND(resolver(5)) for more information on these options. These flags are + per process, however socat() restores the old values after name resolution. enddit() diff --git a/sycls.c b/sycls.c index eba9d01..e6cd8db 100644 --- a/sycls.c +++ b/sycls.c @@ -1445,7 +1445,7 @@ struct hostent *Gethostbyname(const char *name) { int Getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { int result; - Debug15("getaddrinfo(%s%s%s, %s%s%s, {%d,%d,%d,%d,"F_socklen",%p,%p,%p}, %p)", + Debug15("getaddrinfo(%s%s%s, %s%s%s, {0x%02x,%d,%d,%d,"F_socklen",%p,%p,%p}, %p)", node?"\"":"", node?node:"NULL", node?"\"":"", service?"\"":"", service?service:"NULL", service?"\"":"", hints->ai_flags, hints->ai_family, hints->ai_socktype, diff --git a/test.sh b/test.sh index 439a2c2..dd80bc1 100755 --- a/test.sh +++ b/test.sh @@ -173,6 +173,7 @@ SOL_SOCKET="$($PROCAN -c |grep "^#define[[:space:]]*SOL_SOCKET[[:space:]]" |cut SO_REUSEADDR="$($PROCAN -c |grep "^#define[[:space:]]*SO_REUSEADDR[[:space:]]" |cut -d' ' -f3)" TCP_MAXSEG="$($PROCAN -c |grep "^#define[[:space:]]*TCP_MAXSEG[[:space:]]" |cut -d' ' -f3)" SIZE_T=$($PROCAN |grep size_t |awk '{print($3);}') +#AI_ADDRCONFIG=; if [ "$($SOCAT -hhh |grep ai-addrconfig)" ]; then AI_ADDRCONFIG="ai-addrconfig=0"; fi # SSL certificate contents TESTCERT_CONF=testcert.conf @@ -2089,8 +2090,20 @@ case "$TESTS" in *%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*) TEST="$NAME: echo via connection to TCP V6 socket" if ! eval $NUMCOND; then :; -elif ! testfeats tcp ip6 >/dev/null || ! runsip6 >/dev/null; then - $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N +elif ! F=$(testfeats IP6 TCP LISTEN STDIO PIPE); then + $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" +elif ! A=$(testaddrs - TCP6-LISTEN PIPE STDIN STDOUT TCP6-CONNECT); then + $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" +elif ! o=$(testoptions so-reuseaddr ) >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" +elif ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}IPv6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else @@ -2101,27 +2114,36 @@ newport tcp6; tsl=$PORT ts="[::1]:$tsl" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts TCP6-LISTEN:$tsl,$REUSEADDR PIPE" -CMD2="$TRACE $SOCAT $opts stdin!!stdout TCP6:$ts" +CMD2="$TRACE $SOCAT $opts STDIN!!STDOUT TCP6:$ts" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id waittcp6port $tsl 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" if [ $? -ne 0 ]; then - $PRINTF "$FAILED: $TRACE $SOCAT:\n" - echo "$CMD1 &" - echo "$CMD2" - cat "$te" - numFAIL=$((numFAIL+1)) - listFAIL="$listFAIL $N" + $PRINTF "$FAILED: $TRACE $SOCAT:\n" + echo "$CMD1 &" + cat "${te}1" >&2 + echo "$CMD2" + cat "${te}2" >&2 + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then - $PRINTF "$FAILED: diff:\n" - cat "$tdiff" - numFAIL=$((numFAIL+1)) - listFAIL="$listFAIL $N" + $PRINTF "$FAILED: diff:\n" + echo "$CMD1 &" + cat "${te}1" >&2 + echo "$CMD2" + cat "${te}2" >&2 + echo diff: + cat "$tdiff" + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" else $PRINTF "$OK\n" - if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + if [ "$VERBOSE" ]; then echo "$CMD1 &"; fi + if [ "$DEBUG" ]; then cat "${te}1" >&2; fi + if [ "$VERBOSE" ]; then echo "$CMD2"; fi + if [ "$DEBUG" ]; then cat "${te}2" >&2; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null @@ -2131,17 +2153,26 @@ N=$((N+1)) #set +vx +# Test if TCP client with IPv4 address connects to IPv4 port NAME=TCPX4 case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*) TEST="$NAME: echo via connection to TCP socket, v4 by target" if ! eval $NUMCOND; then :; -elif ! testfeats tcp ip4 >/dev/null || ! runsip4 >/dev/null; then - $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N +elif ! F=$(testfeats STDIO PIPE IP4 TCP LISTEN); then + $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" -elif ! testfeats ip6 >/dev/null || ! runsip6 >/dev/null; then - $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N +elif ! A=$(testaddrs TCP TCP-LISTEN STDIN STDOUT PIPE); then + $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" +elif ! o=$(testoptions pf) >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" +elif ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else @@ -2151,29 +2182,39 @@ tdiff="$td/test$N.diff" newport tcp4; tsl=$PORT ts="127.0.0.1:$tsl" da="test$N $(date) $RANDOM" -CMD1="$TRACE $SOCAT $opts TCP-LISTEN:$tsl,pf=ip4,$REUSEADDR PIPE" -CMD2="$TRACE $SOCAT $opts STDIN!!STDOUT TCP:$ts" +CMD0="$TRACE $SOCAT $opts TCP-LISTEN:$tsl,pf=ip4,$REUSEADDR PIPE" +CMD1="$TRACE $SOCAT $opts STDIN!!STDOUT TCP:$ts" printf "test $F_n $TEST... " $N -$CMD1 >"$tf" 2>"${te}1" & +$CMD0 >"$tf" 2>"${te}0" & pid=$! # background process id waittcp4port $tsl 1 -echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +echo "$da" |$CMD1 >>"$tf" 2>>"${te}1" if [ $? -ne 0 ]; then - $PRINTF "$FAILED: $TRACE $SOCAT:\n" - echo "$CMD1 &" - echo "$CMD2" - cat "$te" - numFAIL=$((numFAIL+1)) - listFAIL="$listFAIL $N" + $PRINTF "$FAILED: $TRACE $SOCAT:\n" + echo "$CMD0 &" + cat "${te}0" >&2 + echo "$CMD1" + cat "${te}1" >&2 + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" + namesFAIL="$namesFAIL $NAME" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then - $PRINTF "$FAILED: diff:\n" - cat "$tdiff" - numFAIL=$((numFAIL+1)) - listFAIL="$listFAIL $N" + $PRINTF "$FAILED: diff:\n" + cat "$tdiff" + echo "$CMD0 &" + cat "${te}0" >&2 + echo "$CMD1" + cat "${te}1" >&2 + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" + namesFAIL="$namesFAIL $NAME" else - $PRINTF "$OK\n" - if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi - numOK=$((numOK+1)) + $PRINTF "$OK\n" + if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi + if [ "$DEBUG" ]; then cat "${te}0" >&2; fi + if [ "$VERBOSE" ]; then echo "$CMD1"; fi + if [ "$DEBUG" ]; then cat "${te}1" >&2; fi + numOK=$((numOK+1)) fi kill $pid 2>/dev/null fi @@ -2181,17 +2222,26 @@ esac N=$((N+1)) +# Test if TCP client with IPv6 address connects to IPv6 port NAME=TCPX6 case "$TESTS" in *%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*) TEST="$NAME: echo via connection to TCP socket, v6 by target" if ! eval $NUMCOND; then :; -elif ! testfeats tcp ip4 >/dev/null || ! runsip4 >/dev/null; then - $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N +elif ! F=$(testfeats STDIO PIPE IP6 TCP LISTEN); then + $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" -elif ! testfeats ip6 >/dev/null || ! runsip6 >/dev/null; then - $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N +elif ! A=$(testaddrs TCP TCP-LISTEN STDIN STDOUT PIPE); then + $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" +elif ! o=$(testoptions pf) >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" +elif ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}IPv6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else @@ -2201,29 +2251,39 @@ tdiff="$td/test$N.diff" newport tcp6; tsl=$PORT ts="[::1]:$tsl" da="test$N $(date) $RANDOM" -CMD1="$TRACE $SOCAT $opts TCP-LISTEN:$tsl,pf=ip6,$REUSEADDR PIPE" -CMD2="$TRACE $SOCAT $opts STDIN!!STDOUT TCP:$ts" +CMD0="$TRACE $SOCAT $opts TCP-LISTEN:$tsl,pf=ip6,$REUSEADDR PIPE" +CMD1="$TRACE $SOCAT $opts STDIN!!STDOUT TCP:$ts" printf "test $F_n $TEST... " $N -$CMD1 >"$tf" 2>"${te}1" & +$CMD0 >"$tf" 2>"${te}0" & pid=$! # background process id waittcp6port $tsl 1 -echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" +echo "$da" |$CMD1 >>"$tf" 2>>"${te}1" if [ $? -ne 0 ]; then - $PRINTF "$FAILED: $TRACE $SOCAT:\n" - echo "$CMD1 &" - echo "$CMD2" - cat "$te" - numFAIL=$((numFAIL+1)) - listFAIL="$listFAIL $N" + $PRINTF "$FAILED: $TRACE $SOCAT:\n" + echo "$CMD0 &" + cat "${te}0" >&2 + echo "$CMD1" + cat "${te}1" >&2 + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" + namesFAIL="$namesFAIL $NAME" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then - $PRINTF "$FAILED: diff:\n" - cat "$tdiff" - numFAIL=$((numFAIL+1)) - listFAIL="$listFAIL $N" + $PRINTF "$FAILED: diff:\n" + cat "$tdiff" + echo "$CMD0 &" + cat "${te}0" >&2 + echo "$CMD1" + cat "${te}1" >&2 + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" + namesFAIL="$namesFAIL $NAME" else - $PRINTF "$OK\n" - if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi - numOK=$((numOK+1)) + $PRINTF "$OK\n" + if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi + if [ "$DEBUG" ]; then cat "${te}0" >&2; fi + if [ "$VERBOSE" ]; then echo "$CMD1"; fi + if [ "$DEBUG" ]; then cat "${te}1" >&2; fi + numOK=$((numOK+1)) fi kill $pid 2>/dev/null fi @@ -8298,7 +8358,7 @@ newport udp6; ts1p=$PORT if1="$MCINTERFACE" ts1a="[::1]" da="test$N $(date) $RANDOM" -CMD1="$TRACE $SOCAT -u $opts UDP6-RECV:$ts1p,reuseaddr,ipv6-join-group=[ff02::2]:$if1 -" +CMD1="$TRACE $SOCAT -u $opts UDP6-RECV:$ts1p,$REUSEADDR,ipv6-join-group=[ff02::2]:$if1 -" #CMD2="$TRACE $SOCAT -u $opts - UDP6-SENDTO:[ff02::2]:$ts1p,bind=$ts1a" CMD2="$TRACE $SOCAT -u $opts - UDP6-SENDTO:[ff02::2]:$ts1p" printf "test $F_n $TEST... " $N @@ -13589,7 +13649,7 @@ tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" -CMD0="$TRACE $SOCAT $opts FILE:/dev/null OPENSSL-CONNECT:$SNISERVER:443" +CMD0="$TRACE $SOCAT $opts FILE:/dev/null OPENSSL-CONNECT:$SNISERVER:443,pf=ip4" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" rc0=$? @@ -15177,7 +15237,7 @@ tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" -CMD0="$TRACE $SOCAT $opts -t 3 $PROTO-RECVFROM:$tsl,fork SYSTEM:'read t x; sleep \$t; echo \$x >>'\"$tf\"" +CMD0="$TRACE $SOCAT $opts -t 3 $PROTO-RECVFROM:$tsl,fork SYSTEM:'read t x; sleep \$t; echo \\\"\$x\\\" >>'\"$tf\"" CMD1="$TRACE $SOCAT $opts -t 3 - $PROTO-SENDTO:$tsc" printf "test $F_n $TEST... " $N eval $CMD0 "${te}0" & @@ -15947,6 +16007,7 @@ newport tcp6 CMD0a="$TRACE $SOCAT $opts -lp server1 -6 OPENSSL-LISTEN:$PORT,cert=testsrv.crt,key=testsrv.key,verify=0 PIPE" CMD0b="$TRACE $SOCAT $opts -lp server2 -6 OPENSSL-LISTEN:$PORT,accept-timeout=.01,cert=testsrv.crt,key=testsrv.key,verify=0 PIPE" CMD1="$TRACE $SOCAT $opts -lp client -6 -T 0.1 PIPE OPENSSL-CONNECT:$LOCALHOST6:$PORT,verify=0" +printf "test $F_n $TEST... " $N $CMD0a >/dev/null 2>"${te}0a" & pid0=$! waittcp6port $PORT 1 @@ -16077,8 +16138,8 @@ TEST="$NAME: try all available TCP4 addresses" # that is closed on both addresses. # The test succeeded when the log shows that Socat tried to connect two times. if ! eval $NUMCOND; then :; -elif [ -z "$FOREIGN" ]; then - $PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -foreign${NORMAL}\n" $N +elif ! $(type nslookup >/dev/null 2>&1); then + $PRINTF "test $F_n $TEST... ${YELLOW}nslookup not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" #elif ! $(type nslookup >/dev/null 2>&1) && ! $(type host >/dev/null 2>&1); then @@ -16097,6 +16158,10 @@ elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" +elif [ -z "$FOREIGN" ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -foreign${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" @@ -16162,7 +16227,7 @@ elif [ -z "$FOREIGN" ]; then # only needs Internet DNS # $PRINTF "test $F_n $TEST... ${YELLOW}nslookup and host not available${NORMAL}\n" $N # numCANT=$((numCANT+1)) # listCANT="$listCANT $N" -elif ! F=$(testfeats ip4 ip6 tcp); then +elif ! F=$(testfeats IP4 IP6 TCP); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" @@ -16178,6 +16243,10 @@ elif ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv6 not available or not routable${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" +elif [ -z "$FOREIGN" ]; then # only needs Internet DNS + $PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -foreign${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" @@ -16185,10 +16254,18 @@ tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" LOCALHOST_4_6=localhost-4-6.dest-unreach.net if type nslookup >/dev/null 2>&1; then - ADDRS=$(nslookup server-4.dest-unreach.net. |sed -n '/^$/,$ p' |grep ^Address |awk '{print($2);}') + ADDRS=$(nslookup $LOCALHOST_4_6 |sed -n '/^$/,$ p' |grep ^Address |awk '{print($2);}') elif type host >/dev/null 2>&1; then - ADDRS=$(host server-4.dest-unreach.net. |sed 's/.*address //') + ADDRS=$(host $LOCALHOST_4_6 |sed 's/.*address //') fi +# Specific config: on Ubuntu-12.04: getaddrinfo(...AI_ADDRCONFIG) does not +# resolve to IPv6 addresses even when there are link local IPv6 addresses +if test -f /etc/os-release && + grep -q '^NAME="Ubuntu"' /etc/os-release && + grep -q '^VERSION="12\.04' /etc/os-release; then + AI_ADDRCONFIG="ai-addrconfig=0," +fi +# Check if PORT is really closed on both addresses while true; do OPEN= for addr in $ADDRS; do @@ -16196,7 +16273,7 @@ while true; do *.*) ;; *:*) addr="[$addr]" ; esac - if $SOCAT /dev/null TCP:$addr:$PORT 2>/dev/null; then + if $SOCAT /dev/null TCP:$addr:$PORT,$AI_ADDRCONFIG 2>/dev/null; then # port is open :-( OPEN=1 break @@ -16207,7 +16284,7 @@ while true; do fi newport tcp4 done -CMD="$TRACE $SOCAT $opts -d -d /dev/null TCP:localhost-4-6.dest-unreach.net:$PORT" +CMD="$TRACE $SOCAT $opts -d -d /dev/null TCP:$LOCALHOST_4_6:$PORT,$AI_ADDRCONFIG" printf "test $F_n $TEST... " $N $CMD >/dev/null 2>"${te}" rc=$? @@ -16378,8 +16455,8 @@ elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}Must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" -elif ! $(type systemd-socket-activate >/dev/null 2>&1); then - $PRINTF "test $F_n $TEST... ${YELLOW}systemd-socket-activate not available${NORMAL}\n" $N +elif ! $(type nslookup >/dev/null 2>&1); then + $PRINTF "test $F_n $TEST... ${YELLOW}nslookup not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! F=$(testfeats STDIO IP4 TCP PIPE); then @@ -16398,6 +16475,10 @@ elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" +elif ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" elif [ -z "$FOREIGN" ]; then $PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -foreign${NORMAL}\n" $N numCANT=$((numCANT+1)) diff --git a/xio-ip.c b/xio-ip.c index 0d68338..cb5a88a 100644 --- a/xio-ip.c +++ b/xio-ip.c @@ -81,6 +81,10 @@ const struct optdesc opt_ip_recvdstaddr = { "ip-recvdstaddr", "recvdstaddr",OPT_ const struct optdesc opt_ip_recvif = { "ip-recvif", "recvdstaddrif",OPT_IP_RECVIF, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_RECVIF }; #endif +#ifdef AI_ADDRCONFIG +const struct optdesc opt_ai_addrconfig = { "ai-addrconfig", "addrconfig", OPT_AI_ADDRCONFIG, GROUP_SOCK_IP, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.socket.ip.ai_flags), XIO_SIZEOF(para.socket.ip.ai_flags), AI_ADDRCONFIG }; +#endif + #if WITH_RES_DEPRECATED # define WITH_RES_AAONLY 1 # define WITH_RES_PRIMARY 1 @@ -153,8 +157,8 @@ unsigned long res_opts() { */ int xiogetaddrinfo(const char *node, const char *service, int family, int socktype, int protocol, - struct addrinfo **res, - unsigned long res_opts0, unsigned long res_opts1) { + struct addrinfo **res, const int ai_flags[2], + const unsigned long res_opts[2]) { char *numnode = NULL; size_t nodelen; unsigned long save_res_opts = 0; @@ -166,13 +170,13 @@ int xiogetaddrinfo(const char *node, const char *service, int error_num; #if HAVE_RESOLV_H - if (res_opts0 | res_opts1) { + if (res_opts[0] | res_opts[1]) { if (!(_res.options & RES_INIT)) { Res_init(); /*!!! returns -1 on error */ } save_res_opts = _res.options; - _res.options &= ~res_opts0; - _res.options |= res_opts1; + _res.options |= res_opts[0]; + _res.options &= ~res_opts[1]; Debug2("changed _res.options from 0x%lx to 0x%lx", save_res_opts, _res.options); } @@ -203,9 +207,8 @@ int xiogetaddrinfo(const char *node, const char *service, } else if (node && node[0] == '[' && node[(nodelen=strlen(node))-1]==']') { if ((numnode = Malloc(nodelen-1)) == NULL) { #if HAVE_RESOLV_H - if (res_opts0 | res_opts1) { - _res.options = (_res.options & (~res_opts0&~res_opts1) | - save_res_opts& ( res_opts0| res_opts1)); + if (res_opts[0] | res_opts[1]) { + _res.options = save_res_opts; } #endif return STAT_NORETRY; @@ -219,12 +222,17 @@ int xiogetaddrinfo(const char *node, const char *service, if (family == PF_UNSPEC) family = PF_INET6; #endif /* WITH_IP6 */ } - + if (family == 0) + hints.ai_flags |= AI_ADDRCONFIG; + hints.ai_flags |= AI_PASSIVE /* important for IPv4+IPv6 listen */; #if HAVE_GETADDRINFO if (node != NULL || service != NULL) { struct addrinfo *record; - hints.ai_flags |= AI_PASSIVE; /* important for IPv4+IPv6 listen */ + if (ai_flags != NULL) { + hints.ai_flags |= ai_flags[0]; + hints.ai_flags &= ~ai_flags[1]; + } hints.ai_family = family; hints.ai_socktype = socktype; hints.ai_protocol = protocol; @@ -256,7 +264,7 @@ int xiogetaddrinfo(const char *node, const char *service, continue; } if ((error_num = Getaddrinfo(node, service, &hints, res)) != 0) { - Error7("getaddrinfo(\"%s\", \"%s\", {%d,%d,%d,%d}, {}): %s", + Error7("getaddrinfo(\"%s\", \"%s\", {0x%02x,%d,%d,%d}, {}): %s", node?node:"NULL", service?service:"NULL", hints.ai_flags, hints.ai_family, hints.ai_socktype, hints.ai_protocol, @@ -265,9 +273,8 @@ int xiogetaddrinfo(const char *node, const char *service, if (numnode) free(numnode); #if HAVE_RESOLV_H - if (res_opts0 | res_opts1) { - _res.options = (_res.options & (~res_opts0&~res_opts1) | - save_res_opts& ( res_opts0| res_opts1)); + if (res_opts[0] | res_opts[1]) { + _res.options = save_res_opts; } #endif return STAT_RETRYLATER; @@ -364,9 +371,8 @@ int xiogetaddrinfo(const char *node, const char *service, h_errno == NETDB_INTERNAL ? strerror(errno) : hstrerror(h_errno)); #if HAVE_RESOLV_H - if (res_opts0 | res_opts1) { - _res.options = (_res.options & (~res_opts0&~res_opts1) | - save_res_opts& ( res_opts0| res_opts1)); + if (res_opts[0] | res_opts[1]) { + _res.options = save_res_opts; } #endif return STAT_RETRYLATER; @@ -399,9 +405,8 @@ int xiogetaddrinfo(const char *node, const char *service, if (numnode) free(numnode); #if HAVE_RESOLV_H - if (res_opts0 | res_opts1) { - _res.options = (_res.options & (~res_opts0&~res_opts1) | - save_res_opts& ( res_opts0| res_opts1)); + if (res_opts[0] | res_opts[1]) { + _res.options = save_res_opts; } #endif /* HAVE_RESOLV_H */ return STAT_OK; @@ -423,12 +428,13 @@ void xiofreeaddrinfo(struct addrinfo *res) { int xioresolve(const char *node, const char *service, int family, int socktype, int protocol, union sockaddr_union *addr, socklen_t *addrlen, - unsigned long res_opts0, unsigned long res_opts1) { + const int ai_flags[2], const unsigned long res_opts[2]) +{ struct addrinfo *res = NULL; int rc; rc = xiogetaddrinfo(node, service, family, socktype, protocol, - &res, res_opts0, res_opts1); + &res, ai_flags, res_opts); if (rc != 0) { xiofreeaddrinfo(res); return -1; @@ -760,12 +766,12 @@ mc:addr union sockaddr_union sockaddr2; socklen_t socklen2 = sizeof(sockaddr2.ip4); - /* first parameter is alway multicast address */ + /* First parameter is always multicast address */ /*! result */ xioresolve(opt->value.u_string/*multiaddr*/, NULL, - xfd->para.socket.la.soa.sa_family, - SOCK_DGRAM, IPPROTO_IP, - &sockaddr1, &socklen1, 0, 0); + xfd->para.socket.la.soa.sa_family, + SOCK_DGRAM, IPPROTO_IP, &sockaddr1, &socklen1, + xfd->para.socket.ip.ai_flags, xfd->para.socket.ip.res_opts); ip4_mreqn.mreq.imr_multiaddr = sockaddr1.ip4.sin_addr; if (0) { ; /* for canonical reasons */ @@ -774,9 +780,10 @@ mc:addr /* three parameters */ /* second parameter is interface address */ xioresolve(opt->value2.u_string/*param2*/, NULL, - xfd->para.socket.la.soa.sa_family, - SOCK_DGRAM, IPPROTO_IP, - &sockaddr2, &socklen2, 0, 0); + xfd->para.socket.la.soa.sa_family, + SOCK_DGRAM, IPPROTO_IP, &sockaddr2, &socklen2, + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts); ip4_mreqn.mreq.imr_interface = sockaddr2.ip4.sin_addr; /* third parameter is interface */ if (ifindex(opt->value3.u_string/*ifindex*/, @@ -802,9 +809,11 @@ mc:addr } else { /*! result */ xioresolve(opt->value2.u_string/*param2*/, NULL, - xfd->para.socket.la.soa.sa_family, - SOCK_DGRAM, IPPROTO_IP, - &sockaddr2, &socklen2, 0, 0); + xfd->para.socket.la.soa.sa_family, + SOCK_DGRAM, IPPROTO_IP, + &sockaddr2, &socklen2, + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts); ip4_mreqn.mreq.imr_interface = sockaddr2.ip4.sin_addr; } } @@ -953,27 +962,30 @@ int xioapply_ip_add_source_membership(struct single *xfd, struct opt *opt) { /* first parameter is always multicast address */ rc = xioresolve(opt->value.u_string/*mcaddr*/, NULL, - xfd->para.socket.la.soa.sa_family, - SOCK_DGRAM, IPPROTO_IP, - &sockaddr1, &socklen1, 0, 0); + xfd->para.socket.la.soa.sa_family, + SOCK_DGRAM, IPPROTO_IP, + &sockaddr1, &socklen1, xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts); if (rc < 0) { return -1; } ip4_mreq_src.imr_multiaddr = sockaddr1.ip4.sin_addr; /* second parameter is interface address */ rc = xioresolve(opt->value.u_string/*ifaddr*/, NULL, - xfd->para.socket.la.soa.sa_family, - SOCK_DGRAM, IPPROTO_IP, - &sockaddr2, &socklen2, 0, 0); + xfd->para.socket.la.soa.sa_family, + SOCK_DGRAM, IPPROTO_IP, + &sockaddr2, &socklen2, xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts); if (rc < 0) { return -1; } ip4_mreq_src.imr_interface = sockaddr2.ip4.sin_addr; /* third parameter is source address */ rc = xioresolve(opt->value.u_string/*srcaddr*/, NULL, - xfd->para.socket.la.soa.sa_family, - SOCK_DGRAM, IPPROTO_IP, - &sockaddr3, &socklen3, 0, 0); + xfd->para.socket.la.soa.sa_family, + SOCK_DGRAM, IPPROTO_IP, + &sockaddr3, &socklen3, xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts); if (rc < 0) { return -1; } diff --git a/xio-ip.h b/xio-ip.h index 6869b45..2777461 100644 --- a/xio-ip.h +++ b/xio-ip.h @@ -29,6 +29,8 @@ extern const struct optdesc opt_ip_recvdstaddr; extern const struct optdesc opt_ip_recvif; extern const struct optdesc opt_ip_transparent; +extern const struct optdesc opt_ai_addrconfig; + extern const struct optdesc opt_res_debug; extern const struct optdesc opt_res_aaonly; extern const struct optdesc opt_res_usevc; @@ -39,9 +41,11 @@ extern const struct optdesc opt_res_defnames; extern const struct optdesc opt_res_stayopen; extern const struct optdesc opt_res_dnsrch; -extern int xiogetaddrinfo(const char *node, const char *service, int family, int socktype, int protocol, struct addrinfo **res, unsigned long res_opts0, unsigned long res_opts1); +extern int xioinit_ip(struct single *sfd, int *pf); + +extern int xiogetaddrinfo(const char *node, const char *service, int family, int socktype, int protocol, struct addrinfo **res, const int ai_flags[2], const unsigned long res_opts[2]); extern void xiofreeaddrinfo(struct addrinfo *res); -extern int xioresolve(const char *node, const char *service, int family, int socktype, int protocol, union sockaddr_union *addr, socklen_t *addrlen, unsigned long res_opts0, unsigned long res_opts1); +extern int xioresolve(const char *node, const char *service, int family, int socktype, int protocol, union sockaddr_union *addr, socklen_t *addrlen, const int ai_flags[2], const unsigned long res_opts[2]); extern int xiolog_ancillary_ip(struct single *sfd, struct cmsghdr *cmsg, int *num, char *typbuff, int typlen, char *nambuff, int namlen, char *envbuff, int envlen, char *valbuff, int vallen); extern int xiotype_ip_add_membership(char *token, const struct optname *ent, struct opt *opt); extern int xioapply_ip_add_membership(xiosingle_t *xfd, struct opt *opt); diff --git a/xio-ip4.c b/xio-ip4.c index 264a00d..d4efbbe 100644 --- a/xio-ip4.c +++ b/xio-ip4.c @@ -14,7 +14,12 @@ #include "xio-ip4.h" -int xioparsenetwork_ip4(const char *rangename, struct xiorange *range) { +int xioparsenetwork_ip4( + const char *rangename, + struct xiorange *range, + const int ai_flags[2], + const unsigned long res_opts[2]) +{ 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 */ @@ -46,7 +51,7 @@ int xioparsenetwork_ip4(const char *rangename, struct xiorange *range) { } } else if (delimpos = strchr(rangename1, ':')) { if ((rc = xioresolve(delimpos+1, NULL, PF_INET, 0, 0, - &sau, &socklen, 0, 0)) + &sau, &socklen, ai_flags, res_opts)) != STAT_OK) { return rc; } @@ -59,7 +64,7 @@ int xioparsenetwork_ip4(const char *rangename, struct xiorange *range) { { *delimpos = 0; if ((rc = xioresolve(rangename1, NULL, PF_INET, 0, 0, - &sau, &socklen, 0, 0)) + &sau, &socklen, ai_flags, res_opts)) != STAT_OK) { return rc; } diff --git a/xio-ip4.h b/xio-ip4.h index 5d4e277..94d5e86 100644 --- a/xio-ip4.h +++ b/xio-ip4.h @@ -7,7 +7,7 @@ extern const struct optdesc opt_ip4_add_membership; -int xioparsenetwork_ip4(const char *rangename, struct xiorange *range); +extern int xioparsenetwork_ip4(const char *rangename, struct xiorange *range, const int ai_flags[2], const unsigned long res_opts[2]); extern int xiocheckrange_ip4(struct sockaddr_in *pa, struct xiorange *range); extern int diff --git a/xio-ip6.c b/xio-ip6.c index 195e706..b5e8073 100644 --- a/xio-ip6.c +++ b/xio-ip6.c @@ -82,7 +82,12 @@ const struct optdesc opt_ipv6_recvpathmtu = { "ipv6-recvpathmtu", "recvpathmtu", /* Returns canonical form of IPv6 address. IPv6 address may bei enclose in brackets. Returns STAT_OK on success, STAT_NORETRY on failure. */ -int xioip6_pton(const char *src, struct in6_addr *dst) { +int xioip6_pton( + const char *src, + struct in6_addr *dst, + const int ai_flags[2], + const unsigned long res_opts[2]) +{ union sockaddr_union sockaddr; socklen_t sockaddrlen = sizeof(sockaddr); @@ -94,10 +99,10 @@ int xioip6_pton(const char *src, struct in6_addr *dst) { plainaddr[INET6_ADDRSTRLEN-1] = '\0'; if ((clos = strchr(plainaddr, ']')) != NULL) *clos = '\0'; - return xioip6_pton(plainaddr, dst); + return xioip6_pton(plainaddr, dst, ai_flags, res_opts); } if (xioresolve(src, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen, - 0, 0) + ai_flags, res_opts) != STAT_OK) { return STAT_NORETRY; } @@ -105,7 +110,12 @@ int xioip6_pton(const char *src, struct in6_addr *dst) { return STAT_OK; } -int xioparsenetwork_ip6(const char *rangename, struct xiorange *range) { +int xioparsenetwork_ip6( + const char *rangename, + struct xiorange *range, + const int ai_flags[2], + const unsigned long res_opts[2]) +{ char *delimpos; /* absolute address of delimiter */ size_t delimind; /* index of delimiter in string */ unsigned int bits; /* netmask bits */ @@ -135,7 +145,7 @@ int xioparsenetwork_ip6(const char *rangename, struct xiorange *range) { } baseaddr[delimind-2] = '\0'; if (xioresolve(baseaddr, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen, - 0, 0) + ai_flags, res_opts) != STAT_OK) { return STAT_NORETRY; } @@ -480,9 +490,12 @@ int xioapply_ipv6_join_group( /* First parameter is multicast address */ if ((res = xioresolve(opt->value.u_string/*multiaddr*/, NULL, - xfd->para.socket.la.soa.sa_family, - SOCK_DGRAM, IPPROTO_IP, - &sockaddr1, &socklen1, 0, 0)) != STAT_OK) { + xfd->para.socket.la.soa.sa_family, + SOCK_DGRAM, IPPROTO_IP, + &sockaddr1, &socklen1, + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts)) + != STAT_OK) { return res; } ip6_mreq.ipv6mr_multiaddr = sockaddr1.ip6.sin6_addr; @@ -619,9 +632,10 @@ int xioapply_ip6_join_source_group(struct single *xfd, struct opt *opt) { /* First parameter is always multicast address */ if ((res = xioresolve(opt->value.u_string/*mcaddr*/, NULL, - xfd->para.socket.la.soa.sa_family, - SOCK_DGRAM, IPPROTO_IP, - &sockaddr1, &socklen1, 0, 0)) != STAT_OK) { + xfd->para.socket.la.soa.sa_family, + SOCK_DGRAM, IPPROTO_IP, &sockaddr1, &socklen1, + xfd->para.socket.ip.ai_flags, xfd->para.socket.ip.res_opts)) + != STAT_OK) { return res; } memcpy(&ip6_gsr.gsr_group, &sockaddr1.ip6, socklen1); @@ -636,9 +650,10 @@ int xioapply_ip6_join_source_group(struct single *xfd, struct opt *opt) { /* Third parameter is source address */ if ((res = xioresolve(opt->value3.u_string/*srcaddr*/, NULL, - xfd->para.socket.la.soa.sa_family, - SOCK_DGRAM, IPPROTO_IP, - &sockaddr2, &socklen2, 0, 0)) != STAT_OK) { + xfd->para.socket.la.soa.sa_family, + SOCK_DGRAM, IPPROTO_IP, &sockaddr2, &socklen2, + xfd->para.socket.ip.ai_flags, xfd->para.socket.ip.res_opts)) + != STAT_OK) { return res; } memcpy(&ip6_gsr.gsr_source, &sockaddr2.ip6, socklen2); diff --git a/xio-ip6.h b/xio-ip6.h index fb25cb5..22d9e9b 100644 --- a/xio-ip6.h +++ b/xio-ip6.h @@ -32,9 +32,8 @@ extern const struct optdesc opt_ipv6_tclass; extern const struct optdesc opt_ipv6_recvtclass; extern const struct optdesc opt_ipv6_recvpathmtu; -extern int xioip6_pton(const char *src, struct in6_addr *dst); -extern -int xioparsenetwork_ip6(const char *rangename, struct xiorange *range); +extern int xioip6_pton(const char *src, struct in6_addr *dst, const int ai_flags[2], const unsigned long res_opts[2]); +extern int xioparsenetwork_ip6(const char *rangename, struct xiorange *range, const int ai_flags[2], const unsigned long res_opts[2]); extern int xiorange_ip6andmask(struct xiorange *range); extern diff --git a/xio-ipapp.c b/xio-ipapp.c index c0a6b59..fabc7b7 100644 --- a/xio-ipapp.c +++ b/xio-ipapp.c @@ -42,6 +42,7 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, Error2("%s: wrong number of parameters (%d instead of 2)", argv[0], argc-1); } + xioinit_ip(xfd, &pf); xfd->howtoend = END_SHUTDOWN; if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; @@ -50,8 +51,8 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, retropt_bool(opts, OPT_FORK, &dofork); if (_xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto, - xfd->para.socket.ip.res_opts[1], - xfd->para.socket.ip.res_opts[0], + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts, &themlist, us, &uslen, &needbind, &lowport, socktype) != STAT_OK) { return STAT_NORETRY; @@ -170,16 +171,21 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, OPT_PROTOCOL_FAMILY, OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT */ int - _xioopen_ipapp_prepare(struct opt *opts, struct opt **opts0, - const char *hostname, - const char *portname, - int *pf, - int protocol, - unsigned long res_opts0, unsigned long res_opts1, - struct addrinfo **themlist, - union sockaddr_union *us, socklen_t *uslen, - bool *needbind, bool *lowport, - int socktype) { + _xioopen_ipapp_prepare( + struct opt *opts, + struct opt **opts0, + const char *hostname, + const char *portname, + int *pf, + int protocol, + const int ai_flags[2], + const unsigned long res_opts[2], + struct addrinfo **themlist, + union sockaddr_union *us, + socklen_t *uslen, + bool *needbind, + bool *lowport, + int socktype) { uint16_t port; int result; @@ -188,9 +194,7 @@ int if ((result = xiogetaddrinfo(hostname, portname, *pf, socktype, protocol, - themlist, - res_opts0, res_opts1 - )) + themlist, ai_flags, res_opts)) != STAT_OK) { return STAT_NORETRY; /*! STAT_RETRYLATER? */ } @@ -200,7 +204,7 @@ int /* 3 means: IP address AND port accepted */ if (retropt_bind(opts, (*pf!=PF_UNSPEC)?*pf:(*themlist)->ai_family, socktype, protocol, (struct sockaddr *)us, uslen, 3, - res_opts0, res_opts1) + ai_flags, res_opts) != STAT_NOACTION) { *needbind = true; } else { @@ -242,12 +246,18 @@ int applies and consumes the following options: OPT_PROTOCOL_FAMILY, OPT_BIND */ -int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0, - const char *portname, int *pf, int ipproto, - unsigned long res_opts0, - unsigned long res_opts1, - union sockaddr_union *us, socklen_t *uslen, - int socktype) { +int _xioopen_ipapp_listen_prepare( + struct opt *opts, + struct opt **opts0, + const char *portname, + int *pf, + int ipproto, + const int ai_flags[2], + const unsigned long res_opts[2], + union sockaddr_union *us, + socklen_t *uslen, + int socktype) +{ char *bindname = NULL; int result; @@ -256,8 +266,7 @@ int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0, retropt_string(opts, OPT_BIND, &bindname); result = xioresolve(bindname, portname, *pf, socktype, ipproto, - us, uslen, - res_opts0, res_opts1); + us, uslen, ai_flags, res_opts); if (result != STAT_OK) { /*! STAT_RETRY? */ return result; @@ -270,7 +279,7 @@ int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0, /* we expect the form: port */ /* currently only used for TCP4 */ int xioopen_ipapp_listen(int argc, const char *argv[], struct opt *opts, - int xioflags, xiofile_t *fd, + int xioflags, xiofile_t *xfd, groups_t groups, int socktype, int ipproto, int pf) { struct opt *opts0 = NULL; @@ -282,6 +291,7 @@ int xioopen_ipapp_listen(int argc, const char *argv[], struct opt *opts, Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1); } + xioinit_ip(&xfd->stream, &pf); if (pf == PF_UNSPEC) { #if WITH_IP4 && WITH_IP6 switch (xioparms.default_ip) { @@ -296,22 +306,22 @@ int xioopen_ipapp_listen(int argc, const char *argv[], struct opt *opts, #endif } - fd->stream.howtoend = END_SHUTDOWN; + xfd->stream.howtoend = END_SHUTDOWN; - if (applyopts_single(&fd->stream, opts, PH_INIT) < 0) return -1; + if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1; applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_EARLY); if (_xioopen_ipapp_listen_prepare(opts, &opts0, argv[1], &pf, ipproto, - fd->stream.para.socket.ip.res_opts[1], - fd->stream.para.socket.ip.res_opts[0], + xfd->stream.para.socket.ip.ai_flags, + xfd->stream.para.socket.ip.res_opts, us, &uslen, socktype) != STAT_OK) { return STAT_NORETRY; } if ((result = - xioopen_listen(&fd->stream, xioflags, + xioopen_listen(&xfd->stream, xioflags, (struct sockaddr *)us, uslen, opts, opts0, pf, socktype, ipproto)) != 0) diff --git a/xio-ipapp.h b/xio-ipapp.h index b064c2f..1767fff 100644 --- a/xio-ipapp.h +++ b/xio-ipapp.h @@ -17,15 +17,8 @@ extern const struct optdesc opt_lowport; extern int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, groups_t groups, int socktype, int ipproto, int protname); -extern int - _xioopen_ipapp_prepare(struct opt *opts, struct opt **opts0, - const char *hostname, - const char *portname, int *pf, int protocol, - unsigned long res_opts0, unsigned long res_opts1, - struct addrinfo **res, - union sockaddr_union *us, socklen_t *uslen, - bool *needbind, bool *lowport, - int socktype); +extern int _xioopen_ipapp_prepare(struct opt *opts, struct opt **opts0, const char *hostname, const char *portname, int *pf, int protocol, const int ai_flags[2], const unsigned long res_opts[2], struct addrinfo **res, union sockaddr_union *us, socklen_t *uslen, bool *needbind, bool *lowport, + int socktype); extern int _xioopen_ip4app_connect(const char *hostname, const char *portname, struct single *xfd, int socktype, int ipproto, void *protname, @@ -34,11 +27,6 @@ extern int xioopen_ipapp_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, groups_t groups, int socktype, int ipproto, int protname); -extern int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0, - const char *portname, int *pf, int ipproto, - unsigned long res_opts0, - unsigned long res_opts1, - union sockaddr_union *us, socklen_t *uslen, - int socktype); +extern int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0, const char *portname, int *pf, int ipproto, const int ai_flags[2], const unsigned long res_opts[2], union sockaddr_union *us, socklen_t *uslen, int socktype); #endif /* !defined(__xio_ipapp_h_included) */ diff --git a/xio-listen.c b/xio-listen.c index 882caa5..408b348 100644 --- a/xio-listen.c +++ b/xio-listen.c @@ -199,7 +199,10 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl #if WITH_IP4 /*|| WITH_IP6*/ if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { - if (xioparserange(rangename, pf, &xfd->para.socket.range) < 0) { + if (xioparserange(rangename, pf, &xfd->para.socket.range, + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts) + < 0) { free(rangename); return STAT_NORETRY; } diff --git a/xio-openssl.c b/xio-openssl.c index 479cd67..42197b7 100644 --- a/xio-openssl.c +++ b/xio-openssl.c @@ -280,6 +280,7 @@ static int return STAT_NORETRY; } + xioinit_ip(xfd, &pf); xfd->howtoend = END_SHUTDOWN; if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; applyopts(-1, opts, PH_INIT); @@ -326,8 +327,8 @@ static int result = _xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto, - xfd->para.socket.ip.res_opts[1], - xfd->para.socket.ip.res_opts[0], + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts, &themlist, us, &uslen, &needbind, &lowport, socktype); if (result != STAT_OK) return STAT_NORETRY; @@ -571,6 +572,7 @@ static int return STAT_NORETRY; } + xioinit_ip(xfd, &pf); #if WITH_IP4 && WITH_IP6 switch (xioparms.default_ip) { case '4': pf = PF_INET; break; @@ -610,8 +612,8 @@ static int retropt_int(opts, OPT_SO_PROTOTYPE, &ipproto); if (_xioopen_ipapp_listen_prepare(opts, &opts0, portname, &pf, ipproto, - xfd->para.socket.ip.res_opts[1], - xfd->para.socket.ip.res_opts[0], + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts, us, &uslen, socktype) != STAT_OK) { return STAT_NORETRY; @@ -1894,7 +1896,8 @@ static int openssl_handle_peer_certificate(struct single *xfd, case 16: /* IPv6 */ inet_ntop(AF_INET6, data, aBuffer, sizeof(aBuffer)); if (peername != NULL) { - xioip6_pton(peername, &ip6bin); + xioip6_pton(peername, &ip6bin, xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts); if (memcmp(data, &ip6bin, sizeof(ip6bin)) == 0) { Debug2("subjectAltName \"%s\" matches peername \"%s\"", aBuffer, peername); diff --git a/xio-proxy.c b/xio-proxy.c index bcda8ad..2753d70 100644 --- a/xio-proxy.c +++ b/xio-proxy.c @@ -110,6 +110,7 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts, targetname = argv[2]; targetport = argv[3]; + xioinit_ip(xfd, &pf); xfd->howtoend = END_SHUTDOWN; if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; applyopts(-1, opts, PH_INIT); @@ -124,14 +125,16 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts, } } - result = _xioopen_proxy_prepare(proxyvars, opts, targetname, targetport); + result = _xioopen_proxy_prepare(proxyvars, opts, targetname, targetport, + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts); if (result != STAT_OK) return result; result = _xioopen_ipapp_prepare(opts, &opts0, proxyname, proxyport, &pf, ipproto, - xfd->para.socket.ip.res_opts[1], - xfd->para.socket.ip.res_opts[0], + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts, &themlist, us, &uslen, &needbind, &lowport, socktype); if (result != STAT_OK) return result; @@ -242,8 +245,13 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts, } -int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts, - const char *targetname, const char *targetport) { +int _xioopen_proxy_prepare( + struct proxyvars *proxyvars, + struct opt *opts, + const char *targetname, + const char *targetport, + const int ai_flags[2], + const unsigned long res_opts[2]) { union sockaddr_union host; socklen_t socklen = sizeof(host); int rc; @@ -300,10 +308,10 @@ int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts, if (proxyvars->doresolve) { /* currently we only resolve to IPv4 addresses. This is in accordance to RFC 2396; however once it becomes clear how IPv6 addresses should be - represented in CONNECT commands this code might be extended */ + represented in CONNECT commands this code might need to be extended */ rc = xioresolve(targetname, targetport, PF_INET/*!?*/, - SOCK_STREAM, IPPROTO_TCP, - &host, &socklen, 0, 0); + SOCK_STREAM, IPPROTO_TCP, + &host, &socklen, ai_flags, res_opts); if (rc != STAT_OK) { proxyvars->targetaddr = strdup(targetname); } else { diff --git a/xio-proxy.h b/xio-proxy.h index ff8530b..c8a1d26 100644 --- a/xio-proxy.h +++ b/xio-proxy.h @@ -25,8 +25,7 @@ extern const struct optdesc opt_proxy_authorization_file; extern const struct addrdesc xioaddr_proxy_connect; -int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts, - const char *targetname, const char *targetport); +extern int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts, const char *targetname, const char *targetport, const int ai_flags[2], const unsigned long res_opts[2]); int _xioopen_proxy_connect(struct single *xfd, struct proxyvars *proxyvars, int level); diff --git a/xio-rawip.c b/xio-rawip.c index 76984f9..a314a75 100644 --- a/xio-rawip.c +++ b/xio-rawip.c @@ -73,6 +73,8 @@ int xioopen_rawip_sendto(int argc, const char *argv[], struct opt *opts, argv[0], argc-1); return STAT_NORETRY; } + + xioinit_ip(&xxfd->stream, &pf); if ((result = _xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd, groups, &pf)) != STAT_OK) { return result; @@ -123,8 +125,8 @@ int _xioopen_rawip_sendto(const char *hostname, const char *protname, if ((result = xioresolve(hostname, NULL, *pf, socktype, ipproto, &xfd->peersa, &xfd->salen, - xfd->para.socket.ip.res_opts[0], - xfd->para.socket.ip.res_opts[1])) + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts)) != STAT_OK) { return result; } @@ -137,8 +139,9 @@ int _xioopen_rawip_sendto(const char *hostname, const char *protname, xfd->dtype = XIODATA_RECVFROM_SKIPIP; if (retropt_bind(opts, *pf, socktype, ipproto, &us.soa, &uslen, feats, - xfd->para.socket.ip.res_opts[0], - xfd->para.socket.ip.res_opts[1]) != STAT_NOACTION) { + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts) + != STAT_NOACTION) { needbind = true; } return @@ -161,6 +164,8 @@ int xioopen_rawip_datagram(int argc, const char *argv[], struct opt *opts, argv[0], argc-1); return STAT_NORETRY; } + + xioinit_ip(xfd, &pf); if ((result = _xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd, groups, &pf)) != STAT_OK) { @@ -176,7 +181,10 @@ 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 (xioparserange(rangename, pf, &xfd->para.socket.range) < 0) { + if (xioparserange(rangename, pf, &xfd->para.socket.range, + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts) + < 0) { free(rangename); return STAT_NORETRY; } @@ -212,6 +220,7 @@ int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts, return STAT_NORETRY; } + xioinit_ip(&xfd->stream, &pf); if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) { Error2("xioopen_rawip_recvfrom(\"%s\",,): protocol number exceeds 255 (%u)", protname, ipproto); @@ -239,8 +248,9 @@ int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts, } if (retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, 1, - xfd->stream.para.socket.ip.res_opts[0], - xfd->stream.para.socket.ip.res_opts[1]) != STAT_NOACTION) { + xfd->stream.para.socket.ip.ai_flags, + xfd->stream.para.socket.ip.res_opts) + != STAT_NOACTION) { needbind = true; } @@ -274,6 +284,7 @@ int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts, return STAT_NORETRY; } + xioinit_ip(&xfd->stream, &pf); if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) { Error2("xioopen_rawip_recv(\"%s\",,): protocol number exceeds 255 (%u)", protname, ipproto); @@ -297,9 +308,9 @@ int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts, 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) { + xfd->stream.para.socket.ip.ai_flags, + xfd->stream.para.socket.ip.res_opts) + == STAT_OK) { needbind = true; } else { /* pf is required during xioread checks */ diff --git a/xio-socket.c b/xio-socket.c index 572cdb7..749ac0d 100644 --- a/xio-socket.c +++ b/xio-socket.c @@ -277,7 +277,7 @@ int xioopen_socket_connect(int argc, const char *argv[], struct opt *opts, socket_init(0, &us); if (retropt_bind(opts, 0 /*pf*/, socktype, proto, (struct sockaddr *)&us, &uslen, 3, - 0, 0) + xfd->para.socket.ip.ai_flags, xfd->para.socket.ip.res_opts) != STAT_NOACTION) { needbind = true; us.soa.sa_family = pf; @@ -540,7 +540,10 @@ int xioopen_socket_recvfrom(int argc, const char *argv[], struct opt *opts, xfd->dtype = XIOREAD_RECV|XIOWRITE_SENDTO; if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { - if (xioparserange(rangename, 0, &xfd->para.socket.range) < 0) { + if (xioparserange(rangename, 0, &xfd->para.socket.range, + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts) + < 0) { free(rangename); return STAT_NORETRY; } @@ -619,7 +622,10 @@ int xioopen_socket_recv(int argc, const char *argv[], struct opt *opts, 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) { + if (xioparserange(rangename, 0, &xfd->para.socket.range, + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts) + < 0) { free(rangename); return STAT_NORETRY; } @@ -699,7 +705,10 @@ int xioopen_socket_datagram(int argc, const char *argv[], struct opt *opts, /* 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) { + if (xioparserange(rangename, 0, &xfd->para.socket.range, + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts) + < 0) { free(rangename); return STAT_NORETRY; } @@ -1169,7 +1178,10 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags, /* for generic sockets, this has already been retrieved */ if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { - if (xioparserange(rangename, pf, &xfd->para.socket.range) < 0) { + if (xioparserange(rangename, pf, &xfd->para.socket.range, + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts) + < 0) { free(rangename); return STAT_NORETRY; } @@ -1371,7 +1383,10 @@ int _xioopen_dgram_recv(struct single *xfd, int xioflags, #if WITH_IP4 /*|| WITH_IP6*/ if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { - if (xioparserange(rangename, pf, &xfd->para.socket.range) < 0) { + if (xioparserange(rangename, pf, &xfd->para.socket.range, + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts) + < 0) { free(rangename); return STAT_NORETRY; } @@ -1814,19 +1829,25 @@ 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) { +int xioparsenetwork( + const char *rangename, + int pf, + struct xiorange *range, + const int ai_flags[2], + const unsigned long res_opts[2]) +{ size_t addrlen = 0, masklen = 0; int result; switch (pf) { #if WITH_IP4 case PF_INET: - return xioparsenetwork_ip4(rangename, range); + return xioparsenetwork_ip4(rangename, range, ai_flags, res_opts); break; #endif /* WITH_IP4 */ #if WITH_IP6 case PF_INET6: - return xioparsenetwork_ip6(rangename, range); + return xioparsenetwork_ip6(rangename, range, ai_flags, res_opts); break; #endif /* WITH_IP6 */ case PF_UNSPEC: @@ -1887,9 +1908,15 @@ int xioparsenetwork(const char *rangename, int pf, struct xiorange *range) { /* 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 xioparserange( + const char *rangename, + int pf, + struct xiorange *range, + const int ai_flags[2], + const unsigned long res_opts[2]) +{ int i; - if (xioparsenetwork(rangename, pf, range) < 0) { + if (xioparsenetwork(rangename, pf, range, ai_flags, res_opts) < 0) { Error2("failed to parse or resolve range \"%s\" (pf=%d)", rangename, pf); return -1; } diff --git a/xio-socket.h b/xio-socket.h index c7be43a..cea2749 100644 --- a/xio-socket.h +++ b/xio-socket.h @@ -125,11 +125,8 @@ int xiocheckpeer(xiosingle_t *xfd, 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 xioparsenetwork(const char *rangename, int pf, struct xiorange *range, const int ai_flags[2], const unsigned long res_opts[2]); +extern int xioparserange(const char *rangename, int pf, struct xiorange *range, const int ai_flags[2], const unsigned long res_opts[2]); extern int xiosocket(struct opt *opts, int pf, int socktype, int proto, int level); diff --git a/xio-socks.c b/xio-socks.c index b7472e5..77e5312 100644 --- a/xio-socks.c +++ b/xio-socks.c @@ -72,6 +72,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts targetname = argv[2]; targetport = argv[3]; + xioinit_ip(xfd, &pf); xfd->howtoend = END_SHUTDOWN; if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; applyopts(-1, opts, PH_INIT); @@ -85,8 +86,8 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts result = _xioopen_ipapp_prepare(opts, &opts0, sockdname, socksport, &pf, ipproto, - xfd->para.socket.ip.res_opts[1], - xfd->para.socket.ip.res_opts[0], + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts, &themlist, us, &uslen, &needbind, &lowport, socktype); @@ -272,10 +273,10 @@ int socklen_t saulen = sizeof(sau); if ((result = xioresolve(hostname, NULL, - PF_INET, SOCK_STREAM, IPPROTO_TCP, - &sau, &saulen, - xfd->para.socket.ip.res_opts[1], - xfd->para.socket.ip.res_opts[0])) + PF_INET, SOCK_STREAM, IPPROTO_TCP, + &sau, &saulen, + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts)) != STAT_OK) { return result; /*! STAT_RETRY? */ } diff --git a/xio-tun.c b/xio-tun.c index 707331e..e7eb003 100644 --- a/xio-tun.c +++ b/xio-tun.c @@ -133,7 +133,10 @@ static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xiofl Error1("strdup(\"%s\"): out of memory", argv[1]); return STAT_RETRYLATER; } - if ((result = xioparsenetwork(ifaddr, pf, &network)) != STAT_OK) { + if ((result = xioparsenetwork(ifaddr, pf, &network, + xfd->stream.para.socket.ip.ai_flags, + xfd->stream.para.socket.ip.res_opts)) + != STAT_OK) { /*! recover */ return result; } diff --git a/xio-udp.c b/xio-udp.c index 5a3215f..8e7477e 100644 --- a/xio-udp.c +++ b/xio-udp.c @@ -107,7 +107,10 @@ int _xioopen_ipdgram_listen(struct single *sfd, #if WITH_IP4 /*|| WITH_IP6*/ if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { - if (xioparserange(rangename, pf, &sfd->para.socket.range) < 0) { + if (xioparserange(rangename, pf, &sfd->para.socket.range, + sfd->para.socket.ip.ai_flags, + sfd->para.socket.ip.res_opts) + < 0) { free(rangename); return STAT_NORETRY; } @@ -282,7 +285,7 @@ int _xioopen_ipdgram_listen(struct single *sfd, /* we expect the form: port */ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, - int xioflags, xiofile_t *fd, + int xioflags, xiofile_t *xfd, groups_t groups, int pf, int ipproto, int protname) { const char *portname = argv[1]; @@ -294,6 +297,7 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1); } + xioinit_ip(&xfd->stream, &pf); if (pf == PF_UNSPEC) { #if WITH_IP4 && WITH_IP6 switch (xioparms.default_ip) { @@ -311,14 +315,14 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, retropt_socket_pf(opts, &pf); retropt_int(opts, OPT_SO_PROTOTYPE, &ipproto); - if (applyopts_single(&fd->stream, opts, PH_INIT) < 0) return -1; + if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1; applyopts(-1, opts, PH_INIT); uslen = socket_init(pf, &us); retropt_bind(opts, pf, socktype, ipproto, (struct sockaddr *)&us, &uslen, 1, - fd->stream.para.socket.ip.res_opts[1], - fd->stream.para.socket.ip.res_opts[0]); + xfd->stream.para.socket.ip.ai_flags, + xfd->stream.para.socket.ip.res_opts); if (false) { ; @@ -334,13 +338,13 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, Error1("xioopen_ipdgram_listen(): unknown address family %d", pf); } - return _xioopen_ipdgram_listen(&fd->stream, xioflags, &us, uslen, + return _xioopen_ipdgram_listen(&xfd->stream, xioflags, &us, uslen, opts, pf, socktype, ipproto); } static int xioopen_udp_sendto(int argc, const char *argv[], struct opt *opts, - int xioflags, xiofile_t *xxfd, groups_t groups, + int xioflags, xiofile_t *xfd, groups_t groups, int pf, int socktype, int ipproto) { int result; @@ -350,13 +354,14 @@ int xioopen_udp_sendto(int argc, const char *argv[], struct opt *opts, return STAT_NORETRY; } + xioinit_ip(&xfd->stream, &pf); retropt_socket_pf(opts, &pf); - if ((result = _xioopen_udp_sendto(argv[1], argv[2], opts, xioflags, xxfd, + if ((result = _xioopen_udp_sendto(argv[1], argv[2], opts, xioflags, xfd, groups, pf, socktype, ipproto)) != STAT_OK) { return result; } - _xio_openlate(&xxfd->stream, opts); + _xio_openlate(&xfd->stream, opts); return STAT_OK; } @@ -387,9 +392,9 @@ int _xioopen_udp_sendto(const char *hostname, const char *servname, xfd->salen = sizeof(xfd->peersa); if ((result = xioresolve(hostname, servname, pf, socktype, ipproto, - &xfd->peersa, &xfd->salen, - xfd->para.socket.ip.res_opts[0], - xfd->para.socket.ip.res_opts[1])) + &xfd->peersa, &xfd->salen, + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts)) != STAT_OK) { return result; } @@ -398,8 +403,8 @@ int _xioopen_udp_sendto(const char *hostname, const char *servname, } uslen = socket_init(pf, &us); if (retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, feats, - xfd->para.socket.ip.res_opts[0], - xfd->para.socket.ip.res_opts[1]) + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts) != STAT_NOACTION) { needbind = true; } @@ -446,6 +451,7 @@ int xioopen_udp_datagram(int argc, const char *argv[], struct opt *opts, return STAT_NORETRY; } + xioinit_ip(xfd, &pf); if ((hostname = strdup(argv[1])) == NULL) { Error1("strdup(\"%s\"): out of memory", argv[1]); return STAT_RETRYLATER; @@ -474,7 +480,10 @@ 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 (xioparserange(rangename, pf, &xfd->para.socket.range) < 0) { + if (xioparserange(rangename, pf, &xfd->para.socket.range, + xfd->para.socket.ip.ai_flags, + xfd->para.socket.ip.res_opts) + < 0) { free(rangename); return STAT_NORETRY; } @@ -506,6 +515,7 @@ int xioopen_udp_recvfrom(int argc, const char *argv[], struct opt *opts, return STAT_NORETRY; } + xioinit_ip(&xfd->stream, &pf); xfd->stream.howtoend = END_NONE; retropt_socket_pf(opts, &pf); if (pf == PF_UNSPEC) { @@ -523,9 +533,9 @@ int xioopen_udp_recvfrom(int argc, const char *argv[], struct opt *opts, } if ((result = - xioresolve(NULL, argv[1], pf, socktype, ipproto, - &us, &uslen, xfd->stream.para.socket.ip.res_opts[0], - xfd->stream.para.socket.ip.res_opts[1])) + xioresolve(NULL, argv[1], pf, socktype, ipproto, &us, &uslen, + xfd->stream.para.socket.ip.ai_flags, + xfd->stream.para.socket.ip.res_opts)) != STAT_OK) { return result; } @@ -538,8 +548,8 @@ int xioopen_udp_recvfrom(int argc, const char *argv[], struct opt *opts, socklen_t lalen = sizeof(la); if (retropt_bind(opts, pf, socktype, ipproto, &la.soa, &lalen, 1, - xfd->stream.para.socket.ip.res_opts[0], - xfd->stream.para.socket.ip.res_opts[1]) + xfd->stream.para.socket.ip.ai_flags, + xfd->stream.para.socket.ip.res_opts) != STAT_NOACTION) { switch (pf) { #if WITH_IP4 @@ -584,6 +594,7 @@ int xioopen_udp_recv(int argc, const char *argv[], struct opt *opts, return STAT_NORETRY; } + xioinit_ip(&xfd->stream, &pf); retropt_socket_pf(opts, &pf); if (pf == PF_UNSPEC) { #if WITH_IP4 && WITH_IP6 @@ -600,9 +611,9 @@ int xioopen_udp_recv(int argc, const char *argv[], struct opt *opts, } if ((result = - xioresolve(NULL, argv[1], pf, socktype, ipproto, - &us, &uslen, xfd->stream.para.socket.ip.res_opts[0], - xfd->stream.para.socket.ip.res_opts[1])) + xioresolve(NULL, argv[1], pf, socktype, ipproto, &us, &uslen, + xfd->stream.para.socket.ip.ai_flags, + xfd->stream.para.socket.ip.res_opts)) != STAT_OK) { return result; } @@ -617,8 +628,8 @@ int xioopen_udp_recv(int argc, const char *argv[], struct opt *opts, if (retropt_bind(opts, pf, socktype, ipproto, &xfd->stream.para.socket.la.soa, &lalen, 1, - xfd->stream.para.socket.ip.res_opts[0], - xfd->stream.para.socket.ip.res_opts[1]) + xfd->stream.para.socket.ip.ai_flags, + xfd->stream.para.socket.ip.res_opts) != STAT_NOACTION) { switch (pf) { #if WITH_IP4 @@ -638,7 +649,10 @@ 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 (xioparserange(rangename, pf, &xfd->stream.para.socket.range) < 0) { + if (xioparserange(rangename, pf, &xfd->stream.para.socket.range, + xfd->stream.para.socket.ip.ai_flags, + xfd->stream.para.socket.ip.res_opts) + < 0) { free(rangename); return STAT_NORETRY; } diff --git a/xio-unix.c b/xio-unix.c index 3cc4f36..5de2bd6 100644 --- a/xio-unix.c +++ b/xio-unix.c @@ -240,7 +240,8 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts, retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); } if (retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&us, &uslen, - (abstract<<1)|xfd->para.socket.un.tight, 0, 0) == STAT_OK) { + (abstract<<1)|xfd->para.socket.un.tight, NULL, NULL) + == STAT_OK) { needbind = true; } @@ -383,7 +384,8 @@ static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, i xfd->dtype = XIODATA_RECVFROM; if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen, - (abstract<<1)| xfd->para.socket.un.tight, 0, 0) == STAT_OK) { + (abstract<<1)| xfd->para.socket.un.tight, NULL, NULL) + == STAT_OK) { needbind = true; } @@ -451,7 +453,8 @@ int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts, #if 0 if (retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&us, &uslen, - (abstract<<1)|xfd->para.socket.un.tight, 0, 0) == STAT_OK) { + (abstract<<1)|xfd->para.socket.un.tight, NULL, NULL) + == STAT_OK) { } #endif @@ -531,7 +534,7 @@ int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts, #if 0 if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen, - (abstract<<1)|xfd->para.socket.un.tight, 0, 0) + (abstract<<1)|xfd->para.socket.un.tight, NULL, NULL) == STAT_OK) { } #endif @@ -616,7 +619,7 @@ _xioopen_unix_client(xiosingle_t *xfd, int xioflags, groups_t groups, retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); } if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen, - (abstract<<1)|xfd->para.socket.un.tight, 0, 0) + (abstract<<1)|xfd->para.socket.un.tight, NULL, NULL) != STAT_NOACTION) { needbind = true; } diff --git a/xio-vsock.c b/xio-vsock.c index e6e6465..fca97f0 100644 --- a/xio-vsock.c +++ b/xio-vsock.c @@ -96,7 +96,8 @@ static int xioopen_vsock_connect(int argc, const char *argv[], struct opt *opts, xiolog_vsock_cid(); ret = retropt_bind(opts, pf, socktype, protocol, - (struct sockaddr *)&sa_local, &sa_len, 3, 0, 0); + (struct sockaddr *)&sa_local, &sa_len, 3, + NULL, NULL); if (ret == STAT_NORETRY) return ret; if (ret == STAT_OK) @@ -153,7 +154,7 @@ static int xioopen_vsock_listen(int argc, const char *argv[], struct opt *opts, opts0 = copyopts(opts, GROUP_ALL); ret = retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&sa_bind, - &sa_len, 1, 0, 0); + &sa_len, 1, NULL, NULL); if (ret == STAT_NORETRY) return ret; if (ret == STAT_OK) diff --git a/xio.h b/xio.h index 910909c..1d72fa3 100644 --- a/xio.h +++ b/xio.h @@ -130,7 +130,8 @@ extern xioparms_t xioparms; #if _WITH_IP4 || _WITH_IP6 struct para_ip { - unsigned int res_opts[2]; /* bits to be set in _res.options are + int ai_flags[2]; /* flags for getaddrinfo() ai_flags (set/unset) */ + unsigned long res_opts[2]; /* bits to be set in _res.options are at [0], bits to be cleared are at [1] */ bool dosourceport; /* check the source port of incoming connection or packets */ uint16_t sourceport; /* host byte order */ diff --git a/xioopts.c b/xioopts.c index 2154a12..7878096 100644 --- a/xioopts.c +++ b/xioopts.c @@ -172,6 +172,12 @@ const struct optname optionnames[] = { #endif #if defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP) IF_IP ("add-source-membership", &opt_ip_add_source_membership) +#endif +#if defined(AI_ADDRCONFIG) + IF_IP ("addrconfig", &opt_ai_addrconfig) +#endif +#if defined(AI_ADDRCONFIG) + IF_IP ("ai-addrconfig", &opt_ai_addrconfig) #endif IF_INTERFACE("allmulti", &opt_iff_allmulti) #if WITH_LIBWRAP && defined(HAVE_HOSTS_ALLOW_TABLE) @@ -2597,8 +2603,8 @@ int parseopts_table(const char **a, groups_t groups, struct opt **opts, } *buffp = '\0'; if (xioresolve(buff, NULL, AF_INET, SOCK_DGRAM, IPPROTO_IP, - (union sockaddr_union *)&sa, &salen, - 0, 0/*!!!*/) != STAT_OK) { + (union sockaddr_union *)&sa, &salen, NULL, + NULL/*!! !*/) != STAT_OK) { opt->desc = ODESC_ERROR; continue; } opt->value.u_ip4addr = sa.sin_addr; @@ -3109,7 +3115,8 @@ int retropt_bind(struct opt *opts, UNIX (or'd): 1..tight 2..abstract */ - unsigned long res_opts0, unsigned long res_opts1) { + const int ai_flags[2], const unsigned long res_opts[2]) +{ const char portsep[] = ":"; const char *ends[] = { portsep, NULL }; const char *nests[] = { "[", "]", NULL }; @@ -3175,9 +3182,9 @@ int retropt_bind(struct opt *opts, } if ((result = xioresolve(hostname[0]!='\0'?hostname:NULL, portp, - af, socktype, ipproto, - (union sockaddr_union *)sa, salen, - res_opts0, res_opts1)) + af, socktype, ipproto, + (union sockaddr_union *)sa, salen, + ai_flags, res_opts)) != STAT_OK) { Error("error resolving bind option"); return STAT_NORETRY; @@ -4070,6 +4077,10 @@ int applyopts_single(struct single *xfd, struct opt *opts, enum e_phase phase) { break; case OFUNC_OFFSET_MASKS: + /* An external (e.g. library) variable with independent bits is to be + manipulated. Here the data target is an array with size 2, the first + element holds the bit mask to be set, the second one those to be + cleared. Each related option sets or unsets a specific bit. */ { void *masks = (char *)xfd + opt->desc->major; size_t masksize = opt->desc->minor; @@ -4089,8 +4100,14 @@ int applyopts_single(struct single *xfd, struct opt *opts, enum e_phase phase) { ((uint32_t *)masks)[1] |= bit; } break; + case sizeof(uint64_t): + if (opt->value.u_bool) { + ((uint64_t *)masks)[0] |= bit; + } else { + ((uint64_t *)masks)[1] |= bit; + } + break; default: - Info1("sizeof(uint32_t)="F_Zu, sizeof(uint32_t)); Error1("applyopts_single: masksize "F_Zu" not implemented", masksize); } diff --git a/xioopts.h b/xioopts.h index d1893b9..ab9fe88 100644 --- a/xioopts.h +++ b/xioopts.h @@ -24,6 +24,7 @@ enum e_types { TYPE_CONST, /* keyword means a fix value - implies int type */ TYPE_BIN, /* raw binary data, length determined by data */ TYPE_BOOL, /* value is 0 or 1 (no-value is interpreted as 1) */ + TYPE_BOOL_NULL, /* value is 0 or 1 (no-value is interpreted as 1), or just opt= */ TYPE_BYTE, /* unsigned char */ TYPE_INT, /* int */ @@ -103,7 +104,7 @@ enum e_func { OFUNC_TERMIO, /* termio() ? */ OFUNC_SPEC, /* special, i.e. no generalizable function call */ OFUNC_OFFSET, /* put a value into xiofile struct; major is offset */ - OFUNC_OFFSET_MASKS, /* !!! */ + OFUNC_OFFSET_MASKS, /* set pos or neg bit pattern in array[2] */ /*OFUNC_APPL,*/ /* special, i.e. application must know which f. */ OFUNC_EXT, /* with extended file descriptors only */ OFUNC_TERMIOS_FLAG, /* a flag in struct termios: major..tcflag, minor..bit @@ -201,6 +202,7 @@ enum e_func { /* optcode's */ enum e_optcode { OPT_ADDRESS_FAMILY = 1, + OPT_AI_ADDRCONFIG, /* getaddrinfo() */ /* these are not alphabetically, I know... */ OPT_B0, /* termios.c_cflag */ OPT_B50, /* termios.c_cflag */ @@ -954,15 +956,7 @@ extern int retropt_ulong(struct opt *opts, int optcode, unsigned long *result); extern int retropt_flag(struct opt *opts, int optcode, flags_t *result); extern int retropt_string(struct opt *opts, int optcode, char **result); extern int retropt_timespec(struct opt *opts, int optcode, struct timespec *result); -extern int retropt_bind(struct opt *opts, - int af, - int socktype, - int ipproto, - struct sockaddr *sa, - socklen_t *salen, - int feats, /* TCP etc: 1..address allowed, - 3..address and port allowed */ - unsigned long res_opts0, unsigned long res_opts1); +extern int retropt_bind(struct opt *opts, int af, int socktype, int ipproto, struct sockaddr *sa, socklen_t *salen, int feats, const int ai_flags[2], const unsigned long res_opts[2]); extern int applyopts(int fd, struct opt *opts, enum e_phase phase); extern int applyopts2(int fd, struct opt *opts, unsigned int from, unsigned int to);