mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 07:22:34 +00:00
Reworked domain name resolution, centralized IPv4/IPv6 sorting
This commit is contained in:
parent
127280088c
commit
ec0e1ca20c
10 changed files with 258 additions and 183 deletions
2
CHANGES
2
CHANGES
|
@ -46,6 +46,8 @@ Corrections:
|
|||
Thanks to Heinrich Schuchardt from Canonical for reporting and sending
|
||||
a patch.
|
||||
|
||||
Reworked domain name resolution, centralized IPv4/IPv6 sorting.
|
||||
|
||||
Features:
|
||||
Total inactivity timeout option -T 0 now means 0.0 seconds; up to
|
||||
version 1.8.0.0 it meant no total inactivity timeout.
|
||||
|
|
89
test.sh
89
test.sh
|
@ -4969,6 +4969,7 @@ EOF
|
|||
|
||||
#0 if ! sed 's/.*\r//g' "$tpo" |diff -q "$tr" - >/dev/null 2>&1; then
|
||||
#0 if ! sed 's/.*'"$($ECHO '\r\c')"'/</g' "$tpo" |diff -q "$tr" - >/dev/null 2>&1; then
|
||||
kill $pid 2>/dev/null # necc on OpenBSD
|
||||
wait
|
||||
if ! tr "$($ECHO '\r \c')" "% " <$tpo |sed 's/%$//g' |sed 's/.*%//g' |diff "$tr" - >"$tdiff" 2>&1; then
|
||||
$PRINTF "$FAILED: $TRACE $SOCAT:\n"
|
||||
|
@ -4985,7 +4986,6 @@ else
|
|||
numOK=$((numOK+1))
|
||||
listOK="$listOK $N"
|
||||
fi
|
||||
kill $pid 2>/dev/null # necc on OpenBSD
|
||||
wait
|
||||
MICROS=$SAVEMICS
|
||||
TERM="$SAVETERM"
|
||||
|
@ -19339,7 +19339,7 @@ elif ! cond=$(checkconds \
|
|||
"" \
|
||||
"" \
|
||||
"" \
|
||||
"IP4 TCP LISTEN STDIO UNIX" \
|
||||
"IP4 TCP LISTEN STDIO UNIX SOCKS4" \
|
||||
"TCP4-LISTEN PIPE STDIN STDOUT TCP4 UNIX UNIX-LISTEN" \
|
||||
"so-reuseaddr" \
|
||||
"tcp4 unix" ); then
|
||||
|
@ -20234,7 +20234,7 @@ else
|
|||
rc0=$?
|
||||
if [ "$rc0" -ne 0 ]; then
|
||||
$PRINTF "$FAILED (rc0=$rc0)\n"
|
||||
echo "$CMD0 &"
|
||||
echo "$CMD0"
|
||||
cat "${te}0" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
|
@ -20257,6 +20257,89 @@ UDPLITE-SENDTO udplite4 PORT
|
|||
IP-SENDTO ip4 PROTO
|
||||
"
|
||||
|
||||
# Test if CONNECT to a server name that resolves to IPv6 first and IPv4
|
||||
# as second address, when binding to an IPv4 address, uses IPv4
|
||||
# This failed in Socat 1.8.0.0
|
||||
while read ADDR protov IPPORT _; do
|
||||
if [ -z "$ADDR" ] || [[ "$ADDR" == \#* ]]; then continue; fi
|
||||
FEATS=
|
||||
ADDR_="$(echo $ADDR |tr - _)" # TCP_CONNECT
|
||||
PROTO="${ADDR%%[-:]*}" # TCP
|
||||
proto=$(tolower $PROTO) # tcp
|
||||
FEATS="$FEATS $PROTO"
|
||||
NAME="$(echo "V1800_${ADDR_}_CONNECT_6_4" |sed 's/:[.0-8]*//')"
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%bugs%*|*%ip4%*|*%$protov%*|*%$proto%*|*%socket%*|*%$NAME%*)
|
||||
TEST="$NAME: test regression of $ADDR with IPv6,4 and binding to IPv4"
|
||||
# Run an appropriate server address in background.
|
||||
# Start a CONNECT command to (internal) test name localhost-6-4.dest-unreach.net
|
||||
# and bind to an IPv4 address, connect, terminate immediately.
|
||||
# When no error occurs the test succeeded.
|
||||
if ! eval $NUMCOND; then :
|
||||
elif ! cond=$(checkconds \
|
||||
"" \
|
||||
"" \
|
||||
"" \
|
||||
"$FEATS DEVTESTS IP4" \
|
||||
"$ADDR GOPEN" \
|
||||
"bind" \
|
||||
"$protov" ); then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}$cond${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
namesCANT="$namesCANT $NAME"
|
||||
else
|
||||
tf="$td/test$N.stdout"
|
||||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
da="test$N $(date) $RANDOM"
|
||||
case X$IPPORT in
|
||||
XPORT) newport $(tolower $PROTO); _PORT=$PORT ;;
|
||||
XPROTO) echo "IPPROTO=\"$IPPROTO\""
|
||||
_PORT=$IPPROTO ;;
|
||||
esac
|
||||
CMD0="$TRACE $SOCAT $opts ${ADDR%%-*}-LISTEN:$_PORT,pf=ip4 PIPE"
|
||||
CMD1="$TRACE $SOCAT $opts /dev/null $ADDR:localhost-6-4.dest-unreach.net:$_PORT,bind=127.0.0.1"
|
||||
printf "test $F_n $TEST... " $N
|
||||
$CMD0 2>"${te}0" </dev/null &
|
||||
pid0=$!
|
||||
wait${protov}port $PORT 1
|
||||
$CMD1 2>"${te}1" </dev/null
|
||||
rc1=$?
|
||||
kill $pid0 2>/dev/null; wait
|
||||
if [ "$rc1" -ne 0 ]; then
|
||||
$PRINTF "$FAILED (rc1=$rc1)\n"
|
||||
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 [ "$VERBOSE" ]; then echo "$CMD0 &"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}0" >&2; fi
|
||||
numOK=$((numOK+1))
|
||||
listOK="$listOK $N"
|
||||
fi
|
||||
fi # NUMCOND
|
||||
;;
|
||||
esac
|
||||
PORT=$((PORT+1))
|
||||
N=$((N+1))
|
||||
done <<<"
|
||||
TCP-CONNECT tcp4 PORT
|
||||
SCTP-CONNECT sctp4 PORT
|
||||
DCCP-CONNECT dccp4 PORT
|
||||
#PENSSL tcp4 PORT
|
||||
#OCKS4:127.0.0.1 tcp4 PORT
|
||||
#OCKS4A:127.0.0.1 tcp4 PORT
|
||||
#OCKS5:127.0.0.1:1080 tcp4 PORT
|
||||
#ROXY::127.0.0.1 tcp4 PORT
|
||||
"
|
||||
|
||||
|
||||
# end of common tests
|
||||
|
||||
##################################################################################
|
||||
|
|
130
xio-ip.c
130
xio-ip.c
|
@ -363,7 +363,7 @@ static int xioip_freeaddrinfo_devtests(
|
|||
#endif /* WITH_DEVTESTS */
|
||||
|
||||
|
||||
/* the ultimate(?) socat resolver function
|
||||
/* A socat resolver function
|
||||
node: the address to be resolved; supported forms:
|
||||
1.2.3.4 (IPv4 address)
|
||||
[::2] (IPv6 address)
|
||||
|
@ -376,7 +376,7 @@ static int xioip_freeaddrinfo_devtests(
|
|||
res: a pointer to an uninitialized ptr var for the resulting socket address
|
||||
returns: STAT_OK, STAT_RETRYLATER, STAT_NORETRY, prints message
|
||||
*/
|
||||
int xiogetaddrinfo(const char *node, const char *service,
|
||||
int _xiogetaddrinfo(const char *node, const char *service,
|
||||
int family, int socktype, int protocol,
|
||||
struct addrinfo **res, const int ai_flags[2]) {
|
||||
char *numnode = NULL;
|
||||
|
@ -388,11 +388,11 @@ int xiogetaddrinfo(const char *node, const char *service,
|
|||
#endif
|
||||
int error_num;
|
||||
|
||||
Debug8("xiogetaddrinfo(node=\"%s\", service=\"%s\", family=%d, socktype=%d, protoco=%d, ai_flags={0x%04x/0x%04x} }, res=%p",
|
||||
Debug8("_xiogetaddrinfo(node=\"%s\", service=\"%s\", family=%d, socktype=%d, protoco=%d, ai_flags={0x%04x/0x%04x} }, res=%p",
|
||||
node?node:"NULL", service?service:"NULL", family, socktype, protocol,
|
||||
ai_flags?ai_flags[0]:0, ai_flags?ai_flags[1]:0, res);
|
||||
if (service && service[0]=='\0') {
|
||||
Error("xiogetaddrinfo(): empty port and service");
|
||||
Error("_xiogetaddrinfo(): empty port and service");
|
||||
return EAI_NONAME;
|
||||
}
|
||||
|
||||
|
@ -620,7 +620,7 @@ int xiogetaddrinfo(const char *node, const char *service,
|
|||
return STAT_RETRYLATER;
|
||||
}
|
||||
if (host->h_addrtype != family) {
|
||||
Error2("xiogetaddrinfo(): \"%s\" does not resolve to %s",
|
||||
Error2("_xiogetaddrinfo(): \"%s\" does not resolve to %s",
|
||||
node, family==PF_INET?"IP4":"IP6");
|
||||
} else {
|
||||
switch (family) {
|
||||
|
@ -653,7 +653,97 @@ int xiogetaddrinfo(const char *node, const char *service,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void xiofreeaddrinfo(struct addrinfo *res) {
|
||||
/* Sort the records of an addrinfo list themp (as returned by getaddrinfo),
|
||||
return the sorted list in the array ai_sorted (takes at most n entries
|
||||
including the terminating NULL)
|
||||
Returns 0 on success. */
|
||||
int _xio_sort_ip_addresses(
|
||||
struct addrinfo *themlist,
|
||||
struct addrinfo **ai_sorted)
|
||||
{
|
||||
struct addrinfo *themp;
|
||||
int i;
|
||||
int ipv[3];
|
||||
int ipi = 0;
|
||||
|
||||
/* Make a simple array of IP version preferences */
|
||||
switch (xioparms.preferred_ip) {
|
||||
case '0':
|
||||
ipv[0] = PF_UNSPEC;
|
||||
ipv[1] = -1;
|
||||
break;
|
||||
case '4':
|
||||
ipv[0] = PF_INET;
|
||||
ipv[1] = PF_INET6;
|
||||
ipv[2] = -1;
|
||||
break;
|
||||
case '6':
|
||||
ipv[0] = PF_INET6;
|
||||
ipv[1] = PF_INET;
|
||||
ipv[2] = -1;
|
||||
break;
|
||||
default:
|
||||
Error("INTERNAL: undefined preferred_ip value");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create the sorted list */
|
||||
ipi = 0;
|
||||
i = 0;
|
||||
while (ipv[ipi] >= 0) {
|
||||
themp = themlist;
|
||||
while (themp != NULL) {
|
||||
if (ipv[ipi] == PF_UNSPEC) {
|
||||
ai_sorted[i] = themp;
|
||||
++i;
|
||||
} else if (ipv[ipi] == themp->ai_family) {
|
||||
ai_sorted[i] = themp;
|
||||
++i;
|
||||
}
|
||||
themp = themp->ai_next;
|
||||
}
|
||||
++ipi;
|
||||
}
|
||||
ai_sorted[i] = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Wrapper around _xiogetaddrinfo() (which is a wrapper arount getaddrinfo())
|
||||
that sorts the results according to xioparms.preferred_ip when family is
|
||||
AF_UNSPEC; it returns an array of record pointers instead of a list! */
|
||||
int xiogetaddrinfo(const char *node, const char *service,
|
||||
int family, int socktype, int protocol,
|
||||
struct addrinfo ***ai_sorted, const int ai_flags[2]) {
|
||||
struct addrinfo *res;
|
||||
struct addrinfo **_ai_sorted;
|
||||
struct addrinfo *aip;
|
||||
int ain;
|
||||
int rc;
|
||||
|
||||
rc = _xiogetaddrinfo(node, service, family, socktype, protocol, &res,
|
||||
ai_flags);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
/* Sort results - first, count records for mem allocation */
|
||||
aip = res;
|
||||
ain = 0;
|
||||
while (aip != NULL) {
|
||||
++ain;
|
||||
aip = aip->ai_next;
|
||||
}
|
||||
_ai_sorted = Calloc((ain+2), sizeof(struct addrinfo *));
|
||||
if (_ai_sorted == NULL)
|
||||
return STAT_RETRYLATER;
|
||||
|
||||
/* Generate a list of addresses sorted by preferred ip version */
|
||||
_xio_sort_ip_addresses(res, _ai_sorted);
|
||||
_ai_sorted[ain+1] = res; /* save list past NULL for later freeing */
|
||||
*ai_sorted = _ai_sorted;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _xiofreeaddrinfo(struct addrinfo *res) {
|
||||
#if WITH_DEVTESTS
|
||||
if (!xioip_freeaddrinfo_devtests(res)) {
|
||||
return;
|
||||
|
@ -666,6 +756,20 @@ void xiofreeaddrinfo(struct addrinfo *res) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void xiofreeaddrinfo(struct addrinfo **ai_sorted) {
|
||||
int ain;
|
||||
struct addrinfo *res;
|
||||
|
||||
/* Find the original *res from getaddrinfo past NULL */
|
||||
ain = 0;
|
||||
while (ai_sorted[ain] != NULL)
|
||||
++ain;
|
||||
res = ai_sorted[ain+1];
|
||||
_xiofreeaddrinfo(res);
|
||||
free(ai_sorted);
|
||||
}
|
||||
|
||||
|
||||
/* A simple resolver interface that just returns one address,
|
||||
the first found by calling xiogetaddrinfo(), but ev.respects preferred_ip;
|
||||
pf may be AF_INET, AF_INET6, or AF_UNSPEC;
|
||||
|
@ -677,7 +781,7 @@ int xioresolve(const char *node, const char *service,
|
|||
union sockaddr_union *addr, socklen_t *addrlen,
|
||||
const int ai_flags[2])
|
||||
{
|
||||
struct addrinfo *res = NULL;
|
||||
struct addrinfo **res = NULL;
|
||||
struct addrinfo *aip;
|
||||
int rc;
|
||||
|
||||
|
@ -699,17 +803,17 @@ int xioresolve(const char *node, const char *service,
|
|||
xiofreeaddrinfo(res);
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
if (res->ai_addrlen > *addrlen) {
|
||||
if ((*res)->ai_addrlen > *addrlen) {
|
||||
Error3("xioresolve(node=\"%s\", addrlen="F_socklen", ...): "F_socklen" bytes required",
|
||||
node, *addrlen, res->ai_addrlen);
|
||||
node, *addrlen, (*res)->ai_addrlen);
|
||||
xiofreeaddrinfo(res);
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
if (res->ai_next != NULL) {
|
||||
if ((*res)->ai_next != NULL) {
|
||||
Info4("xioresolve(node=\"%s\", service=%s%s%s, ...): More than one address found", node?node:"NULL", service?"\"":"", service?service:"NULL", service?"\"":"");
|
||||
}
|
||||
|
||||
aip = res;
|
||||
aip = *res;
|
||||
if (ai_flags != NULL && ai_flags[0] & AI_PASSIVE && pf == PF_UNSPEC) {
|
||||
/* We select the first IPv6 address, if available,
|
||||
because this might accept IPv4 connections too */
|
||||
|
@ -719,7 +823,7 @@ int xioresolve(const char *node, const char *service,
|
|||
aip = aip->ai_next;
|
||||
}
|
||||
if (aip == NULL)
|
||||
aip = res;
|
||||
aip = *res;
|
||||
} else if (pf == PF_UNSPEC && xioparms.preferred_ip != '0') {
|
||||
int prefip = PF_UNSPEC;
|
||||
xioinit_ip(&prefip, xioparms.preferred_ip);
|
||||
|
@ -729,7 +833,7 @@ int xioresolve(const char *node, const char *service,
|
|||
aip = aip->ai_next;
|
||||
}
|
||||
if (aip == NULL)
|
||||
aip = res;
|
||||
aip = *res;
|
||||
}
|
||||
|
||||
memcpy(addr, aip->ai_addr, aip->ai_addrlen);
|
||||
|
|
5
xio-ip.h
5
xio-ip.h
|
@ -49,8 +49,9 @@ extern const struct optdesc opt_res_nsaddr;
|
|||
|
||||
extern int xioinit_ip(int *pf, char ipv);
|
||||
|
||||
extern int xiogetaddrinfo(const char *node, const char *service, int family, int socktype, int protocol, struct addrinfo **res, const int ai_flags[2]);
|
||||
extern void xiofreeaddrinfo(struct addrinfo *res);
|
||||
extern int xiogetaddrinfo(const char *node, const char *service, int family, int socktype, int protocol, struct addrinfo ***ai_sorted, const int ai_flags[2]);
|
||||
extern void xiofreeaddrinfo(struct addrinfo **ai_sorted);
|
||||
extern int _xio_sort_ip_addresses(struct addrinfo *themlist, struct addrinfo **ai_sorted);
|
||||
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]);
|
||||
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);
|
||||
|
|
101
xio-ipapp.c
101
xio-ipapp.c
|
@ -39,12 +39,11 @@ int xioopen_ipapp_connect(
|
|||
int maxchildren = 0;
|
||||
union sockaddr_union us_sa, *us = &us_sa;
|
||||
socklen_t uslen = sizeof(us_sa);
|
||||
struct addrinfo *themlist, *themp;
|
||||
struct addrinfo **themarr, *themp;
|
||||
char infobuff[256];
|
||||
bool needbind = false;
|
||||
bool lowport = false;
|
||||
int level;
|
||||
struct addrinfo **ai_sorted;
|
||||
int i;
|
||||
int result;
|
||||
|
||||
|
@ -78,7 +77,7 @@ int xioopen_ipapp_connect(
|
|||
|
||||
if (_xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto,
|
||||
sfd->para.socket.ip.ai_flags,
|
||||
&themlist, us, &uslen, &needbind, &lowport,
|
||||
&themarr, us, &uslen, &needbind, &lowport,
|
||||
socktype) != STAT_OK) {
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
|
@ -94,33 +93,22 @@ int xioopen_ipapp_connect(
|
|||
Info("starting connect loop");
|
||||
}
|
||||
|
||||
/* Count addrinfo entries */
|
||||
themp = themlist;
|
||||
i = 0;
|
||||
while (themp != NULL) {
|
||||
++i;
|
||||
themp = themp->ai_next;
|
||||
}
|
||||
ai_sorted = Calloc((i+1), sizeof(struct addrinfo *));
|
||||
if (ai_sorted == NULL)
|
||||
return STAT_RETRYLATER;
|
||||
/* Generate a list of addresses sorted by preferred ip version */
|
||||
_xio_sort_ip_addresses(themlist, ai_sorted);
|
||||
|
||||
do { /* loop over retries, and forks */
|
||||
|
||||
/* Loop over themlist - no, over ai_sorted */
|
||||
/* Loop over themarr (which had been "ai_sorted") */
|
||||
result = STAT_RETRYLATER;
|
||||
i = 0;
|
||||
themp = ai_sorted[i++];
|
||||
themp = themarr[i++];
|
||||
while (themp != NULL) {
|
||||
Notice1("opening connection to %s",
|
||||
sockaddr_info(themp->ai_addr, themp->ai_addrlen,
|
||||
infobuff, sizeof(infobuff)));
|
||||
|
||||
#if WITH_RETRY
|
||||
if (sfd->forever || sfd->retry || ai_sorted[i] != NULL) {
|
||||
if (sfd->forever || sfd->retry) {
|
||||
level = E_INFO;
|
||||
} else if (themarr[i] != NULL) {
|
||||
level = E_WARN;
|
||||
} else
|
||||
#endif /* WITH_RETRY */
|
||||
level = E_ERROR;
|
||||
|
@ -133,7 +121,7 @@ int xioopen_ipapp_connect(
|
|||
lowport, level);
|
||||
if (result == STAT_OK)
|
||||
break;
|
||||
themp = ai_sorted[i++];
|
||||
themp = themarr[i++];
|
||||
if (themp == NULL) {
|
||||
result = STAT_RETRYLATER;
|
||||
}
|
||||
|
@ -153,7 +141,7 @@ int xioopen_ipapp_connect(
|
|||
}
|
||||
#endif /* WITH_RETRY */
|
||||
default:
|
||||
free(ai_sorted);
|
||||
xiofreeaddrinfo(themarr);
|
||||
free(opts0);free(opts);
|
||||
return result;
|
||||
}
|
||||
|
@ -170,7 +158,7 @@ int xioopen_ipapp_connect(
|
|||
if (sfd->forever || --sfd->retry) {
|
||||
Nanosleep(&sfd->intervall, NULL); continue;
|
||||
}
|
||||
free(ai_sorted);
|
||||
xiofreeaddrinfo(themarr);
|
||||
free(opts0);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
@ -197,8 +185,7 @@ int xioopen_ipapp_connect(
|
|||
}
|
||||
} while (true);
|
||||
/* only "active" process breaks (master without fork, or child) */
|
||||
free(ai_sorted);
|
||||
xiofreeaddrinfo(themlist);
|
||||
xiofreeaddrinfo(themarr);
|
||||
|
||||
if ((result = _xio_openlate(sfd, opts)) < 0) {
|
||||
free(opts0);free(opts);
|
||||
|
@ -223,7 +210,7 @@ int
|
|||
int *pf,
|
||||
int protocol,
|
||||
const int ai_flags[2],
|
||||
struct addrinfo **themlist,
|
||||
struct addrinfo ***themarr,
|
||||
union sockaddr_union *us,
|
||||
socklen_t *uslen,
|
||||
bool *needbind,
|
||||
|
@ -236,7 +223,7 @@ int
|
|||
|
||||
if (hostname != NULL || portname != NULL) {
|
||||
rc = xiogetaddrinfo(hostname, portname, *pf, socktype, protocol,
|
||||
themlist, ai_flags);
|
||||
themarr, ai_flags);
|
||||
if (rc == EAI_AGAIN) {
|
||||
Warn4("_xioopen_ipapp_prepare(node=\"%s\", service=\"%s\", pf=%d, ...): %s",
|
||||
hostname?hostname:"NULL", portname?portname:"NULL",
|
||||
|
@ -253,13 +240,13 @@ int
|
|||
applyopts(NULL, -1, opts, PH_EARLY);
|
||||
|
||||
/* 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:(**themarr)->ai_family,
|
||||
socktype, protocol, (struct sockaddr *)us, uslen, 3,
|
||||
ai_flags)
|
||||
!= STAT_NOACTION) {
|
||||
*needbind = true;
|
||||
} else {
|
||||
switch ((*pf!=PF_UNSPEC)?*pf:(*themlist)->ai_family) {
|
||||
switch ((*pf!=PF_UNSPEC)?*pf:(**themarr)->ai_family) {
|
||||
#if WITH_IP4
|
||||
case PF_INET: socket_in_init(&us->ip4); *uslen = sizeof(us->ip4); break;
|
||||
#endif /* WITH_IP4 */
|
||||
|
@ -271,7 +258,7 @@ int
|
|||
}
|
||||
|
||||
if (retropt_2bytes(opts, OPT_SOURCEPORT, &port) >= 0) {
|
||||
switch ((*pf!=PF_UNSPEC)?*pf:(*themlist)->ai_family) {
|
||||
switch ((*pf!=PF_UNSPEC)?*pf:(**themarr)->ai_family) {
|
||||
#if WITH_IP4
|
||||
case PF_INET: us->ip4.sin_port = htons(port); break;
|
||||
#endif /* WITH_IP4 */
|
||||
|
@ -397,60 +384,4 @@ int xioopen_ipapp_listen(
|
|||
}
|
||||
#endif /* WITH_IP4 && WITH_TCP && WITH_LISTEN */
|
||||
|
||||
|
||||
/* Sort the records of an addrinfo list themp (as returned by getaddrinfo),
|
||||
return the sorted list in the array ai_sorted (takes at most n entries
|
||||
including the terminating NULL)
|
||||
Returns 0 on success. */
|
||||
int _xio_sort_ip_addresses(
|
||||
struct addrinfo *themlist,
|
||||
struct addrinfo **ai_sorted)
|
||||
{
|
||||
struct addrinfo *themp;
|
||||
int i;
|
||||
int ipv[3];
|
||||
int ipi = 0;
|
||||
|
||||
/* Make a simple array of IP version preferences */
|
||||
switch (xioparms.preferred_ip) {
|
||||
case '0':
|
||||
ipv[0] = PF_UNSPEC;
|
||||
ipv[1] = -1;
|
||||
break;
|
||||
case '4':
|
||||
ipv[0] = PF_INET;
|
||||
ipv[1] = PF_INET6;
|
||||
ipv[2] = -1;
|
||||
break;
|
||||
case '6':
|
||||
ipv[0] = PF_INET6;
|
||||
ipv[1] = PF_INET;
|
||||
ipv[2] = -1;
|
||||
break;
|
||||
default:
|
||||
Error("INTERNAL: undefined preferred_ip value");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create the sorted list */
|
||||
ipi = 0;
|
||||
i = 0;
|
||||
while (ipv[ipi] >= 0) {
|
||||
themp = themlist;
|
||||
while (themp != NULL) {
|
||||
if (ipv[ipi] == PF_UNSPEC) {
|
||||
ai_sorted[i] = themp;
|
||||
++i;
|
||||
} else if (ipv[ipi] == themp->ai_family) {
|
||||
ai_sorted[i] = themp;
|
||||
++i;
|
||||
}
|
||||
themp = themp->ai_next;
|
||||
}
|
||||
++ipi;
|
||||
}
|
||||
ai_sorted[i] = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* WITH_TCP || WITH_UDP */
|
||||
|
|
|
@ -15,13 +15,12 @@ extern const struct optdesc opt_sourceport;
|
|||
extern const struct optdesc opt_lowport;
|
||||
|
||||
extern int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, const struct addrdesc *addrdesc);
|
||||
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], 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], struct addrinfo ***themlist, 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,
|
||||
struct opt *opts);
|
||||
extern int xioopen_ipapp_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, const struct addrdesc *addrdesc);
|
||||
extern int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0, const char *portname, int *pf, int ipproto, const int ai_flags[2], union sockaddr_union *us, socklen_t *uslen, int socktype);
|
||||
extern int _xio_sort_ip_addresses(struct addrinfo *themlist, struct addrinfo **ai_sorted);
|
||||
|
||||
#endif /* !defined(__xio_ipapp_h_included) */
|
||||
|
|
|
@ -241,11 +241,10 @@ static int xioopen_openssl_connect(
|
|||
bool dofork = false;
|
||||
union sockaddr_union us_sa, *us = &us_sa;
|
||||
socklen_t uslen = sizeof(us_sa);
|
||||
struct addrinfo *themlist, *themp;
|
||||
struct addrinfo **themarr, *themp;
|
||||
bool needbind = false;
|
||||
bool lowport = false;
|
||||
int level = E_ERROR;
|
||||
struct addrinfo **ai_sorted;
|
||||
int i;
|
||||
SSL_CTX* ctx;
|
||||
bool opt_ver = true; /* verify peer certificate */
|
||||
|
@ -323,7 +322,7 @@ static int xioopen_openssl_connect(
|
|||
result =
|
||||
_xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto,
|
||||
sfd->para.socket.ip.ai_flags,
|
||||
&themlist, us, &uslen,
|
||||
&themarr, us, &uslen,
|
||||
&needbind, &lowport, socktype);
|
||||
if (result != STAT_OK) return STAT_NORETRY;
|
||||
|
||||
|
@ -334,28 +333,15 @@ static int xioopen_openssl_connect(
|
|||
Info("starting connect loop");
|
||||
}
|
||||
|
||||
/* Count addrinfo entries */
|
||||
themp = themlist;
|
||||
i = 0;
|
||||
while (themp != NULL) {
|
||||
++i;
|
||||
themp = themp->ai_next;
|
||||
}
|
||||
ai_sorted = Calloc((i+1), sizeof(struct addrinfo *));
|
||||
if (ai_sorted == NULL)
|
||||
return STAT_RETRYLATER;
|
||||
/* Generate a list of addresses sorted by preferred ip version */
|
||||
_xio_sort_ip_addresses(themlist, ai_sorted);
|
||||
|
||||
do { /* loop over failed connect and SSL handshake attempts */
|
||||
|
||||
/* Loop over ai_sorted list */
|
||||
/* Loop over themarr (which had been "ai_sorted") */
|
||||
i = 0;
|
||||
themp = ai_sorted[i++];
|
||||
themp = themarr[i++];
|
||||
while (themp != NULL) {
|
||||
|
||||
#if WITH_RETRY
|
||||
if (sfd->forever || sfd->retry || ai_sorted[i] != NULL) {
|
||||
if (sfd->forever || sfd->retry || themarr[i] != NULL) {
|
||||
level = E_INFO;
|
||||
} else
|
||||
#endif /* WITH_RETRY */
|
||||
|
@ -369,7 +355,7 @@ static int xioopen_openssl_connect(
|
|||
opts, pf?pf:themp->ai_addr->sa_family, socktype, ipproto, lowport, level);
|
||||
if (result == STAT_OK)
|
||||
break;
|
||||
themp = ai_sorted[i++];
|
||||
themp = themarr[i++];
|
||||
if (themp == NULL) {
|
||||
result = STAT_RETRYLATER;
|
||||
}
|
||||
|
@ -387,16 +373,16 @@ static int xioopen_openssl_connect(
|
|||
--sfd->retry;
|
||||
continue;
|
||||
}
|
||||
free(ai_sorted);
|
||||
xiofreeaddrinfo(themarr);
|
||||
return STAT_NORETRY;
|
||||
#endif /* WITH_RETRY */
|
||||
default:
|
||||
free(ai_sorted);
|
||||
xiofreeaddrinfo(themarr);
|
||||
return result;
|
||||
}
|
||||
/*! isn't this too early? */
|
||||
if ((result = _xio_openlate(sfd, opts)) < 0) {
|
||||
free(ai_sorted);
|
||||
xiofreeaddrinfo(themarr);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -418,7 +404,7 @@ static int xioopen_openssl_connect(
|
|||
}
|
||||
#endif /* WITH_RETRY */
|
||||
default:
|
||||
xiofreeaddrinfo(themlist);
|
||||
xiofreeaddrinfo(themarr);
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
|
@ -437,7 +423,7 @@ static int xioopen_openssl_connect(
|
|||
if (sfd->forever || --sfd->retry) {
|
||||
Nanosleep(&sfd->intervall, NULL); continue;
|
||||
}
|
||||
xiofreeaddrinfo(themlist);
|
||||
xiofreeaddrinfo(themarr);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
|
@ -458,8 +444,7 @@ static int xioopen_openssl_connect(
|
|||
#endif /* WITH_RETRY */
|
||||
break;
|
||||
} while (true); /* drop out on success */
|
||||
free(ai_sorted);
|
||||
xiofreeaddrinfo(themlist);
|
||||
xiofreeaddrinfo(themarr);
|
||||
|
||||
openssl_conn_loginfo(sfd->para.openssl.ssl);
|
||||
|
||||
|
|
29
xio-proxy.c
29
xio-proxy.c
|
@ -93,8 +93,7 @@ static int xioopen_proxy_connect(
|
|||
int pf = PF_UNSPEC;
|
||||
union sockaddr_union us_sa, *us = &us_sa;
|
||||
socklen_t uslen = sizeof(us_sa);
|
||||
struct addrinfo *themlist, *themp;
|
||||
struct addrinfo **ai_sorted;
|
||||
struct addrinfo **themarr, *themp;
|
||||
int i;
|
||||
const char *proxyname; char *proxyport = NULL;
|
||||
const char *targetname, *targetport;
|
||||
|
@ -146,32 +145,19 @@ static int xioopen_proxy_connect(
|
|||
_xioopen_ipapp_prepare(opts, &opts0, proxyname, proxyport,
|
||||
&pf, ipproto,
|
||||
sfd->para.socket.ip.ai_flags,
|
||||
&themlist, us, &uslen,
|
||||
&themarr, us, &uslen,
|
||||
&needbind, &lowport, socktype);
|
||||
if (result != STAT_OK)
|
||||
return result;
|
||||
|
||||
/* Count addrinfo entries */
|
||||
themp = themlist;
|
||||
i = 0;
|
||||
while (themp != NULL) {
|
||||
++i;
|
||||
themp = themp->ai_next;
|
||||
}
|
||||
ai_sorted = Calloc((i+1), sizeof(struct addrinfo *));
|
||||
if (ai_sorted == NULL)
|
||||
return STAT_RETRYLATER;
|
||||
/* Generate a list of addresses sorted by preferred ip version */
|
||||
_xio_sort_ip_addresses(themlist, ai_sorted);
|
||||
|
||||
/* Loop over themlist */
|
||||
i = 0;
|
||||
themp = ai_sorted[i++];
|
||||
themp = themarr[i++];
|
||||
while (themp != NULL) {
|
||||
Notice4("opening connection to %s:%u via proxy %s:%s",
|
||||
proxyvars->targetaddr, proxyvars->targetport, proxyname, proxyport);
|
||||
#if WITH_RETRY
|
||||
if (sfd->forever || sfd->retry || ai_sorted[i] != NULL) {
|
||||
if (sfd->forever || sfd->retry || themarr[i] != NULL) {
|
||||
level = E_INFO;
|
||||
} else
|
||||
#endif /* WITH_RETRY */
|
||||
|
@ -184,7 +170,7 @@ static int xioopen_proxy_connect(
|
|||
opts, pf?pf:themp->ai_family, socktype, IPPROTO_TCP, lowport, level);
|
||||
if (result == STAT_OK)
|
||||
break;
|
||||
themp = ai_sorted[i++];
|
||||
themp = themarr[i++];
|
||||
if (themp == NULL) {
|
||||
result = STAT_RETRYLATER;
|
||||
}
|
||||
|
@ -201,12 +187,11 @@ static int xioopen_proxy_connect(
|
|||
}
|
||||
#endif /* WITH_RETRY */
|
||||
default:
|
||||
free(ai_sorted);
|
||||
xiofreeaddrinfo(themlist);
|
||||
xiofreeaddrinfo(themarr);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
xiofreeaddrinfo(themlist);
|
||||
xiofreeaddrinfo(themarr);
|
||||
applyopts(sfd, -1, opts, PH_ALL);
|
||||
|
||||
if ((result = _xio_openlate(sfd, opts)) < 0)
|
||||
|
|
31
xio-socks.c
31
xio-socks.c
|
@ -55,8 +55,7 @@ static int xioopen_socks4_connect(
|
|||
bool dofork = false;
|
||||
union sockaddr_union us_sa, *us = &us_sa;
|
||||
socklen_t uslen = sizeof(us_sa);
|
||||
struct addrinfo *themlist, *themp;
|
||||
struct addrinfo **ai_sorted;
|
||||
struct addrinfo **themarr, *themp;
|
||||
int i;
|
||||
bool needbind = false;
|
||||
bool lowport = false;
|
||||
|
@ -103,22 +102,9 @@ static int xioopen_socks4_connect(
|
|||
_xioopen_ipapp_prepare(opts, &opts0, sockdname, socksport,
|
||||
&pf, ipproto,
|
||||
sfd->para.socket.ip.ai_flags,
|
||||
&themlist, us, &uslen,
|
||||
&themarr, us, &uslen,
|
||||
&needbind, &lowport, socktype);
|
||||
|
||||
/* Count addrinfo entries */
|
||||
themp = themlist;
|
||||
i = 0;
|
||||
while (themp != NULL) {
|
||||
++i;
|
||||
themp = themp->ai_next;
|
||||
}
|
||||
ai_sorted = Calloc((i+1), sizeof(struct addrinfo *));
|
||||
if (ai_sorted == NULL)
|
||||
return STAT_RETRYLATER;
|
||||
/* Generate a list of addresses sorted by preferred ip version */
|
||||
_xio_sort_ip_addresses(themlist, ai_sorted);
|
||||
|
||||
/* we try to resolve the target address _before_ connecting to the socks
|
||||
server: this avoids unnecessary socks connects and timeouts */
|
||||
result =
|
||||
|
@ -139,15 +125,15 @@ static int xioopen_socks4_connect(
|
|||
return result;
|
||||
}
|
||||
|
||||
/* loop over themlist */
|
||||
/* loop over themarr */
|
||||
i = 0;
|
||||
themp = ai_sorted[i++];
|
||||
themp = themarr[i++];
|
||||
while (themp != NULL) {
|
||||
Notice1("opening connection to %s",
|
||||
sockaddr_info(themp->ai_addr, themp->ai_addrlen,
|
||||
infobuff, sizeof(infobuff)));
|
||||
#if WITH_RETRY
|
||||
if (sfd->forever || sfd->retry || ai_sorted[i] != NULL) {
|
||||
if (sfd->forever || sfd->retry || themarr[i] != NULL) {
|
||||
level = E_INFO;
|
||||
} else
|
||||
#endif /* WITH_RETRY */
|
||||
|
@ -161,7 +147,7 @@ static int xioopen_socks4_connect(
|
|||
opts, pf?pf:themp->ai_family, socktype, IPPROTO_TCP, lowport, level);
|
||||
if (result == STAT_OK)
|
||||
break;
|
||||
themp = ai_sorted[i++];
|
||||
themp = themarr[i++];
|
||||
if (themp == NULL)
|
||||
result = STAT_RETRYLATER;
|
||||
}
|
||||
|
@ -178,11 +164,10 @@ static int xioopen_socks4_connect(
|
|||
}
|
||||
#endif /* WITH_RETRY */
|
||||
default:
|
||||
free(ai_sorted);
|
||||
xiofreeaddrinfo(themlist);
|
||||
xiofreeaddrinfo(themarr);
|
||||
return result;
|
||||
}
|
||||
xiofreeaddrinfo(themlist);
|
||||
xiofreeaddrinfo(themarr);
|
||||
applyopts(sfd, -1, opts, PH_ALL);
|
||||
|
||||
if ((result = _xio_openlate(sfd, opts)) < 0)
|
||||
|
|
12
xio-socks5.c
12
xio-socks5.c
|
@ -512,7 +512,7 @@ static int xioopen_socks5(
|
|||
const char *socks_server, *target_name, *target_port, *socks_port;
|
||||
union sockaddr_union us_sa, *us = &us_sa;
|
||||
socklen_t uslen = sizeof(us_sa);
|
||||
struct addrinfo *themlist, *themp;
|
||||
struct addrinfo **themarr, *themp;
|
||||
bool needbind = false;
|
||||
bool lowport = false;
|
||||
char infobuff[256];
|
||||
|
@ -542,7 +542,7 @@ static int xioopen_socks5(
|
|||
result = _xioopen_ipapp_prepare(opts, &opts0, socks_server, socks_port,
|
||||
&pf, ipproto,
|
||||
sfd->para.socket.ip.ai_flags,
|
||||
&themlist, us, &uslen,
|
||||
&themarr, us, &uslen,
|
||||
&needbind, &lowport, socktype);
|
||||
|
||||
Notice2("connecting to socks5 server %s:%s",
|
||||
|
@ -557,8 +557,8 @@ static int xioopen_socks5(
|
|||
}
|
||||
#endif
|
||||
|
||||
/* loop over themlist */
|
||||
themp = themlist;
|
||||
/* loop over themarr */
|
||||
themp = themarr[0];
|
||||
while (themp != NULL) {
|
||||
Notice1("opening connection to %s",
|
||||
sockaddr_info(themp->ai_addr, themp->ai_addrlen,
|
||||
|
@ -584,11 +584,11 @@ static int xioopen_socks5(
|
|||
}
|
||||
#endif
|
||||
default:
|
||||
xiofreeaddrinfo(themlist);
|
||||
xiofreeaddrinfo(themarr);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
xiofreeaddrinfo(themlist);
|
||||
xiofreeaddrinfo(themarr);
|
||||
applyopts(sfd, -1, opts, PH_ALL);
|
||||
|
||||
if ((result = _xio_openlate(sfd, opts)) < 0)
|
||||
|
|
Loading…
Reference in a new issue