Mechanism for ai-* options; new option ai-addrconfig

This commit is contained in:
Gerhard Rieger 2023-11-05 13:56:58 +01:00
parent 8b2e0593f3
commit 4e00a345b4
28 changed files with 492 additions and 285 deletions

View file

@ -78,6 +78,12 @@ Features:
configure option --with-default-ipv allows to specify at build time if configure option --with-default-ipv allows to specify at build time if
IPv4, IPv6, or none of these is the preferred default. 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: Corrections:
When a sub process (EXEC, SYSTEM) terminated with exit code other than 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/ 0, its last sent data might have been lost depending on timing of read/

View file

@ -1 +1 @@
"1.7.4.5+" "1.7.4.5+conn-over"

View file

@ -218,10 +218,10 @@ label(option_W)dit(bf(tt(-W))tt(<lockfile>))
If lockfile exists, waits until it disappears. When lockfile does not exist, If lockfile exists, waits until it disappears. When lockfile does not exist,
creates it and continues, unlinks lockfile on exit. creates it and continues, unlinks lockfile on exit.
label(option_4)dit(bf(tt(-4))) 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. specify a version; this is the default.
label(option_6)dit(bf(tt(-6))) 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. specify a version.
label(option_statistics)dit(bf(tt(--statistics))) label(option_statistics)dit(bf(tt(--statistics)))
Logs transfer statistics (bytes and blocks counters for both directions) Logs transfer statistics (bytes and blocks counters for both directions)
@ -2240,6 +2240,11 @@ label(OPTOIN_IP_TRANSPARENT)
dit(bf(tt(ip-transparent))) dit(bf(tt(ip-transparent)))
Sets the IP_TRANSPARENT socket option. Sets the IP_TRANSPARENT socket option.
This option might require root privilege. 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_DEBUG)dit(bf(tt(res-debug)))
label(OPTION_RES_AAONLY)dit(bf(tt(res-aaonly))) label(OPTION_RES_AAONLY)dit(bf(tt(res-aaonly)))
label(OPTION_RES_USEVC)dit(bf(tt(res-usevc))) 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_DEFNAMES)dit(bf(tt(res-defnames)))
label(OPTION_RES_STAYOPEN)dit(bf(tt(res-stayopen))) label(OPTION_RES_STAYOPEN)dit(bf(tt(res-stayopen)))
label(OPTION_RES_DNSRCH)dit(bf(tt(res-dnsrch))) label(OPTION_RES_DNSRCH)dit(bf(tt(res-dnsrch)))
These options set the corresponding resolver (name resolution) option flags. These options temporarily set the corresponding resolver (name resolution)
Append "=0" to clear a default option. See man NOEXPAND(resolver(5)) for more option flags. Append "=0" to clear a default option. See man
information on these options. Note: these options are valid only for the NOEXPAND(resolver(5)) for more information on these options. These flags are
address they are applied to. per process, however socat() restores the old values after name resolution.
enddit() enddit()

View file

@ -1445,7 +1445,7 @@ struct hostent *Gethostbyname(const char *name) {
int Getaddrinfo(const char *node, const char *service, int Getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints, struct addrinfo **res) { const struct addrinfo *hints, struct addrinfo **res) {
int result; 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?"\"":"", node?"\"":"", node?node:"NULL", node?"\"":"",
service?"\"":"", service?service:"NULL", service?"\"":"", service?"\"":"", service?service:"NULL", service?"\"":"",
hints->ai_flags, hints->ai_family, hints->ai_socktype, hints->ai_flags, hints->ai_family, hints->ai_socktype,

217
test.sh
View file

@ -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)" 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)" TCP_MAXSEG="$($PROCAN -c |grep "^#define[[:space:]]*TCP_MAXSEG[[:space:]]" |cut -d' ' -f3)"
SIZE_T=$($PROCAN |grep size_t |awk '{print($3);}') 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 # SSL certificate contents
TESTCERT_CONF=testcert.conf TESTCERT_CONF=testcert.conf
@ -2089,8 +2090,20 @@ case "$TESTS" in
*%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*) *%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*)
TEST="$NAME: echo via connection to TCP V6 socket" TEST="$NAME: echo via connection to TCP V6 socket"
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
elif ! testfeats tcp ip6 >/dev/null || ! runsip6 >/dev/null; then elif ! F=$(testfeats IP6 TCP LISTEN STDIO PIPE); then
$PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N $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)) numCANT=$((numCANT+1))
listCANT="$listCANT $N" listCANT="$listCANT $N"
else else
@ -2101,27 +2114,36 @@ newport tcp6; tsl=$PORT
ts="[::1]:$tsl" ts="[::1]:$tsl"
da="test$N $(date) $RANDOM" da="test$N $(date) $RANDOM"
CMD1="$TRACE $SOCAT $opts TCP6-LISTEN:$tsl,$REUSEADDR PIPE" 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 printf "test $F_n $TEST... " $N
$CMD1 >"$tf" 2>"${te}1" & $CMD1 >"$tf" 2>"${te}1" &
pid=$! # background process id pid=$! # background process id
waittcp6port $tsl 1 waittcp6port $tsl 1
echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" echo "$da" |$CMD2 >>"$tf" 2>>"${te}2"
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
$PRINTF "$FAILED: $TRACE $SOCAT:\n" $PRINTF "$FAILED: $TRACE $SOCAT:\n"
echo "$CMD1 &" echo "$CMD1 &"
echo "$CMD2" cat "${te}1" >&2
cat "$te" echo "$CMD2"
numFAIL=$((numFAIL+1)) cat "${te}2" >&2
listFAIL="$listFAIL $N" numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED: diff:\n" $PRINTF "$FAILED: diff:\n"
cat "$tdiff" echo "$CMD1 &"
numFAIL=$((numFAIL+1)) cat "${te}1" >&2
listFAIL="$listFAIL $N" echo "$CMD2"
cat "${te}2" >&2
echo diff:
cat "$tdiff"
numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
else else
$PRINTF "$OK\n" $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)) numOK=$((numOK+1))
fi fi
kill $pid 2>/dev/null kill $pid 2>/dev/null
@ -2131,17 +2153,26 @@ N=$((N+1))
#set +vx #set +vx
# Test if TCP client with IPv4 address connects to IPv4 port
NAME=TCPX4 NAME=TCPX4
case "$TESTS" in case "$TESTS" in
*%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*) *%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*)
TEST="$NAME: echo via connection to TCP socket, v4 by target" TEST="$NAME: echo via connection to TCP socket, v4 by target"
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
elif ! testfeats tcp ip4 >/dev/null || ! runsip4 >/dev/null; then elif ! F=$(testfeats STDIO PIPE IP4 TCP LISTEN); then
$PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured${NORMAL}\n" $N
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
listCANT="$listCANT $N" listCANT="$listCANT $N"
elif ! testfeats ip6 >/dev/null || ! runsip6 >/dev/null; then elif ! A=$(testaddrs TCP TCP-LISTEN STDIN STDOUT PIPE); then
$PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N $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)) numCANT=$((numCANT+1))
listCANT="$listCANT $N" listCANT="$listCANT $N"
else else
@ -2151,29 +2182,39 @@ tdiff="$td/test$N.diff"
newport tcp4; tsl=$PORT newport tcp4; tsl=$PORT
ts="127.0.0.1:$tsl" ts="127.0.0.1:$tsl"
da="test$N $(date) $RANDOM" da="test$N $(date) $RANDOM"
CMD1="$TRACE $SOCAT $opts TCP-LISTEN:$tsl,pf=ip4,$REUSEADDR PIPE" CMD0="$TRACE $SOCAT $opts TCP-LISTEN:$tsl,pf=ip4,$REUSEADDR PIPE"
CMD2="$TRACE $SOCAT $opts STDIN!!STDOUT TCP:$ts" CMD1="$TRACE $SOCAT $opts STDIN!!STDOUT TCP:$ts"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
$CMD1 >"$tf" 2>"${te}1" & $CMD0 >"$tf" 2>"${te}0" &
pid=$! # background process id pid=$! # background process id
waittcp4port $tsl 1 waittcp4port $tsl 1
echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" echo "$da" |$CMD1 >>"$tf" 2>>"${te}1"
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
$PRINTF "$FAILED: $TRACE $SOCAT:\n" $PRINTF "$FAILED: $TRACE $SOCAT:\n"
echo "$CMD1 &" echo "$CMD0 &"
echo "$CMD2" cat "${te}0" >&2
cat "$te" echo "$CMD1"
numFAIL=$((numFAIL+1)) cat "${te}1" >&2
listFAIL="$listFAIL $N" numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
namesFAIL="$namesFAIL $NAME"
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED: diff:\n" $PRINTF "$FAILED: diff:\n"
cat "$tdiff" cat "$tdiff"
numFAIL=$((numFAIL+1)) echo "$CMD0 &"
listFAIL="$listFAIL $N" cat "${te}0" >&2
echo "$CMD1"
cat "${te}1" >&2
numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
namesFAIL="$namesFAIL $NAME"
else else
$PRINTF "$OK\n" $PRINTF "$OK\n"
if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi
numOK=$((numOK+1)) 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 fi
kill $pid 2>/dev/null kill $pid 2>/dev/null
fi fi
@ -2181,17 +2222,26 @@ esac
N=$((N+1)) N=$((N+1))
# Test if TCP client with IPv6 address connects to IPv6 port
NAME=TCPX6 NAME=TCPX6
case "$TESTS" in case "$TESTS" in
*%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*) *%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*)
TEST="$NAME: echo via connection to TCP socket, v6 by target" TEST="$NAME: echo via connection to TCP socket, v6 by target"
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
elif ! testfeats tcp ip4 >/dev/null || ! runsip4 >/dev/null; then elif ! F=$(testfeats STDIO PIPE IP6 TCP LISTEN); then
$PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured${NORMAL}\n" $N
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
listCANT="$listCANT $N" listCANT="$listCANT $N"
elif ! testfeats ip6 >/dev/null || ! runsip6 >/dev/null; then elif ! A=$(testaddrs TCP TCP-LISTEN STDIN STDOUT PIPE); then
$PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N $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)) numCANT=$((numCANT+1))
listCANT="$listCANT $N" listCANT="$listCANT $N"
else else
@ -2201,29 +2251,39 @@ tdiff="$td/test$N.diff"
newport tcp6; tsl=$PORT newport tcp6; tsl=$PORT
ts="[::1]:$tsl" ts="[::1]:$tsl"
da="test$N $(date) $RANDOM" da="test$N $(date) $RANDOM"
CMD1="$TRACE $SOCAT $opts TCP-LISTEN:$tsl,pf=ip6,$REUSEADDR PIPE" CMD0="$TRACE $SOCAT $opts TCP-LISTEN:$tsl,pf=ip6,$REUSEADDR PIPE"
CMD2="$TRACE $SOCAT $opts STDIN!!STDOUT TCP:$ts" CMD1="$TRACE $SOCAT $opts STDIN!!STDOUT TCP:$ts"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
$CMD1 >"$tf" 2>"${te}1" & $CMD0 >"$tf" 2>"${te}0" &
pid=$! # background process id pid=$! # background process id
waittcp6port $tsl 1 waittcp6port $tsl 1
echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" echo "$da" |$CMD1 >>"$tf" 2>>"${te}1"
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
$PRINTF "$FAILED: $TRACE $SOCAT:\n" $PRINTF "$FAILED: $TRACE $SOCAT:\n"
echo "$CMD1 &" echo "$CMD0 &"
echo "$CMD2" cat "${te}0" >&2
cat "$te" echo "$CMD1"
numFAIL=$((numFAIL+1)) cat "${te}1" >&2
listFAIL="$listFAIL $N" numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
namesFAIL="$namesFAIL $NAME"
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED: diff:\n" $PRINTF "$FAILED: diff:\n"
cat "$tdiff" cat "$tdiff"
numFAIL=$((numFAIL+1)) echo "$CMD0 &"
listFAIL="$listFAIL $N" cat "${te}0" >&2
echo "$CMD1"
cat "${te}1" >&2
numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
namesFAIL="$namesFAIL $NAME"
else else
$PRINTF "$OK\n" $PRINTF "$OK\n"
if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi
numOK=$((numOK+1)) 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 fi
kill $pid 2>/dev/null kill $pid 2>/dev/null
fi fi
@ -8298,7 +8358,7 @@ newport udp6; ts1p=$PORT
if1="$MCINTERFACE" if1="$MCINTERFACE"
ts1a="[::1]" ts1a="[::1]"
da="test$N $(date) $RANDOM" 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,bind=$ts1a"
CMD2="$TRACE $SOCAT -u $opts - UDP6-SENDTO:[ff02::2]:$ts1p" CMD2="$TRACE $SOCAT -u $opts - UDP6-SENDTO:[ff02::2]:$ts1p"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
@ -13589,7 +13649,7 @@ tf="$td/test$N.stdout"
te="$td/test$N.stderr" te="$td/test$N.stderr"
tdiff="$td/test$N.diff" tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM" 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 printf "test $F_n $TEST... " $N
$CMD0 >/dev/null 2>"${te}0" $CMD0 >/dev/null 2>"${te}0"
rc0=$? rc0=$?
@ -15177,7 +15237,7 @@ tf="$td/test$N.stdout"
te="$td/test$N.stderr" te="$td/test$N.stderr"
tdiff="$td/test$N.diff" tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM" 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" CMD1="$TRACE $SOCAT $opts -t 3 - $PROTO-SENDTO:$tsc"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
eval $CMD0 </dev/null 2>"${te}0" & eval $CMD0 </dev/null 2>"${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" 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" 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" 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" & $CMD0a >/dev/null 2>"${te}0a" &
pid0=$! pid0=$!
waittcp6port $PORT 1 waittcp6port $PORT 1
@ -16077,8 +16138,8 @@ TEST="$NAME: try all available TCP4 addresses"
# that is closed on both addresses. # that is closed on both addresses.
# The test succeeded when the log shows that Socat tried to connect two times. # The test succeeded when the log shows that Socat tried to connect two times.
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
elif [ -z "$FOREIGN" ]; then elif ! $(type nslookup >/dev/null 2>&1); then
$PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -foreign${NORMAL}\n" $N $PRINTF "test $F_n $TEST... ${YELLOW}nslookup not available${NORMAL}\n" $N
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
listCANT="$listCANT $N" listCANT="$listCANT $N"
#elif ! $(type nslookup >/dev/null 2>&1) && ! $(type host >/dev/null 2>&1); then #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 $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
listCANT="$listCANT $N" 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 else
tf="$td/test$N.stdout" tf="$td/test$N.stdout"
te="$td/test$N.stderr" 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 # $PRINTF "test $F_n $TEST... ${YELLOW}nslookup and host not available${NORMAL}\n" $N
# numCANT=$((numCANT+1)) # numCANT=$((numCANT+1))
# listCANT="$listCANT $N" # 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 $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available${NORMAL}\n" $N
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
listCANT="$listCANT $N" 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 $PRINTF "test $F_n $TEST... ${YELLOW}IPv6 not available or not routable${NORMAL}\n" $N
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
listCANT="$listCANT $N" 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 else
tf="$td/test$N.stdout" tf="$td/test$N.stdout"
te="$td/test$N.stderr" te="$td/test$N.stderr"
@ -16185,10 +16254,18 @@ tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM" da="test$N $(date) $RANDOM"
LOCALHOST_4_6=localhost-4-6.dest-unreach.net LOCALHOST_4_6=localhost-4-6.dest-unreach.net
if type nslookup >/dev/null 2>&1; then 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 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 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 while true; do
OPEN= OPEN=
for addr in $ADDRS; do for addr in $ADDRS; do
@ -16196,7 +16273,7 @@ while true; do
*.*) ;; *.*) ;;
*:*) addr="[$addr]" ; *:*) addr="[$addr]" ;
esac 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 :-( # port is open :-(
OPEN=1 OPEN=1
break break
@ -16207,7 +16284,7 @@ while true; do
fi fi
newport tcp4 newport tcp4
done 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 printf "test $F_n $TEST... " $N
$CMD >/dev/null 2>"${te}" $CMD >/dev/null 2>"${te}"
rc=$? 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 $PRINTF "test $F_n $TEST... ${YELLOW}Must be root${NORMAL}\n" $N
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
listCANT="$listCANT $N" listCANT="$listCANT $N"
elif ! $(type systemd-socket-activate >/dev/null 2>&1); then elif ! $(type nslookup >/dev/null 2>&1); then
$PRINTF "test $F_n $TEST... ${YELLOW}systemd-socket-activate not available${NORMAL}\n" $N $PRINTF "test $F_n $TEST... ${YELLOW}nslookup not available${NORMAL}\n" $N
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
listCANT="$listCANT $N" listCANT="$listCANT $N"
elif ! F=$(testfeats STDIO IP4 TCP PIPE); then 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 $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
listCANT="$listCANT $N" 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 elif [ -z "$FOREIGN" ]; then
$PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -foreign${NORMAL}\n" $N $PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -foreign${NORMAL}\n" $N
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))

View file

@ -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 }; 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 #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 #if WITH_RES_DEPRECATED
# define WITH_RES_AAONLY 1 # define WITH_RES_AAONLY 1
# define WITH_RES_PRIMARY 1 # define WITH_RES_PRIMARY 1
@ -153,8 +157,8 @@ unsigned long res_opts() {
*/ */
int xiogetaddrinfo(const char *node, const char *service, int xiogetaddrinfo(const char *node, const char *service,
int family, int socktype, int protocol, int family, int socktype, int protocol,
struct addrinfo **res, struct addrinfo **res, const int ai_flags[2],
unsigned long res_opts0, unsigned long res_opts1) { const unsigned long res_opts[2]) {
char *numnode = NULL; char *numnode = NULL;
size_t nodelen; size_t nodelen;
unsigned long save_res_opts = 0; unsigned long save_res_opts = 0;
@ -166,13 +170,13 @@ int xiogetaddrinfo(const char *node, const char *service,
int error_num; int error_num;
#if HAVE_RESOLV_H #if HAVE_RESOLV_H
if (res_opts0 | res_opts1) { if (res_opts[0] | res_opts[1]) {
if (!(_res.options & RES_INIT)) { if (!(_res.options & RES_INIT)) {
Res_init(); /*!!! returns -1 on error */ Res_init(); /*!!! returns -1 on error */
} }
save_res_opts = _res.options; save_res_opts = _res.options;
_res.options &= ~res_opts0; _res.options |= res_opts[0];
_res.options |= res_opts1; _res.options &= ~res_opts[1];
Debug2("changed _res.options from 0x%lx to 0x%lx", Debug2("changed _res.options from 0x%lx to 0x%lx",
save_res_opts, _res.options); 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]==']') { } else if (node && node[0] == '[' && node[(nodelen=strlen(node))-1]==']') {
if ((numnode = Malloc(nodelen-1)) == NULL) { if ((numnode = Malloc(nodelen-1)) == NULL) {
#if HAVE_RESOLV_H #if HAVE_RESOLV_H
if (res_opts0 | res_opts1) { if (res_opts[0] | res_opts[1]) {
_res.options = (_res.options & (~res_opts0&~res_opts1) | _res.options = save_res_opts;
save_res_opts& ( res_opts0| res_opts1));
} }
#endif #endif
return STAT_NORETRY; return STAT_NORETRY;
@ -219,12 +222,17 @@ int xiogetaddrinfo(const char *node, const char *service,
if (family == PF_UNSPEC) family = PF_INET6; if (family == PF_UNSPEC) family = PF_INET6;
#endif /* WITH_IP6 */ #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 HAVE_GETADDRINFO
if (node != NULL || service != NULL) { if (node != NULL || service != NULL) {
struct addrinfo *record; 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_family = family;
hints.ai_socktype = socktype; hints.ai_socktype = socktype;
hints.ai_protocol = protocol; hints.ai_protocol = protocol;
@ -256,7 +264,7 @@ int xiogetaddrinfo(const char *node, const char *service,
continue; continue;
} }
if ((error_num = Getaddrinfo(node, service, &hints, res)) != 0) { 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", node?node:"NULL", service?service:"NULL",
hints.ai_flags, hints.ai_family, hints.ai_flags, hints.ai_family,
hints.ai_socktype, hints.ai_protocol, hints.ai_socktype, hints.ai_protocol,
@ -265,9 +273,8 @@ int xiogetaddrinfo(const char *node, const char *service,
if (numnode) free(numnode); if (numnode) free(numnode);
#if HAVE_RESOLV_H #if HAVE_RESOLV_H
if (res_opts0 | res_opts1) { if (res_opts[0] | res_opts[1]) {
_res.options = (_res.options & (~res_opts0&~res_opts1) | _res.options = save_res_opts;
save_res_opts& ( res_opts0| res_opts1));
} }
#endif #endif
return STAT_RETRYLATER; return STAT_RETRYLATER;
@ -364,9 +371,8 @@ int xiogetaddrinfo(const char *node, const char *service,
h_errno == NETDB_INTERNAL ? strerror(errno) : h_errno == NETDB_INTERNAL ? strerror(errno) :
hstrerror(h_errno)); hstrerror(h_errno));
#if HAVE_RESOLV_H #if HAVE_RESOLV_H
if (res_opts0 | res_opts1) { if (res_opts[0] | res_opts[1]) {
_res.options = (_res.options & (~res_opts0&~res_opts1) | _res.options = save_res_opts;
save_res_opts& ( res_opts0| res_opts1));
} }
#endif #endif
return STAT_RETRYLATER; return STAT_RETRYLATER;
@ -399,9 +405,8 @@ int xiogetaddrinfo(const char *node, const char *service,
if (numnode) free(numnode); if (numnode) free(numnode);
#if HAVE_RESOLV_H #if HAVE_RESOLV_H
if (res_opts0 | res_opts1) { if (res_opts[0] | res_opts[1]) {
_res.options = (_res.options & (~res_opts0&~res_opts1) | _res.options = save_res_opts;
save_res_opts& ( res_opts0| res_opts1));
} }
#endif /* HAVE_RESOLV_H */ #endif /* HAVE_RESOLV_H */
return STAT_OK; return STAT_OK;
@ -423,12 +428,13 @@ void xiofreeaddrinfo(struct addrinfo *res) {
int xioresolve(const char *node, const char *service, int xioresolve(const char *node, const char *service,
int family, int socktype, int protocol, int family, int socktype, int protocol,
union sockaddr_union *addr, socklen_t *addrlen, 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; struct addrinfo *res = NULL;
int rc; int rc;
rc = xiogetaddrinfo(node, service, family, socktype, protocol, rc = xiogetaddrinfo(node, service, family, socktype, protocol,
&res, res_opts0, res_opts1); &res, ai_flags, res_opts);
if (rc != 0) { if (rc != 0) {
xiofreeaddrinfo(res); xiofreeaddrinfo(res);
return -1; return -1;
@ -760,12 +766,12 @@ mc:addr
union sockaddr_union sockaddr2; union sockaddr_union sockaddr2;
socklen_t socklen2 = sizeof(sockaddr2.ip4); socklen_t socklen2 = sizeof(sockaddr2.ip4);
/* first parameter is alway multicast address */ /* First parameter is always multicast address */
/*! result */ /*! result */
xioresolve(opt->value.u_string/*multiaddr*/, NULL, xioresolve(opt->value.u_string/*multiaddr*/, NULL,
xfd->para.socket.la.soa.sa_family, xfd->para.socket.la.soa.sa_family,
SOCK_DGRAM, IPPROTO_IP, SOCK_DGRAM, IPPROTO_IP, &sockaddr1, &socklen1,
&sockaddr1, &socklen1, 0, 0); xfd->para.socket.ip.ai_flags, xfd->para.socket.ip.res_opts);
ip4_mreqn.mreq.imr_multiaddr = sockaddr1.ip4.sin_addr; ip4_mreqn.mreq.imr_multiaddr = sockaddr1.ip4.sin_addr;
if (0) { if (0) {
; /* for canonical reasons */ ; /* for canonical reasons */
@ -774,9 +780,10 @@ mc:addr
/* three parameters */ /* three parameters */
/* second parameter is interface address */ /* second parameter is interface address */
xioresolve(opt->value2.u_string/*param2*/, NULL, xioresolve(opt->value2.u_string/*param2*/, NULL,
xfd->para.socket.la.soa.sa_family, xfd->para.socket.la.soa.sa_family,
SOCK_DGRAM, IPPROTO_IP, SOCK_DGRAM, IPPROTO_IP, &sockaddr2, &socklen2,
&sockaddr2, &socklen2, 0, 0); xfd->para.socket.ip.ai_flags,
xfd->para.socket.ip.res_opts);
ip4_mreqn.mreq.imr_interface = sockaddr2.ip4.sin_addr; ip4_mreqn.mreq.imr_interface = sockaddr2.ip4.sin_addr;
/* third parameter is interface */ /* third parameter is interface */
if (ifindex(opt->value3.u_string/*ifindex*/, if (ifindex(opt->value3.u_string/*ifindex*/,
@ -802,9 +809,11 @@ mc:addr
} else { } else {
/*! result */ /*! result */
xioresolve(opt->value2.u_string/*param2*/, NULL, xioresolve(opt->value2.u_string/*param2*/, NULL,
xfd->para.socket.la.soa.sa_family, xfd->para.socket.la.soa.sa_family,
SOCK_DGRAM, IPPROTO_IP, SOCK_DGRAM, IPPROTO_IP,
&sockaddr2, &socklen2, 0, 0); &sockaddr2, &socklen2,
xfd->para.socket.ip.ai_flags,
xfd->para.socket.ip.res_opts);
ip4_mreqn.mreq.imr_interface = sockaddr2.ip4.sin_addr; 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 */ /* first parameter is always multicast address */
rc = xioresolve(opt->value.u_string/*mcaddr*/, NULL, rc = xioresolve(opt->value.u_string/*mcaddr*/, NULL,
xfd->para.socket.la.soa.sa_family, xfd->para.socket.la.soa.sa_family,
SOCK_DGRAM, IPPROTO_IP, SOCK_DGRAM, IPPROTO_IP,
&sockaddr1, &socklen1, 0, 0); &sockaddr1, &socklen1, xfd->para.socket.ip.ai_flags,
xfd->para.socket.ip.res_opts);
if (rc < 0) { if (rc < 0) {
return -1; return -1;
} }
ip4_mreq_src.imr_multiaddr = sockaddr1.ip4.sin_addr; ip4_mreq_src.imr_multiaddr = sockaddr1.ip4.sin_addr;
/* second parameter is interface address */ /* second parameter is interface address */
rc = xioresolve(opt->value.u_string/*ifaddr*/, NULL, rc = xioresolve(opt->value.u_string/*ifaddr*/, NULL,
xfd->para.socket.la.soa.sa_family, xfd->para.socket.la.soa.sa_family,
SOCK_DGRAM, IPPROTO_IP, SOCK_DGRAM, IPPROTO_IP,
&sockaddr2, &socklen2, 0, 0); &sockaddr2, &socklen2, xfd->para.socket.ip.ai_flags,
xfd->para.socket.ip.res_opts);
if (rc < 0) { if (rc < 0) {
return -1; return -1;
} }
ip4_mreq_src.imr_interface = sockaddr2.ip4.sin_addr; ip4_mreq_src.imr_interface = sockaddr2.ip4.sin_addr;
/* third parameter is source address */ /* third parameter is source address */
rc = xioresolve(opt->value.u_string/*srcaddr*/, NULL, rc = xioresolve(opt->value.u_string/*srcaddr*/, NULL,
xfd->para.socket.la.soa.sa_family, xfd->para.socket.la.soa.sa_family,
SOCK_DGRAM, IPPROTO_IP, SOCK_DGRAM, IPPROTO_IP,
&sockaddr3, &socklen3, 0, 0); &sockaddr3, &socklen3, xfd->para.socket.ip.ai_flags,
xfd->para.socket.ip.res_opts);
if (rc < 0) { if (rc < 0) {
return -1; return -1;
} }

View file

@ -29,6 +29,8 @@ extern const struct optdesc opt_ip_recvdstaddr;
extern const struct optdesc opt_ip_recvif; extern const struct optdesc opt_ip_recvif;
extern const struct optdesc opt_ip_transparent; 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_debug;
extern const struct optdesc opt_res_aaonly; extern const struct optdesc opt_res_aaonly;
extern const struct optdesc opt_res_usevc; 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_stayopen;
extern const struct optdesc opt_res_dnsrch; 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 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 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 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); extern int xioapply_ip_add_membership(xiosingle_t *xfd, struct opt *opt);

View file

@ -14,7 +14,12 @@
#include "xio-ip4.h" #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 *netaddr_in = &range->netaddr.ip4.sin_addr;
struct in_addr *netmask_in = &range->netmask.ip4.sin_addr; struct in_addr *netmask_in = &range->netmask.ip4.sin_addr;
char *rangename1; /* a copy of rangename with writing allowed */ 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, ':')) { } else if (delimpos = strchr(rangename1, ':')) {
if ((rc = xioresolve(delimpos+1, NULL, PF_INET, 0, 0, if ((rc = xioresolve(delimpos+1, NULL, PF_INET, 0, 0,
&sau, &socklen, 0, 0)) &sau, &socklen, ai_flags, res_opts))
!= STAT_OK) { != STAT_OK) {
return rc; return rc;
} }
@ -59,7 +64,7 @@ int xioparsenetwork_ip4(const char *rangename, struct xiorange *range) {
{ {
*delimpos = 0; *delimpos = 0;
if ((rc = xioresolve(rangename1, NULL, PF_INET, 0, 0, if ((rc = xioresolve(rangename1, NULL, PF_INET, 0, 0,
&sau, &socklen, 0, 0)) &sau, &socklen, ai_flags, res_opts))
!= STAT_OK) { != STAT_OK) {
return rc; return rc;
} }

View file

@ -7,7 +7,7 @@
extern const struct optdesc opt_ip4_add_membership; 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 extern
int xiocheckrange_ip4(struct sockaddr_in *pa, struct xiorange *range); int xiocheckrange_ip4(struct sockaddr_in *pa, struct xiorange *range);
extern int extern int

View file

@ -82,7 +82,12 @@ const struct optdesc opt_ipv6_recvpathmtu = { "ipv6-recvpathmtu", "recvpathmtu",
/* Returns canonical form of IPv6 address. /* Returns canonical form of IPv6 address.
IPv6 address may bei enclose in brackets. IPv6 address may bei enclose in brackets.
Returns STAT_OK on success, STAT_NORETRY on failure. */ 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; union sockaddr_union sockaddr;
socklen_t sockaddrlen = sizeof(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'; plainaddr[INET6_ADDRSTRLEN-1] = '\0';
if ((clos = strchr(plainaddr, ']')) != NULL) if ((clos = strchr(plainaddr, ']')) != NULL)
*clos = '\0'; *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, if (xioresolve(src, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen,
0, 0) ai_flags, res_opts)
!= STAT_OK) { != STAT_OK) {
return STAT_NORETRY; return STAT_NORETRY;
} }
@ -105,7 +110,12 @@ int xioip6_pton(const char *src, struct in6_addr *dst) {
return STAT_OK; 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 */ char *delimpos; /* absolute address of delimiter */
size_t delimind; /* index of delimiter in string */ size_t delimind; /* index of delimiter in string */
unsigned int bits; /* netmask bits */ unsigned int bits; /* netmask bits */
@ -135,7 +145,7 @@ int xioparsenetwork_ip6(const char *rangename, struct xiorange *range) {
} }
baseaddr[delimind-2] = '\0'; baseaddr[delimind-2] = '\0';
if (xioresolve(baseaddr, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen, if (xioresolve(baseaddr, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen,
0, 0) ai_flags, res_opts)
!= STAT_OK) { != STAT_OK) {
return STAT_NORETRY; return STAT_NORETRY;
} }
@ -480,9 +490,12 @@ int xioapply_ipv6_join_group(
/* First parameter is multicast address */ /* First parameter is multicast address */
if ((res = if ((res =
xioresolve(opt->value.u_string/*multiaddr*/, NULL, xioresolve(opt->value.u_string/*multiaddr*/, NULL,
xfd->para.socket.la.soa.sa_family, xfd->para.socket.la.soa.sa_family,
SOCK_DGRAM, IPPROTO_IP, SOCK_DGRAM, IPPROTO_IP,
&sockaddr1, &socklen1, 0, 0)) != STAT_OK) { &sockaddr1, &socklen1,
xfd->para.socket.ip.ai_flags,
xfd->para.socket.ip.res_opts))
!= STAT_OK) {
return res; return res;
} }
ip6_mreq.ipv6mr_multiaddr = sockaddr1.ip6.sin6_addr; 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 */ /* First parameter is always multicast address */
if ((res = if ((res =
xioresolve(opt->value.u_string/*mcaddr*/, NULL, xioresolve(opt->value.u_string/*mcaddr*/, NULL,
xfd->para.socket.la.soa.sa_family, xfd->para.socket.la.soa.sa_family,
SOCK_DGRAM, IPPROTO_IP, SOCK_DGRAM, IPPROTO_IP, &sockaddr1, &socklen1,
&sockaddr1, &socklen1, 0, 0)) != STAT_OK) { xfd->para.socket.ip.ai_flags, xfd->para.socket.ip.res_opts))
!= STAT_OK) {
return res; return res;
} }
memcpy(&ip6_gsr.gsr_group, &sockaddr1.ip6, socklen1); 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 */ /* Third parameter is source address */
if ((res = if ((res =
xioresolve(opt->value3.u_string/*srcaddr*/, NULL, xioresolve(opt->value3.u_string/*srcaddr*/, NULL,
xfd->para.socket.la.soa.sa_family, xfd->para.socket.la.soa.sa_family,
SOCK_DGRAM, IPPROTO_IP, SOCK_DGRAM, IPPROTO_IP, &sockaddr2, &socklen2,
&sockaddr2, &socklen2, 0, 0)) != STAT_OK) { xfd->para.socket.ip.ai_flags, xfd->para.socket.ip.res_opts))
!= STAT_OK) {
return res; return res;
} }
memcpy(&ip6_gsr.gsr_source, &sockaddr2.ip6, socklen2); memcpy(&ip6_gsr.gsr_source, &sockaddr2.ip6, socklen2);

View file

@ -32,9 +32,8 @@ extern const struct optdesc opt_ipv6_tclass;
extern const struct optdesc opt_ipv6_recvtclass; extern const struct optdesc opt_ipv6_recvtclass;
extern const struct optdesc opt_ipv6_recvpathmtu; extern const struct optdesc opt_ipv6_recvpathmtu;
extern int xioip6_pton(const char *src, struct in6_addr *dst); extern int xioip6_pton(const char *src, struct in6_addr *dst, const int ai_flags[2], const unsigned long res_opts[2]);
extern extern int xioparsenetwork_ip6(const char *rangename, struct xiorange *range, const int ai_flags[2], const unsigned long res_opts[2]);
int xioparsenetwork_ip6(const char *rangename, struct xiorange *range);
extern int xiorange_ip6andmask(struct xiorange *range); extern int xiorange_ip6andmask(struct xiorange *range);
extern extern

View file

@ -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); Error2("%s: wrong number of parameters (%d instead of 2)", argv[0], argc-1);
} }
xioinit_ip(xfd, &pf);
xfd->howtoend = END_SHUTDOWN; xfd->howtoend = END_SHUTDOWN;
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; 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); retropt_bool(opts, OPT_FORK, &dofork);
if (_xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto, if (_xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto,
xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.ai_flags,
xfd->para.socket.ip.res_opts[0], xfd->para.socket.ip.res_opts,
&themlist, us, &uslen, &needbind, &lowport, &themlist, us, &uslen, &needbind, &lowport,
socktype) != STAT_OK) { socktype) != STAT_OK) {
return STAT_NORETRY; 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 OPT_PROTOCOL_FAMILY, OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT
*/ */
int int
_xioopen_ipapp_prepare(struct opt *opts, struct opt **opts0, _xioopen_ipapp_prepare(
const char *hostname, struct opt *opts,
const char *portname, struct opt **opts0,
int *pf, const char *hostname,
int protocol, const char *portname,
unsigned long res_opts0, unsigned long res_opts1, int *pf,
struct addrinfo **themlist, int protocol,
union sockaddr_union *us, socklen_t *uslen, const int ai_flags[2],
bool *needbind, bool *lowport, const unsigned long res_opts[2],
int socktype) { struct addrinfo **themlist,
union sockaddr_union *us,
socklen_t *uslen,
bool *needbind,
bool *lowport,
int socktype) {
uint16_t port; uint16_t port;
int result; int result;
@ -188,9 +194,7 @@ int
if ((result = if ((result =
xiogetaddrinfo(hostname, portname, xiogetaddrinfo(hostname, portname,
*pf, socktype, protocol, *pf, socktype, protocol,
themlist, themlist, ai_flags, res_opts))
res_opts0, res_opts1
))
!= STAT_OK) { != STAT_OK) {
return STAT_NORETRY; /*! STAT_RETRYLATER? */ return STAT_NORETRY; /*! STAT_RETRYLATER? */
} }
@ -200,7 +204,7 @@ int
/* 3 means: IP address AND port accepted */ /* 3 means: IP address AND port accepted */
if (retropt_bind(opts, (*pf!=PF_UNSPEC)?*pf:(*themlist)->ai_family, if (retropt_bind(opts, (*pf!=PF_UNSPEC)?*pf:(*themlist)->ai_family,
socktype, protocol, (struct sockaddr *)us, uslen, 3, socktype, protocol, (struct sockaddr *)us, uslen, 3,
res_opts0, res_opts1) ai_flags, res_opts)
!= STAT_NOACTION) { != STAT_NOACTION) {
*needbind = true; *needbind = true;
} else { } else {
@ -242,12 +246,18 @@ int
applies and consumes the following options: applies and consumes the following options:
OPT_PROTOCOL_FAMILY, OPT_BIND OPT_PROTOCOL_FAMILY, OPT_BIND
*/ */
int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0, int _xioopen_ipapp_listen_prepare(
const char *portname, int *pf, int ipproto, struct opt *opts,
unsigned long res_opts0, struct opt **opts0,
unsigned long res_opts1, const char *portname,
union sockaddr_union *us, socklen_t *uslen, int *pf,
int socktype) { 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; char *bindname = NULL;
int result; int result;
@ -256,8 +266,7 @@ int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0,
retropt_string(opts, OPT_BIND, &bindname); retropt_string(opts, OPT_BIND, &bindname);
result = result =
xioresolve(bindname, portname, *pf, socktype, ipproto, xioresolve(bindname, portname, *pf, socktype, ipproto,
us, uslen, us, uslen, ai_flags, res_opts);
res_opts0, res_opts1);
if (result != STAT_OK) { if (result != STAT_OK) {
/*! STAT_RETRY? */ /*! STAT_RETRY? */
return result; return result;
@ -270,7 +279,7 @@ int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0,
/* we expect the form: port */ /* we expect the form: port */
/* currently only used for TCP4 */ /* currently only used for TCP4 */
int xioopen_ipapp_listen(int argc, const char *argv[], struct opt *opts, 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, groups_t groups, int socktype,
int ipproto, int pf) { int ipproto, int pf) {
struct opt *opts0 = NULL; 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); Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1);
} }
xioinit_ip(&xfd->stream, &pf);
if (pf == PF_UNSPEC) { if (pf == PF_UNSPEC) {
#if WITH_IP4 && WITH_IP6 #if WITH_IP4 && WITH_IP6
switch (xioparms.default_ip) { switch (xioparms.default_ip) {
@ -296,22 +306,22 @@ int xioopen_ipapp_listen(int argc, const char *argv[], struct opt *opts,
#endif #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_INIT);
applyopts(-1, opts, PH_EARLY); applyopts(-1, opts, PH_EARLY);
if (_xioopen_ipapp_listen_prepare(opts, &opts0, argv[1], &pf, ipproto, if (_xioopen_ipapp_listen_prepare(opts, &opts0, argv[1], &pf, ipproto,
fd->stream.para.socket.ip.res_opts[1], xfd->stream.para.socket.ip.ai_flags,
fd->stream.para.socket.ip.res_opts[0], xfd->stream.para.socket.ip.res_opts,
us, &uslen, socktype) us, &uslen, socktype)
!= STAT_OK) { != STAT_OK) {
return STAT_NORETRY; return STAT_NORETRY;
} }
if ((result = if ((result =
xioopen_listen(&fd->stream, xioflags, xioopen_listen(&xfd->stream, xioflags,
(struct sockaddr *)us, uslen, (struct sockaddr *)us, uslen,
opts, opts0, pf, socktype, ipproto)) opts, opts0, pf, socktype, ipproto))
!= 0) != 0)

View file

@ -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, extern int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd,
groups_t groups, int socktype, groups_t groups, int socktype,
int ipproto, int protname); int ipproto, int protname);
extern int 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,
_xioopen_ipapp_prepare(struct opt *opts, struct opt **opts0, int socktype);
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_ip4app_connect(const char *hostname, const char *portname, extern int _xioopen_ip4app_connect(const char *hostname, const char *portname,
struct single *xfd, struct single *xfd,
int socktype, int ipproto, void *protname, 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, int xioflags, xiofile_t *fd,
groups_t groups, int socktype, groups_t groups, int socktype,
int ipproto, int protname); int ipproto, int protname);
extern int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0, 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);
const char *portname, int *pf, int ipproto,
unsigned long res_opts0,
unsigned long res_opts1,
union sockaddr_union *us, socklen_t *uslen,
int socktype);
#endif /* !defined(__xio_ipapp_h_included) */ #endif /* !defined(__xio_ipapp_h_included) */

View file

@ -199,7 +199,10 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
#if WITH_IP4 /*|| WITH_IP6*/ #if WITH_IP4 /*|| WITH_IP6*/
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { 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); free(rangename);
return STAT_NORETRY; return STAT_NORETRY;
} }

View file

@ -280,6 +280,7 @@ static int
return STAT_NORETRY; return STAT_NORETRY;
} }
xioinit_ip(xfd, &pf);
xfd->howtoend = END_SHUTDOWN; xfd->howtoend = END_SHUTDOWN;
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
@ -326,8 +327,8 @@ static int
result = result =
_xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto, _xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto,
xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.ai_flags,
xfd->para.socket.ip.res_opts[0], xfd->para.socket.ip.res_opts,
&themlist, us, &uslen, &themlist, us, &uslen,
&needbind, &lowport, socktype); &needbind, &lowport, socktype);
if (result != STAT_OK) return STAT_NORETRY; if (result != STAT_OK) return STAT_NORETRY;
@ -571,6 +572,7 @@ static int
return STAT_NORETRY; return STAT_NORETRY;
} }
xioinit_ip(xfd, &pf);
#if WITH_IP4 && WITH_IP6 #if WITH_IP4 && WITH_IP6
switch (xioparms.default_ip) { switch (xioparms.default_ip) {
case '4': pf = PF_INET; break; case '4': pf = PF_INET; break;
@ -610,8 +612,8 @@ static int
retropt_int(opts, OPT_SO_PROTOTYPE, &ipproto); retropt_int(opts, OPT_SO_PROTOTYPE, &ipproto);
if (_xioopen_ipapp_listen_prepare(opts, &opts0, portname, &pf, ipproto, if (_xioopen_ipapp_listen_prepare(opts, &opts0, portname, &pf, ipproto,
xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.ai_flags,
xfd->para.socket.ip.res_opts[0], xfd->para.socket.ip.res_opts,
us, &uslen, socktype) us, &uslen, socktype)
!= STAT_OK) { != STAT_OK) {
return STAT_NORETRY; return STAT_NORETRY;
@ -1894,7 +1896,8 @@ static int openssl_handle_peer_certificate(struct single *xfd,
case 16: /* IPv6 */ case 16: /* IPv6 */
inet_ntop(AF_INET6, data, aBuffer, sizeof(aBuffer)); inet_ntop(AF_INET6, data, aBuffer, sizeof(aBuffer));
if (peername != NULL) { 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) { if (memcmp(data, &ip6bin, sizeof(ip6bin)) == 0) {
Debug2("subjectAltName \"%s\" matches peername \"%s\"", Debug2("subjectAltName \"%s\" matches peername \"%s\"",
aBuffer, peername); aBuffer, peername);

View file

@ -110,6 +110,7 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
targetname = argv[2]; targetname = argv[2];
targetport = argv[3]; targetport = argv[3];
xioinit_ip(xfd, &pf);
xfd->howtoend = END_SHUTDOWN; xfd->howtoend = END_SHUTDOWN;
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT); 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; if (result != STAT_OK) return result;
result = result =
_xioopen_ipapp_prepare(opts, &opts0, proxyname, proxyport, _xioopen_ipapp_prepare(opts, &opts0, proxyname, proxyport,
&pf, ipproto, &pf, ipproto,
xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.ai_flags,
xfd->para.socket.ip.res_opts[0], xfd->para.socket.ip.res_opts,
&themlist, us, &uslen, &themlist, us, &uslen,
&needbind, &lowport, socktype); &needbind, &lowport, socktype);
if (result != STAT_OK) return result; 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, int _xioopen_proxy_prepare(
const char *targetname, const char *targetport) { 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; union sockaddr_union host;
socklen_t socklen = sizeof(host); socklen_t socklen = sizeof(host);
int rc; int rc;
@ -300,10 +308,10 @@ int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts,
if (proxyvars->doresolve) { if (proxyvars->doresolve) {
/* currently we only resolve to IPv4 addresses. This is in accordance to /* currently we only resolve to IPv4 addresses. This is in accordance to
RFC 2396; however once it becomes clear how IPv6 addresses should be 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/*!?*/, rc = xioresolve(targetname, targetport, PF_INET/*!?*/,
SOCK_STREAM, IPPROTO_TCP, SOCK_STREAM, IPPROTO_TCP,
&host, &socklen, 0, 0); &host, &socklen, ai_flags, res_opts);
if (rc != STAT_OK) { if (rc != STAT_OK) {
proxyvars->targetaddr = strdup(targetname); proxyvars->targetaddr = strdup(targetname);
} else { } else {

View file

@ -25,8 +25,7 @@ extern const struct optdesc opt_proxy_authorization_file;
extern const struct addrdesc xioaddr_proxy_connect; extern const struct addrdesc xioaddr_proxy_connect;
int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts, 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]);
const char *targetname, const char *targetport);
int _xioopen_proxy_connect(struct single *xfd, int _xioopen_proxy_connect(struct single *xfd,
struct proxyvars *proxyvars, struct proxyvars *proxyvars,
int level); int level);

View file

@ -73,6 +73,8 @@ int xioopen_rawip_sendto(int argc, const char *argv[], struct opt *opts,
argv[0], argc-1); argv[0], argc-1);
return STAT_NORETRY; return STAT_NORETRY;
} }
xioinit_ip(&xxfd->stream, &pf);
if ((result = _xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd, if ((result = _xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd,
groups, &pf)) != STAT_OK) { groups, &pf)) != STAT_OK) {
return result; return result;
@ -123,8 +125,8 @@ int _xioopen_rawip_sendto(const char *hostname, const char *protname,
if ((result = if ((result =
xioresolve(hostname, NULL, *pf, socktype, ipproto, xioresolve(hostname, NULL, *pf, socktype, ipproto,
&xfd->peersa, &xfd->salen, &xfd->peersa, &xfd->salen,
xfd->para.socket.ip.res_opts[0], xfd->para.socket.ip.ai_flags,
xfd->para.socket.ip.res_opts[1])) xfd->para.socket.ip.res_opts))
!= STAT_OK) { != STAT_OK) {
return result; return result;
} }
@ -137,8 +139,9 @@ int _xioopen_rawip_sendto(const char *hostname, const char *protname,
xfd->dtype = XIODATA_RECVFROM_SKIPIP; xfd->dtype = XIODATA_RECVFROM_SKIPIP;
if (retropt_bind(opts, *pf, socktype, ipproto, &us.soa, &uslen, feats, if (retropt_bind(opts, *pf, socktype, ipproto, &us.soa, &uslen, feats,
xfd->para.socket.ip.res_opts[0], xfd->para.socket.ip.ai_flags,
xfd->para.socket.ip.res_opts[1]) != STAT_NOACTION) { xfd->para.socket.ip.res_opts)
!= STAT_NOACTION) {
needbind = true; needbind = true;
} }
return return
@ -161,6 +164,8 @@ int xioopen_rawip_datagram(int argc, const char *argv[], struct opt *opts,
argv[0], argc-1); argv[0], argc-1);
return STAT_NORETRY; return STAT_NORETRY;
} }
xioinit_ip(xfd, &pf);
if ((result = if ((result =
_xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd, _xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd,
groups, &pf)) != STAT_OK) { 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 */ /* which reply packets will be accepted - determine by range option */
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { 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); free(rangename);
return STAT_NORETRY; return STAT_NORETRY;
} }
@ -212,6 +220,7 @@ int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts,
return STAT_NORETRY; return STAT_NORETRY;
} }
xioinit_ip(&xfd->stream, &pf);
if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) { if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) {
Error2("xioopen_rawip_recvfrom(\"%s\",,): protocol number exceeds 255 (%u)", Error2("xioopen_rawip_recvfrom(\"%s\",,): protocol number exceeds 255 (%u)",
protname, ipproto); 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, if (retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, 1,
xfd->stream.para.socket.ip.res_opts[0], xfd->stream.para.socket.ip.ai_flags,
xfd->stream.para.socket.ip.res_opts[1]) != STAT_NOACTION) { xfd->stream.para.socket.ip.res_opts)
!= STAT_NOACTION) {
needbind = true; needbind = true;
} }
@ -274,6 +284,7 @@ int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts,
return STAT_NORETRY; return STAT_NORETRY;
} }
xioinit_ip(&xfd->stream, &pf);
if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) { if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) {
Error2("xioopen_rawip_recv(\"%s\",,): protocol number exceeds 255 (%u)", Error2("xioopen_rawip_recv(\"%s\",,): protocol number exceeds 255 (%u)",
protname, ipproto); 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, if (retropt_bind(opts, pf, socktype, ipproto,
&/*us.soa*/xfd->stream.para.socket.la.soa, &uslen, 1, &/*us.soa*/xfd->stream.para.socket.la.soa, &uslen, 1,
xfd->stream.para.socket.ip.res_opts[0], xfd->stream.para.socket.ip.ai_flags,
xfd->stream.para.socket.ip.res_opts[1]) == xfd->stream.para.socket.ip.res_opts)
STAT_OK) { == STAT_OK) {
needbind = true; needbind = true;
} else { } else {
/* pf is required during xioread checks */ /* pf is required during xioread checks */

View file

@ -277,7 +277,7 @@ int xioopen_socket_connect(int argc, const char *argv[], struct opt *opts,
socket_init(0, &us); socket_init(0, &us);
if (retropt_bind(opts, 0 /*pf*/, socktype, proto, (struct sockaddr *)&us, &uslen, 3, 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) { != STAT_NOACTION) {
needbind = true; needbind = true;
us.soa.sa_family = pf; 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; xfd->dtype = XIOREAD_RECV|XIOWRITE_SENDTO;
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { 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); free(rangename);
return STAT_NORETRY; 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; xfd->para.socket.la.soa.sa_family = pf;
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { 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); free(rangename);
return STAT_NORETRY; 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 */ /* which reply sockets will accept - determine by range option */
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { 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); free(rangename);
return STAT_NORETRY; return STAT_NORETRY;
} }
@ -1169,7 +1178,10 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
/* for generic sockets, this has already been retrieved */ /* for generic sockets, this has already been retrieved */
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { 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); free(rangename);
return STAT_NORETRY; return STAT_NORETRY;
} }
@ -1371,7 +1383,10 @@ int _xioopen_dgram_recv(struct single *xfd, int xioflags,
#if WITH_IP4 /*|| WITH_IP6*/ #if WITH_IP4 /*|| WITH_IP6*/
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { 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); free(rangename);
return STAT_NORETRY; 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. */ /* 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; size_t addrlen = 0, masklen = 0;
int result; int result;
switch (pf) { switch (pf) {
#if WITH_IP4 #if WITH_IP4
case PF_INET: case PF_INET:
return xioparsenetwork_ip4(rangename, range); return xioparsenetwork_ip4(rangename, range, ai_flags, res_opts);
break; break;
#endif /* WITH_IP4 */ #endif /* WITH_IP4 */
#if WITH_IP6 #if WITH_IP6
case PF_INET6: case PF_INET6:
return xioparsenetwork_ip6(rangename, range); return xioparsenetwork_ip6(rangename, range, ai_flags, res_opts);
break; break;
#endif /* WITH_IP6 */ #endif /* WITH_IP6 */
case PF_UNSPEC: 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 /* 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. */ 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; 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); Error2("failed to parse or resolve range \"%s\" (pf=%d)", rangename, pf);
return -1; return -1;
} }

View file

@ -125,11 +125,8 @@ int xiocheckpeer(xiosingle_t *xfd,
extern extern
int xiosetsockaddrenv(const char *lr, union sockaddr_union *sau, socklen_t salen, int proto); int xiosetsockaddrenv(const char *lr, union sockaddr_union *sau, socklen_t salen, int proto);
extern extern int xioparsenetwork(const char *rangename, int pf, struct xiorange *range, const int ai_flags[2], const unsigned long res_opts[2]);
int xioparsenetwork(const char *rangename, int pf, extern int xioparserange(const char *rangename, int pf, struct xiorange *range, const int ai_flags[2], const unsigned long res_opts[2]);
struct xiorange *range);
extern
int xioparserange(const char *rangename, int pf, struct xiorange *range);
extern int extern int
xiosocket(struct opt *opts, int pf, int socktype, int proto, int level); xiosocket(struct opt *opts, int pf, int socktype, int proto, int level);

View file

@ -72,6 +72,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
targetname = argv[2]; targetname = argv[2];
targetport = argv[3]; targetport = argv[3];
xioinit_ip(xfd, &pf);
xfd->howtoend = END_SHUTDOWN; xfd->howtoend = END_SHUTDOWN;
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
@ -85,8 +86,8 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
result = result =
_xioopen_ipapp_prepare(opts, &opts0, sockdname, socksport, _xioopen_ipapp_prepare(opts, &opts0, sockdname, socksport,
&pf, ipproto, &pf, ipproto,
xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.ai_flags,
xfd->para.socket.ip.res_opts[0], xfd->para.socket.ip.res_opts,
&themlist, us, &uslen, &themlist, us, &uslen,
&needbind, &lowport, socktype); &needbind, &lowport, socktype);
@ -272,10 +273,10 @@ int
socklen_t saulen = sizeof(sau); socklen_t saulen = sizeof(sau);
if ((result = xioresolve(hostname, NULL, if ((result = xioresolve(hostname, NULL,
PF_INET, SOCK_STREAM, IPPROTO_TCP, PF_INET, SOCK_STREAM, IPPROTO_TCP,
&sau, &saulen, &sau, &saulen,
xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.ai_flags,
xfd->para.socket.ip.res_opts[0])) xfd->para.socket.ip.res_opts))
!= STAT_OK) { != STAT_OK) {
return result; /*! STAT_RETRY? */ return result; /*! STAT_RETRY? */
} }

View file

@ -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]); Error1("strdup(\"%s\"): out of memory", argv[1]);
return STAT_RETRYLATER; 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 */ /*! recover */
return result; return result;
} }

View file

@ -107,7 +107,10 @@ int _xioopen_ipdgram_listen(struct single *sfd,
#if WITH_IP4 /*|| WITH_IP6*/ #if WITH_IP4 /*|| WITH_IP6*/
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { 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); free(rangename);
return STAT_NORETRY; return STAT_NORETRY;
} }
@ -282,7 +285,7 @@ int _xioopen_ipdgram_listen(struct single *sfd,
/* we expect the form: port */ /* we expect the form: port */
int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, 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, groups_t groups, int pf, int ipproto,
int protname) { int protname) {
const char *portname = argv[1]; 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); Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1);
} }
xioinit_ip(&xfd->stream, &pf);
if (pf == PF_UNSPEC) { if (pf == PF_UNSPEC) {
#if WITH_IP4 && WITH_IP6 #if WITH_IP4 && WITH_IP6
switch (xioparms.default_ip) { 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_socket_pf(opts, &pf);
retropt_int(opts, OPT_SO_PROTOTYPE, &ipproto); 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); applyopts(-1, opts, PH_INIT);
uslen = socket_init(pf, &us); uslen = socket_init(pf, &us);
retropt_bind(opts, pf, socktype, ipproto, retropt_bind(opts, pf, socktype, ipproto,
(struct sockaddr *)&us, &uslen, 1, (struct sockaddr *)&us, &uslen, 1,
fd->stream.para.socket.ip.res_opts[1], xfd->stream.para.socket.ip.ai_flags,
fd->stream.para.socket.ip.res_opts[0]); xfd->stream.para.socket.ip.res_opts);
if (false) { 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); 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); opts, pf, socktype, ipproto);
} }
static static
int xioopen_udp_sendto(int argc, const char *argv[], struct opt *opts, 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 pf, int socktype, int ipproto) {
int result; int result;
@ -350,13 +354,14 @@ int xioopen_udp_sendto(int argc, const char *argv[], struct opt *opts,
return STAT_NORETRY; return STAT_NORETRY;
} }
xioinit_ip(&xfd->stream, &pf);
retropt_socket_pf(opts, &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)) groups, pf, socktype, ipproto))
!= STAT_OK) { != STAT_OK) {
return result; return result;
} }
_xio_openlate(&xxfd->stream, opts); _xio_openlate(&xfd->stream, opts);
return STAT_OK; return STAT_OK;
} }
@ -387,9 +392,9 @@ int _xioopen_udp_sendto(const char *hostname, const char *servname,
xfd->salen = sizeof(xfd->peersa); xfd->salen = sizeof(xfd->peersa);
if ((result = if ((result =
xioresolve(hostname, servname, pf, socktype, ipproto, xioresolve(hostname, servname, pf, socktype, ipproto,
&xfd->peersa, &xfd->salen, &xfd->peersa, &xfd->salen,
xfd->para.socket.ip.res_opts[0], xfd->para.socket.ip.ai_flags,
xfd->para.socket.ip.res_opts[1])) xfd->para.socket.ip.res_opts))
!= STAT_OK) { != STAT_OK) {
return result; return result;
} }
@ -398,8 +403,8 @@ int _xioopen_udp_sendto(const char *hostname, const char *servname,
} }
uslen = socket_init(pf, &us); uslen = socket_init(pf, &us);
if (retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, feats, if (retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, feats,
xfd->para.socket.ip.res_opts[0], xfd->para.socket.ip.ai_flags,
xfd->para.socket.ip.res_opts[1]) xfd->para.socket.ip.res_opts)
!= STAT_NOACTION) { != STAT_NOACTION) {
needbind = true; needbind = true;
} }
@ -446,6 +451,7 @@ int xioopen_udp_datagram(int argc, const char *argv[], struct opt *opts,
return STAT_NORETRY; return STAT_NORETRY;
} }
xioinit_ip(xfd, &pf);
if ((hostname = strdup(argv[1])) == NULL) { if ((hostname = strdup(argv[1])) == NULL) {
Error1("strdup(\"%s\"): out of memory", argv[1]); Error1("strdup(\"%s\"): out of memory", argv[1]);
return STAT_RETRYLATER; 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 */ /* which reply packets will be accepted - determine by range option */
if (retropt_string(opts, OPT_RANGE, &rangename) if (retropt_string(opts, OPT_RANGE, &rangename)
>= 0) { >= 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); free(rangename);
return STAT_NORETRY; return STAT_NORETRY;
} }
@ -506,6 +515,7 @@ int xioopen_udp_recvfrom(int argc, const char *argv[], struct opt *opts,
return STAT_NORETRY; return STAT_NORETRY;
} }
xioinit_ip(&xfd->stream, &pf);
xfd->stream.howtoend = END_NONE; xfd->stream.howtoend = END_NONE;
retropt_socket_pf(opts, &pf); retropt_socket_pf(opts, &pf);
if (pf == PF_UNSPEC) { if (pf == PF_UNSPEC) {
@ -523,9 +533,9 @@ int xioopen_udp_recvfrom(int argc, const char *argv[], struct opt *opts,
} }
if ((result = if ((result =
xioresolve(NULL, argv[1], pf, socktype, ipproto, xioresolve(NULL, argv[1], pf, socktype, ipproto, &us, &uslen,
&us, &uslen, xfd->stream.para.socket.ip.res_opts[0], xfd->stream.para.socket.ip.ai_flags,
xfd->stream.para.socket.ip.res_opts[1])) xfd->stream.para.socket.ip.res_opts))
!= STAT_OK) { != STAT_OK) {
return result; return result;
} }
@ -538,8 +548,8 @@ int xioopen_udp_recvfrom(int argc, const char *argv[], struct opt *opts,
socklen_t lalen = sizeof(la); socklen_t lalen = sizeof(la);
if (retropt_bind(opts, pf, socktype, ipproto, &la.soa, &lalen, 1, if (retropt_bind(opts, pf, socktype, ipproto, &la.soa, &lalen, 1,
xfd->stream.para.socket.ip.res_opts[0], xfd->stream.para.socket.ip.ai_flags,
xfd->stream.para.socket.ip.res_opts[1]) xfd->stream.para.socket.ip.res_opts)
!= STAT_NOACTION) { != STAT_NOACTION) {
switch (pf) { switch (pf) {
#if WITH_IP4 #if WITH_IP4
@ -584,6 +594,7 @@ int xioopen_udp_recv(int argc, const char *argv[], struct opt *opts,
return STAT_NORETRY; return STAT_NORETRY;
} }
xioinit_ip(&xfd->stream, &pf);
retropt_socket_pf(opts, &pf); retropt_socket_pf(opts, &pf);
if (pf == PF_UNSPEC) { if (pf == PF_UNSPEC) {
#if WITH_IP4 && WITH_IP6 #if WITH_IP4 && WITH_IP6
@ -600,9 +611,9 @@ int xioopen_udp_recv(int argc, const char *argv[], struct opt *opts,
} }
if ((result = if ((result =
xioresolve(NULL, argv[1], pf, socktype, ipproto, xioresolve(NULL, argv[1], pf, socktype, ipproto, &us, &uslen,
&us, &uslen, xfd->stream.para.socket.ip.res_opts[0], xfd->stream.para.socket.ip.ai_flags,
xfd->stream.para.socket.ip.res_opts[1])) xfd->stream.para.socket.ip.res_opts))
!= STAT_OK) { != STAT_OK) {
return result; 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, if (retropt_bind(opts, pf, socktype, ipproto,
&xfd->stream.para.socket.la.soa, &lalen, 1, &xfd->stream.para.socket.la.soa, &lalen, 1,
xfd->stream.para.socket.ip.res_opts[0], xfd->stream.para.socket.ip.ai_flags,
xfd->stream.para.socket.ip.res_opts[1]) xfd->stream.para.socket.ip.res_opts)
!= STAT_NOACTION) { != STAT_NOACTION) {
switch (pf) { switch (pf) {
#if WITH_IP4 #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 WITH_IP4 /*|| WITH_IP6*/
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { 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); free(rangename);
return STAT_NORETRY; return STAT_NORETRY;
} }

View file

@ -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); retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
} }
if (retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&us, &uslen, 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; needbind = true;
} }
@ -383,7 +384,8 @@ static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, i
xfd->dtype = XIODATA_RECVFROM; xfd->dtype = XIODATA_RECVFROM;
if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen, 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; needbind = true;
} }
@ -451,7 +453,8 @@ int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts,
#if 0 #if 0
if (retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&us, &uslen, 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 #endif
@ -531,7 +534,7 @@ int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts,
#if 0 #if 0
if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen, 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) { == STAT_OK) {
} }
#endif #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); retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
} }
if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen, 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) { != STAT_NOACTION) {
needbind = true; needbind = true;
} }

View file

@ -96,7 +96,8 @@ static int xioopen_vsock_connect(int argc, const char *argv[], struct opt *opts,
xiolog_vsock_cid(); xiolog_vsock_cid();
ret = retropt_bind(opts, pf, socktype, protocol, 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) if (ret == STAT_NORETRY)
return ret; return ret;
if (ret == STAT_OK) 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); opts0 = copyopts(opts, GROUP_ALL);
ret = retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&sa_bind, 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) if (ret == STAT_NORETRY)
return ret; return ret;
if (ret == STAT_OK) if (ret == STAT_OK)

3
xio.h
View file

@ -130,7 +130,8 @@ extern xioparms_t xioparms;
#if _WITH_IP4 || _WITH_IP6 #if _WITH_IP4 || _WITH_IP6
struct para_ip { 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] */ at [0], bits to be cleared are at [1] */
bool dosourceport; /* check the source port of incoming connection or packets */ bool dosourceport; /* check the source port of incoming connection or packets */
uint16_t sourceport; /* host byte order */ uint16_t sourceport; /* host byte order */

View file

@ -172,6 +172,12 @@ const struct optname optionnames[] = {
#endif #endif
#if defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP) #if defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP)
IF_IP ("add-source-membership", &opt_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 #endif
IF_INTERFACE("allmulti", &opt_iff_allmulti) IF_INTERFACE("allmulti", &opt_iff_allmulti)
#if WITH_LIBWRAP && defined(HAVE_HOSTS_ALLOW_TABLE) #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'; *buffp = '\0';
if (xioresolve(buff, NULL, AF_INET, SOCK_DGRAM, IPPROTO_IP, if (xioresolve(buff, NULL, AF_INET, SOCK_DGRAM, IPPROTO_IP,
(union sockaddr_union *)&sa, &salen, (union sockaddr_union *)&sa, &salen, NULL,
0, 0/*!!!*/) != STAT_OK) { NULL/*!! !*/) != STAT_OK) {
opt->desc = ODESC_ERROR; continue; opt->desc = ODESC_ERROR; continue;
} }
opt->value.u_ip4addr = sa.sin_addr; opt->value.u_ip4addr = sa.sin_addr;
@ -3109,7 +3115,8 @@ int retropt_bind(struct opt *opts,
UNIX (or'd): 1..tight UNIX (or'd): 1..tight
2..abstract 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 portsep[] = ":";
const char *ends[] = { portsep, NULL }; const char *ends[] = { portsep, NULL };
const char *nests[] = { "[", "]", NULL }; const char *nests[] = { "[", "]", NULL };
@ -3175,9 +3182,9 @@ int retropt_bind(struct opt *opts,
} }
if ((result = if ((result =
xioresolve(hostname[0]!='\0'?hostname:NULL, portp, xioresolve(hostname[0]!='\0'?hostname:NULL, portp,
af, socktype, ipproto, af, socktype, ipproto,
(union sockaddr_union *)sa, salen, (union sockaddr_union *)sa, salen,
res_opts0, res_opts1)) ai_flags, res_opts))
!= STAT_OK) { != STAT_OK) {
Error("error resolving bind option"); Error("error resolving bind option");
return STAT_NORETRY; return STAT_NORETRY;
@ -4070,6 +4077,10 @@ int applyopts_single(struct single *xfd, struct opt *opts, enum e_phase phase) {
break; break;
case OFUNC_OFFSET_MASKS: 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; void *masks = (char *)xfd + opt->desc->major;
size_t masksize = opt->desc->minor; 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; ((uint32_t *)masks)[1] |= bit;
} }
break; break;
case sizeof(uint64_t):
if (opt->value.u_bool) {
((uint64_t *)masks)[0] |= bit;
} else {
((uint64_t *)masks)[1] |= bit;
}
break;
default: default:
Info1("sizeof(uint32_t)="F_Zu, sizeof(uint32_t));
Error1("applyopts_single: masksize "F_Zu" not implemented", Error1("applyopts_single: masksize "F_Zu" not implemented",
masksize); masksize);
} }

View file

@ -24,6 +24,7 @@ enum e_types {
TYPE_CONST, /* keyword means a fix value - implies int type */ TYPE_CONST, /* keyword means a fix value - implies int type */
TYPE_BIN, /* raw binary data, length determined by data */ TYPE_BIN, /* raw binary data, length determined by data */
TYPE_BOOL, /* value is 0 or 1 (no-value is interpreted as 1) */ 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_BYTE, /* unsigned char */
TYPE_INT, /* int */ TYPE_INT, /* int */
@ -103,7 +104,7 @@ enum e_func {
OFUNC_TERMIO, /* termio() ? */ OFUNC_TERMIO, /* termio() ? */
OFUNC_SPEC, /* special, i.e. no generalizable function call */ OFUNC_SPEC, /* special, i.e. no generalizable function call */
OFUNC_OFFSET, /* put a value into xiofile struct; major is offset */ 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_APPL,*/ /* special, i.e. application must know which f. */
OFUNC_EXT, /* with extended file descriptors only */ OFUNC_EXT, /* with extended file descriptors only */
OFUNC_TERMIOS_FLAG, /* a flag in struct termios: major..tcflag, minor..bit OFUNC_TERMIOS_FLAG, /* a flag in struct termios: major..tcflag, minor..bit
@ -201,6 +202,7 @@ enum e_func {
/* optcode's */ /* optcode's */
enum e_optcode { enum e_optcode {
OPT_ADDRESS_FAMILY = 1, OPT_ADDRESS_FAMILY = 1,
OPT_AI_ADDRCONFIG, /* getaddrinfo() */
/* these are not alphabetically, I know... */ /* these are not alphabetically, I know... */
OPT_B0, /* termios.c_cflag */ OPT_B0, /* termios.c_cflag */
OPT_B50, /* 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_flag(struct opt *opts, int optcode, flags_t *result);
extern int retropt_string(struct opt *opts, int optcode, char **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_timespec(struct opt *opts, int optcode, struct timespec *result);
extern int retropt_bind(struct opt *opts, 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]);
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 applyopts(int fd, struct opt *opts, enum e_phase phase); extern int applyopts(int fd, struct opt *opts, enum e_phase phase);
extern int applyopts2(int fd, struct opt *opts, unsigned int from, extern int applyopts2(int fd, struct opt *opts, unsigned int from,
unsigned int to); unsigned int to);