mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 15:32:35 +00:00
Preferred IP version sorts getaddrionf() results
This commit is contained in:
parent
2d282f5608
commit
277f0d755d
16 changed files with 331 additions and 146 deletions
22
CHANGES
22
CHANGES
|
@ -75,14 +75,22 @@ Features:
|
|||
Tests: TRY_ADDRS_4 TRY_ADDRS_4_6
|
||||
Feature recommended by Anand Buddhdev.
|
||||
|
||||
configure option --with-default-ipv allows to specify at build time if
|
||||
IPv4, IPv6, or none of these is the preferred default.
|
||||
configure option --enable-default-ipv allows to specify at build time if
|
||||
IPv4, IPv6, or none of these is the preferred default; this is related
|
||||
to environment variables SOCAT_PREFERRED_RESOLVE_IP and
|
||||
SOCAT_DEFAULT_LISTEN_IP, and to Socat option -4, -6.
|
||||
Furthermore, mechanism of IPv4 vs.IPv6 selection has been reworked.
|
||||
When no IP version is preferred by these mechanism, passive Socat
|
||||
addresses (LISTEN, RECV, RECVFROM) default to IPv6 because it might
|
||||
support both versions (but checkout option ipv6-v6only).
|
||||
For client addresses, when one of these mechanisms applies and name
|
||||
resolution gives addresses of both IP versions, the addresses of the
|
||||
preferred versions are tried first.
|
||||
|
||||
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)
|
||||
New option ai-addrconfig sets or unsets the AI_ADDRCONFIG flag of the
|
||||
resolver to prevent name resolution to address families that are not
|
||||
available in the network configuration. Default value is 1 in case the
|
||||
resolver does not get an address family hint.
|
||||
|
||||
Flag AI_PASSIVE is now automatically applied for LISTEN, RECV, and
|
||||
RECVFROM type addresses, and with bind option. In addition to its
|
||||
|
|
|
@ -723,7 +723,7 @@
|
|||
|
||||
#undef WITH_MSGLEVEL
|
||||
|
||||
#undef WITH_DEFAULT_IPV /* default IP version: undef, "4", "6" */
|
||||
#undef WITH_DEFAULT_IPV /* default IP version: "0", "4", "6" */
|
||||
|
||||
#define BUILD_DATE __DATE__ " " __TIME__
|
||||
|
||||
|
|
|
@ -821,12 +821,12 @@ AC_ARG_ENABLE(msglevel, [ --enable-msglevel=N set max verbosity to debug,in
|
|||
[AC_DEFINE(WITH_MSGLEVEL,0) AC_MSG_RESULT(debug)])
|
||||
|
||||
AC_MSG_CHECKING(default IP version)
|
||||
AC_ARG_ENABLE(ip-version, [ --enable-ip-version=N set default IP version to undef, "4", "6"],
|
||||
AC_ARG_ENABLE(default-ipv, [ --enable-default-ipv=N set default/preferred IP version to "0" (none), "4", "6"],
|
||||
[case "$enableval" in
|
||||
"") AC_DEFINE(WITH_DEFAULT_IPV, 0) AC_MSG_RESULT("0");;
|
||||
"") AC_DEFINE(WITH_DEFAULT_IPV, '0') AC_MSG_RESULT("0");;
|
||||
4) AC_DEFINE(WITH_DEFAULT_IPV, '4') AC_MSG_RESULT("4");;
|
||||
6) AC_DEFINE(WITH_DEFAULT_IPV, '6') AC_MSG_RESULT("6");;
|
||||
*) AC_DEFINE(WITH_DEFAULT_IPV, 0) AC_MSG_RESULT("0");;
|
||||
*) AC_DEFINE(WITH_DEFAULT_IPV, '0') AC_MSG_RESULT("0");;
|
||||
esac],
|
||||
[AC_DEFINE(WITH_DEFAULT_IPV, '0') AC_MSG_RESULT("0")])
|
||||
|
||||
|
|
|
@ -2244,7 +2244,7 @@ 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.
|
||||
resolver does not get an address family hint from Socat address or defaults.
|
||||
dit(bf(tt(ai-passive[=0|1]))), dit(bf(tt(passive[=0|1])))
|
||||
Sets of unsets the AI_ADDRCONFIG flag for code(getaddrinfo)) calls. Default
|
||||
is 1 for LISTEN, RECV, and RECVFROM type addresses, and with
|
||||
|
|
79
test.sh
79
test.sh
|
@ -2483,20 +2483,29 @@ waittcp6port $tsl 1
|
|||
echo "$da" |$CMD2 >>"$tf" 2>>"${te}2"
|
||||
if [ $? -ne 0 ]; then
|
||||
$PRINTF "$FAILED: $TRACE $SOCAT:\n"
|
||||
echo "$CMD1 &"
|
||||
echo "SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 &"
|
||||
cat "${te}1" >&2
|
||||
echo "$CMD2"
|
||||
cat "${te}1" "${te}2"
|
||||
cat "${te}2" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
|
||||
$PRINTF "$FAILED: diff:\n"
|
||||
cat "$tdiff"
|
||||
$PRINTF "$FAILED (diff):\n"
|
||||
echo "SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 &"
|
||||
cat "${te}1" >&2
|
||||
echo "$CMD2"
|
||||
cat "${te}2" >&2
|
||||
echo "// diff:" >&2
|
||||
cat "$tdiff" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
else
|
||||
$PRINTF "$OK\n"
|
||||
if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi
|
||||
numOK=$((numOK+1))
|
||||
$PRINTF "$OK\n"
|
||||
if [ "$VERBOSE" ]; then echo "$CMD1 &"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}1" >&2; fi
|
||||
if [ "$VERBOSE" ]; then echo "$CMD2"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}2" >&2; fi
|
||||
numOK=$((numOK+1))
|
||||
fi
|
||||
kill $pid 2>/dev/null; wait
|
||||
fi
|
||||
|
@ -3870,26 +3879,30 @@ tdiff="$td/test$N.diff"
|
|||
da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')"
|
||||
# we have a normal tcp echo listening - so the socks header must appear in answer
|
||||
newport tcp6 # provide free port number in $PORT
|
||||
CMD2="$TRACE $SOCAT $opts TCP6-L:$PORT,$REUSEADDR exec:\"./socks4echo.sh\""
|
||||
CMD="$TRACE $SOCAT $opts - socks4:$LOCALHOST6:32.98.76.54:32109,socksport=$PORT",socksuser="nobody"
|
||||
CMD0="$TRACE $SOCAT $opts TCP6-L:$PORT,$REUSEADDR exec:\"./socks4echo.sh\""
|
||||
CMD1="$TRACE $SOCAT $opts - socks4:$LOCALHOST6:32.98.76.54:32109,socksport=$PORT",socksuser="nobody"
|
||||
printf "test $F_n $TEST... " $N
|
||||
eval "$CMD2 2>\"${te}1\" &"
|
||||
eval "$CMD0 2>\"${te}0\" &"
|
||||
pid=$! # background process id
|
||||
waittcp6port $PORT 1
|
||||
echo "$da" |$CMD >$tf 2>"${te}2"
|
||||
if ! echo "$da" |diff - "$tf" >"$tdiff"; then
|
||||
echo "$da" |$CMD1 >${tf}1 2>"${te}1"
|
||||
if ! echo "$da" |diff - "${tf}1" >"$tdiff"; then
|
||||
$PRINTF "$FAILED: $TRACE $SOCAT:\n"
|
||||
echo "$CMD2 &"
|
||||
echo "$CMD"
|
||||
cat "${te}1"
|
||||
cat "${te}2"
|
||||
cat "$tdiff"
|
||||
echo "$CMD0 &"
|
||||
cat "${te}0" >&2
|
||||
echo "$CMD1"
|
||||
cat "${te}1" >&2
|
||||
echo "// diff:" >&2
|
||||
cat "$tdiff" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
else
|
||||
$PRINTF "$OK\n"
|
||||
if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi
|
||||
numOK=$((numOK+1))
|
||||
$PRINTF "$OK\n"
|
||||
if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}0" >&2; fi
|
||||
if [ "$VERBOSE" ]; then echo "$CMD1"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}1" >&2; fi
|
||||
numOK=$((numOK+1))
|
||||
fi
|
||||
kill $pid 2>/dev/null
|
||||
wait
|
||||
|
@ -7885,24 +7898,34 @@ rc1=$?
|
|||
rc2=$?
|
||||
kill $pid0 2>/dev/null; wait
|
||||
if [ $rc1 != 0 -o $rc2 != 0 ]; then
|
||||
$PRINTF "$FAILED\n"
|
||||
$PRINTF "$FAILED (client(s) failed)\n"
|
||||
echo "$CMD0 &"
|
||||
cat "${te}0" >&2
|
||||
echo "$CMD1"
|
||||
cat "${te}0"
|
||||
cat "${te}1"
|
||||
cat "${te}2"
|
||||
cat "${te}1" >&2
|
||||
echo "$CMD1"
|
||||
cat "${te}2" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
elif echo "$da" |diff - "${tf}" >"$tdiff"; then
|
||||
$PRINTF "$OK\n"
|
||||
if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}0" >&2; fi
|
||||
if [ "$VERBOSE" ]; then echo "$CMD1"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}1" >&2; fi
|
||||
if [ "$VERBOSE" ]; then echo "$CMD2"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}2" >&2; fi
|
||||
numOK=$((numOK+1))
|
||||
else
|
||||
$PRINTF "$FAILED\n"
|
||||
$PRINTF "$FAILED (diff)\n"
|
||||
echo "$CMD0 &"
|
||||
cat "${te}0" >&2
|
||||
echo "$CMD1"
|
||||
cat "${te}0"
|
||||
cat "${te}1"
|
||||
cat "${tdiff}"
|
||||
cat "${te}1" >&2
|
||||
echo "$CMD2"
|
||||
cat "${te}2" >&2
|
||||
echo "// diff:" >&2
|
||||
cat "${tdiff}" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
fi
|
||||
|
|
32
xio-ip.c
32
xio-ip.c
|
@ -112,11 +112,11 @@ const struct optdesc opt_res_dnsrch = { "res-dnsrch", "dnsrch", OPT_RES_DN
|
|||
|
||||
|
||||
int xioinit_ip(
|
||||
struct single *sfd,
|
||||
int *pf)
|
||||
int *pf,
|
||||
char ipv)
|
||||
{
|
||||
if (*pf == PF_UNSPEC) {
|
||||
switch (xioparms.preferred_ip) {
|
||||
switch (ipv) {
|
||||
case '0': *pf = PF_UNSPEC; break;
|
||||
#if WITH_IP4
|
||||
case '4': *pf = PF_INET; break;
|
||||
|
@ -254,7 +254,7 @@ int xiogetaddrinfo(const char *node, const char *service,
|
|||
}
|
||||
if (error_num == EAI_SERVICE && protocol != 0) {
|
||||
if (hints.ai_protocol == 0) {
|
||||
Error7("getaddrinfo\"%s\", \"%s\", {%d,%d,%d,%d}, {}): %s",
|
||||
Error7("getaddrinfo\"%s\", \"%s\", {0x%02x,%d,%d,%d}, {}): %s",
|
||||
node?node:"NULL", service?service:"NULL",
|
||||
hints.ai_flags, hints.ai_family,
|
||||
hints.ai_socktype, hints.ai_protocol,
|
||||
|
@ -290,7 +290,7 @@ int xiogetaddrinfo(const char *node, const char *service,
|
|||
while (record) {
|
||||
char buff[256/*!*/];
|
||||
sockaddr_info(record->ai_addr, record->ai_addrlen, buff, sizeof(buff));
|
||||
Debug5("getaddrinfo() -> flags=%d family=%d socktype=%d protocol=%d addr=%s", record->ai_flags, record->ai_family, record->ai_socktype, record->ai_protocol, buff);
|
||||
Debug5("getaddrinfo() -> flags=0x%02x family=%d socktype=%d protocol=%d addr=%s", record->ai_flags, record->ai_family, record->ai_socktype, record->ai_protocol, buff);
|
||||
record = record->ai_next;
|
||||
}
|
||||
#endif /* WITH_MSGLEVEL <= E_DEBUG */
|
||||
|
@ -425,7 +425,7 @@ void xiofreeaddrinfo(struct addrinfo *res) {
|
|||
|
||||
/* A simple resolver interface that just returns one address,
|
||||
the first found by calling xiogetaddrinfo().
|
||||
family may be AF_INET, AF_INET6, or AF_UNSPEC.
|
||||
family may be AF_INET, AF_INET6, or AF_UNSPEC;
|
||||
Returns -1 when an error occurred or when no result found.
|
||||
*/
|
||||
int xioresolve(const char *node, const char *service,
|
||||
|
@ -434,6 +434,7 @@ int xioresolve(const char *node, const char *service,
|
|||
const int ai_flags[2], const unsigned long res_opts[2])
|
||||
{
|
||||
struct addrinfo *res = NULL;
|
||||
struct addrinfo *aip;
|
||||
int rc;
|
||||
|
||||
rc = xiogetaddrinfo(node, service, family, socktype, protocol,
|
||||
|
@ -455,8 +456,23 @@ int xioresolve(const char *node, const char *service,
|
|||
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?"\"":"");
|
||||
}
|
||||
memcpy(addr, res->ai_addr, res->ai_addrlen);
|
||||
*addrlen = res->ai_addrlen;
|
||||
|
||||
aip = res;
|
||||
if (ai_flags[0] & AI_PASSIVE && family == PF_UNSPEC) {
|
||||
/* We select the first IPv6 address, if available,
|
||||
because this might accept IPv4 connections too */
|
||||
struct addrinfo *aip = res;
|
||||
while (aip != NULL) {
|
||||
if (aip->ai_family == PF_INET6)
|
||||
break;
|
||||
aip = aip->ai_next;
|
||||
}
|
||||
if (aip == NULL)
|
||||
aip = res;
|
||||
}
|
||||
|
||||
memcpy(addr, aip->ai_addr, aip->ai_addrlen);
|
||||
*addrlen = aip->ai_addrlen;
|
||||
xiofreeaddrinfo(res);
|
||||
return 0;
|
||||
}
|
||||
|
|
2
xio-ip.h
2
xio-ip.h
|
@ -42,7 +42,7 @@ extern const struct optdesc opt_res_defnames;
|
|||
extern const struct optdesc opt_res_stayopen;
|
||||
extern const struct optdesc opt_res_dnsrch;
|
||||
|
||||
extern int xioinit_ip(struct single *sfd, int *pf);
|
||||
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], const unsigned long res_opts[2]);
|
||||
extern void xiofreeaddrinfo(struct addrinfo *res);
|
||||
|
|
95
xio-ipapp.c
95
xio-ipapp.c
|
@ -38,11 +38,13 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
|
|||
int level;
|
||||
int result;
|
||||
|
||||
struct addrinfo **ai_sorted;
|
||||
int i;
|
||||
|
||||
if (argc != 3) {
|
||||
Error2("%s: wrong number of parameters (%d instead of 2)", argv[0], argc-1);
|
||||
}
|
||||
|
||||
xioinit_ip(xfd, &pf);
|
||||
xfd->howtoend = END_SHUTDOWN;
|
||||
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
|
@ -69,18 +71,32 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
|
|||
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 */
|
||||
|
||||
themp = themlist;
|
||||
/* Loop over themlist */
|
||||
/* Loop over themlist - no, over ai_sorted */
|
||||
result = STAT_RETRYLATER;
|
||||
i = 0;
|
||||
themp = ai_sorted[i++];
|
||||
while (themp != NULL) {
|
||||
Notice1("opening connection to %s",
|
||||
sockaddr_info(themp->ai_addr, themp->ai_addrlen,
|
||||
infobuff, sizeof(infobuff)));
|
||||
|
||||
#if WITH_RETRY
|
||||
if (xfd->forever || xfd->retry || themp->ai_next != NULL) {
|
||||
if (xfd->forever || xfd->retry || ai_sorted[i] != NULL) {
|
||||
level = E_INFO;
|
||||
} else
|
||||
#endif /* WITH_RETRY */
|
||||
|
@ -94,7 +110,7 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
|
|||
lowport, level);
|
||||
if (result == STAT_OK)
|
||||
break;
|
||||
themp = themp->ai_next;
|
||||
themp = ai_sorted[i++];
|
||||
if (themp == NULL) {
|
||||
result = STAT_RETRYLATER;
|
||||
}
|
||||
|
@ -114,7 +130,7 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
|
|||
}
|
||||
#endif /* WITH_RETRY */
|
||||
default:
|
||||
xiofreeaddrinfo(themlist);
|
||||
free(ai_sorted);
|
||||
free(opts0);free(opts);
|
||||
return result;
|
||||
}
|
||||
|
@ -131,7 +147,7 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
|
|||
if (xfd->forever || --xfd->retry) {
|
||||
Nanosleep(&xfd->intervall, NULL); continue;
|
||||
}
|
||||
xiofreeaddrinfo(themlist);
|
||||
free(ai_sorted);
|
||||
free(opts0);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
@ -154,13 +170,14 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
|
|||
}
|
||||
} while (true);
|
||||
/* only "active" process breaks (master without fork, or child) */
|
||||
free(ai_sorted);
|
||||
xiofreeaddrinfo(themlist);
|
||||
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0) {
|
||||
free(opts0);free(opts);
|
||||
return result;
|
||||
}
|
||||
free(opts0);free(opts);
|
||||
free(opts0); free(opts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -191,12 +208,14 @@ int
|
|||
|
||||
retropt_socket_pf(opts, pf);
|
||||
|
||||
if ((result =
|
||||
if (hostname != NULL || portname != NULL) {
|
||||
if ((result =
|
||||
xiogetaddrinfo(hostname, portname,
|
||||
*pf, socktype, protocol,
|
||||
themlist, ai_flags, res_opts))
|
||||
!= STAT_OK) {
|
||||
return STAT_NORETRY; /*! STAT_RETRYLATER? */
|
||||
}
|
||||
}
|
||||
|
||||
applyopts(-1, opts, PH_EARLY);
|
||||
|
@ -299,7 +318,7 @@ int xioopen_ipapp_listen(int argc, const char *argv[], struct opt *opts,
|
|||
Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1);
|
||||
}
|
||||
|
||||
xioinit_ip(&xfd->stream, &pf);
|
||||
xioinit_ip(&pf, xioparms.default_ip);
|
||||
if (pf == PF_UNSPEC) {
|
||||
#if WITH_IP4 && WITH_IP6
|
||||
switch (xioparms.default_ip) {
|
||||
|
@ -338,4 +357,60 @@ int xioopen_ipapp_listen(int argc, const char *argv[], struct opt *opts,
|
|||
}
|
||||
#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 */
|
||||
|
|
|
@ -28,5 +28,6 @@ extern int xioopen_ipapp_listen(int argc, const char *argv[], struct opt *opts,
|
|||
groups_t groups, int socktype,
|
||||
int ipproto, int protname);
|
||||
extern int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0, const char *portname, int *pf, int ipproto, const int ai_flags[2], const unsigned long res_opts[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) */
|
||||
|
|
|
@ -252,7 +252,9 @@ static int
|
|||
struct addrinfo *themlist, *themp;
|
||||
bool needbind = false;
|
||||
bool lowport = false;
|
||||
int level;
|
||||
int level = E_ERROR;
|
||||
struct addrinfo **ai_sorted;
|
||||
int i;
|
||||
SSL_CTX* ctx;
|
||||
bool opt_ver = true; /* verify peer certificate */
|
||||
char *opt_cert = NULL; /* file name of client certificate */
|
||||
|
@ -280,7 +282,6 @@ static int
|
|||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
xioinit_ip(xfd, &pf);
|
||||
xfd->howtoend = END_SHUTDOWN;
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
|
@ -340,19 +341,34 @@ static int
|
|||
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 */
|
||||
|
||||
#if WITH_RETRY
|
||||
if (xfd->forever || xfd->retry) {
|
||||
level = E_INFO;
|
||||
} else
|
||||
#endif /* WITH_RETRY */
|
||||
level = E_ERROR;
|
||||
|
||||
themp = themlist;
|
||||
/* loop over themlist */
|
||||
/* Loop over ai_sorted list */
|
||||
i = 0;
|
||||
themp = ai_sorted[i++];
|
||||
while (themp != NULL) {
|
||||
/* This cannot fork because we retrieved fork option above */
|
||||
|
||||
#if WITH_RETRY
|
||||
if (xfd->forever || xfd->retry || ai_sorted[i] != NULL) {
|
||||
level = E_INFO;
|
||||
} else
|
||||
#endif /* WITH_RETRY */
|
||||
level = E_ERROR;
|
||||
|
||||
/* This cannot fork because we retrieved fork option above */
|
||||
result =
|
||||
_xioopen_connect(xfd,
|
||||
needbind?us:NULL, uslen,
|
||||
|
@ -360,7 +376,7 @@ static int
|
|||
opts, pf?pf:themp->ai_addr->sa_family, socktype, ipproto, lowport, level);
|
||||
if (result == STAT_OK)
|
||||
break;
|
||||
themp = themp->ai_next;
|
||||
themp = ai_sorted[i++];
|
||||
if (themp == NULL) {
|
||||
result = STAT_RETRYLATER;
|
||||
}
|
||||
|
@ -378,16 +394,16 @@ static int
|
|||
--xfd->retry;
|
||||
continue;
|
||||
}
|
||||
xiofreeaddrinfo(themlist);
|
||||
free(ai_sorted);
|
||||
return STAT_NORETRY;
|
||||
#endif /* WITH_RETRY */
|
||||
default:
|
||||
xiofreeaddrinfo(themlist);
|
||||
free(ai_sorted);
|
||||
return result;
|
||||
}
|
||||
/*! isn't this too early? */
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0) {
|
||||
xiofreeaddrinfo(themlist);
|
||||
free(ai_sorted);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -449,6 +465,7 @@ static int
|
|||
#endif /* WITH_RETRY */
|
||||
break;
|
||||
} while (true); /* drop out on success */
|
||||
free(ai_sorted);
|
||||
xiofreeaddrinfo(themlist);
|
||||
|
||||
openssl_conn_loginfo(xfd->para.openssl.ssl);
|
||||
|
@ -572,7 +589,6 @@ static int
|
|||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
xioinit_ip(xfd, &pf);
|
||||
#if WITH_IP4 && WITH_IP6
|
||||
switch (xioparms.default_ip) {
|
||||
case '4': pf = PF_INET; break;
|
||||
|
|
67
xio-proxy.c
67
xio-proxy.c
|
@ -93,6 +93,8 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
|
|||
union sockaddr_union us_sa, *us = &us_sa;
|
||||
socklen_t uslen = sizeof(us_sa);
|
||||
struct addrinfo *themlist, *themp;
|
||||
struct addrinfo **ai_sorted;
|
||||
int i;
|
||||
const char *proxyname; char *proxyport = NULL;
|
||||
const char *targetname, *targetport;
|
||||
int ipproto = IPPROTO_TCP;
|
||||
|
@ -110,7 +112,6 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
|
|||
targetname = argv[2];
|
||||
targetport = argv[3];
|
||||
|
||||
xioinit_ip(xfd, &pf);
|
||||
xfd->howtoend = END_SHUTDOWN;
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
|
@ -128,32 +129,53 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
|
|||
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 =
|
||||
Notice4("opening connection to %s:%u via proxy %s:%s",
|
||||
proxyvars->targetaddr, proxyvars->targetport, proxyname, proxyport);
|
||||
|
||||
i = 0;
|
||||
do { /* loop over retries (failed connect and proxy-request attempts) */
|
||||
|
||||
level = E_INFO;
|
||||
|
||||
result =
|
||||
_xioopen_ipapp_prepare(opts, &opts0, proxyname, proxyport,
|
||||
&pf, ipproto,
|
||||
xfd->para.socket.ip.ai_flags,
|
||||
xfd->para.socket.ip.res_opts,
|
||||
&themlist, us, &uslen,
|
||||
&needbind, &lowport, socktype);
|
||||
if (result != STAT_OK) return result;
|
||||
|
||||
Notice4("opening connection to %s:%u via proxy %s:%s",
|
||||
proxyvars->targetaddr, proxyvars->targetport, proxyname, proxyport);
|
||||
|
||||
do { /* loop over failed connect and proxy connect attempts */
|
||||
|
||||
#if WITH_RETRY
|
||||
if (xfd->forever || xfd->retry) {
|
||||
level = E_INFO;
|
||||
} else
|
||||
#endif /* WITH_RETRY */
|
||||
level = E_ERROR;
|
||||
if (result != STAT_OK)
|
||||
return result;
|
||||
|
||||
/* Count addrinfo entries */
|
||||
themp = themlist;
|
||||
/* Loop over 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++];
|
||||
while (themp != NULL) {
|
||||
Notice4("opening connection to %s:%u via proxy %s:%s",
|
||||
proxyvars->targetaddr, proxyvars->targetport, proxyname, proxyport);
|
||||
#if WITH_RETRY
|
||||
if (xfd->forever || xfd->retry || ai_sorted[i] != NULL) {
|
||||
level = E_INFO;
|
||||
} else
|
||||
#endif /* WITH_RETRY */
|
||||
level = E_ERROR;
|
||||
|
||||
result =
|
||||
_xioopen_connect(xfd,
|
||||
needbind?us:NULL, sizeof(*us),
|
||||
|
@ -161,7 +183,7 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
|
|||
opts, pf?pf:themp->ai_family, socktype, IPPROTO_TCP, lowport, level);
|
||||
if (result == STAT_OK)
|
||||
break;
|
||||
themp = themp->ai_next;
|
||||
themp = ai_sorted[i++];
|
||||
if (themp == NULL) {
|
||||
result = STAT_RETRYLATER;
|
||||
}
|
||||
|
@ -170,18 +192,19 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
|
|||
#if WITH_RETRY
|
||||
case STAT_RETRYLATER:
|
||||
case STAT_RETRYNOW:
|
||||
if (xfd->forever || xfd->retry--) {
|
||||
if (result == STAT_RETRYLATER) Nanosleep(&xfd->intervall, NULL);
|
||||
if (xfd->forever || xfd->retry) {
|
||||
--xfd->retry;
|
||||
if (result == STAT_RETRYLATER)
|
||||
Nanosleep(&xfd->intervall, NULL);
|
||||
continue;
|
||||
}
|
||||
#endif /* WITH_RETRY */
|
||||
default:
|
||||
free(ai_sorted);
|
||||
xiofreeaddrinfo(themlist);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
xiofreeaddrinfo(themlist);
|
||||
applyopts(xfd->fd, opts, PH_ALL);
|
||||
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0)
|
||||
return result;
|
||||
|
|
|
@ -74,7 +74,7 @@ int xioopen_rawip_sendto(int argc, const char *argv[], struct opt *opts,
|
|||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
xioinit_ip(&xxfd->stream, &pf);
|
||||
xioinit_ip(&pf, xioparms.preferred_ip);
|
||||
if ((result = _xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd,
|
||||
groups, &pf)) != STAT_OK) {
|
||||
return result;
|
||||
|
@ -165,7 +165,7 @@ int xioopen_rawip_datagram(int argc, const char *argv[], struct opt *opts,
|
|||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
xioinit_ip(xfd, &pf);
|
||||
xioinit_ip(&pf, xioparms.preferred_ip);
|
||||
if ((result =
|
||||
_xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd,
|
||||
groups, &pf)) != STAT_OK) {
|
||||
|
@ -220,7 +220,7 @@ int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts,
|
|||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
xioinit_ip(&xfd->stream, &pf);
|
||||
xioinit_ip(&pf, xioparms.default_ip);
|
||||
if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) {
|
||||
Error2("xioopen_rawip_recvfrom(\"%s\",,): protocol number exceeds 255 (%u)",
|
||||
protname, ipproto);
|
||||
|
@ -284,7 +284,7 @@ int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts,
|
|||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
xioinit_ip(&xfd->stream, &pf);
|
||||
xioinit_ip(&pf, xioparms.default_ip);
|
||||
if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) {
|
||||
Error2("xioopen_rawip_recv(\"%s\",,): protocol number exceeds 255 (%u)",
|
||||
protname, ipproto);
|
||||
|
|
86
xio-socks.c
86
xio-socks.c
|
@ -54,6 +54,8 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
|
|||
union sockaddr_union us_sa, *us = &us_sa;
|
||||
socklen_t uslen = sizeof(us_sa);
|
||||
struct addrinfo *themlist, *themp;
|
||||
struct addrinfo **ai_sorted;
|
||||
int i;
|
||||
bool needbind = false;
|
||||
bool lowport = false;
|
||||
char infobuff[256];
|
||||
|
@ -72,7 +74,6 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
|
|||
targetname = argv[2];
|
||||
targetport = argv[3];
|
||||
|
||||
xioinit_ip(xfd, &pf);
|
||||
xfd->howtoend = END_SHUTDOWN;
|
||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
|
@ -82,28 +83,39 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
|
|||
retropt_bool(opts, OPT_FORK, &dofork);
|
||||
|
||||
result = _xioopen_socks4_prepare(targetport, opts, &socksport, sockhead, &buflen);
|
||||
if (result != STAT_OK) return result;
|
||||
result =
|
||||
_xioopen_ipapp_prepare(opts, &opts0, sockdname, socksport,
|
||||
&pf, ipproto,
|
||||
xfd->para.socket.ip.ai_flags,
|
||||
xfd->para.socket.ip.res_opts,
|
||||
&themlist, us, &uslen,
|
||||
&needbind, &lowport, socktype);
|
||||
if (result != STAT_OK)
|
||||
return result;
|
||||
|
||||
Notice5("opening connection to %s:%u via socks4 server %s:%s as user \"%s\"",
|
||||
targetname,
|
||||
ntohs(sockhead->port),
|
||||
sockdname, socksport, sockhead->userid);
|
||||
|
||||
do { /* loop over failed connect and socks-request attempts */
|
||||
i = 0;
|
||||
do { /* loop over retries (failed connect and socks-request attempts) */
|
||||
|
||||
#if WITH_RETRY
|
||||
if (xfd->forever || xfd->retry) {
|
||||
level = E_INFO;
|
||||
} else
|
||||
#endif /* WITH_RETRY */
|
||||
level = E_ERROR;
|
||||
level = E_INFO;
|
||||
|
||||
result =
|
||||
_xioopen_ipapp_prepare(opts, &opts0, sockdname, socksport,
|
||||
&pf, ipproto,
|
||||
xfd->para.socket.ip.ai_flags,
|
||||
xfd->para.socket.ip.res_opts,
|
||||
&themlist, 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 */
|
||||
|
@ -124,41 +136,51 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
|
|||
return result;
|
||||
}
|
||||
|
||||
themp = themlist;
|
||||
/* loop over themlist */
|
||||
i = 0;
|
||||
themp = ai_sorted[i++];
|
||||
while (themp != NULL) {
|
||||
Notice1("opening connection to %s",
|
||||
sockaddr_info(themp->ai_addr, themp->ai_addrlen,
|
||||
infobuff, sizeof(infobuff)));
|
||||
#if WITH_RETRY
|
||||
if (xfd->forever || xfd->retry || ai_sorted[i] != NULL) {
|
||||
level = E_INFO;
|
||||
} else
|
||||
#endif /* WITH_RETRY */
|
||||
level = E_ERROR;
|
||||
|
||||
/* this cannot fork because we retrieved fork option above */
|
||||
result =
|
||||
_xioopen_connect(xfd,
|
||||
needbind?us:NULL, sizeof(*us),
|
||||
themp->ai_addr, themp->ai_addrlen,
|
||||
opts, pf?pf:themp->ai_family, socktype, IPPROTO_TCP, lowport, level);
|
||||
if (result == STAT_OK)
|
||||
break;
|
||||
themp = themp->ai_next;
|
||||
if (themp == NULL) {
|
||||
result = STAT_RETRYLATER;
|
||||
result =
|
||||
_xioopen_connect(xfd,
|
||||
needbind?us:NULL, sizeof(*us),
|
||||
themp->ai_addr, themp->ai_addrlen,
|
||||
opts, pf?pf:themp->ai_family, socktype, IPPROTO_TCP,
|
||||
lowport, level);
|
||||
if (result == STAT_OK)
|
||||
break;
|
||||
themp = ai_sorted[i++];
|
||||
if (themp == NULL) {
|
||||
result = STAT_RETRYLATER;
|
||||
}
|
||||
}
|
||||
switch (result) {
|
||||
case STAT_OK: break;
|
||||
#if WITH_RETRY
|
||||
case STAT_RETRYLATER:
|
||||
case STAT_RETRYNOW:
|
||||
if (xfd->forever || xfd->retry--) {
|
||||
if (result == STAT_RETRYLATER) Nanosleep(&xfd->intervall, NULL);
|
||||
if (xfd->forever || xfd->retry) {
|
||||
--xfd->retry;
|
||||
if (result == STAT_RETRYLATER)
|
||||
Nanosleep(&xfd->intervall, NULL);
|
||||
continue;
|
||||
}
|
||||
#endif /* WITH_RETRY */
|
||||
default:
|
||||
free(ai_sorted);
|
||||
xiofreeaddrinfo(themlist);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
xiofreeaddrinfo(themlist);
|
||||
applyopts(xfd->fd, opts, PH_ALL);
|
||||
|
||||
if ((result = _xio_openlate(xfd, opts)) < 0)
|
||||
return result;
|
||||
|
|
13
xio-udp.c
13
xio-udp.c
|
@ -297,7 +297,7 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
|
|||
Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1);
|
||||
}
|
||||
|
||||
xioinit_ip(&xfd->stream, &pf);
|
||||
xioinit_ip(&pf, xioparms.default_ip);
|
||||
if (pf == PF_UNSPEC) {
|
||||
#if WITH_IP4 && WITH_IP6
|
||||
switch (xioparms.default_ip) {
|
||||
|
@ -354,7 +354,7 @@ int xioopen_udp_sendto(int argc, const char *argv[], struct opt *opts,
|
|||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
xioinit_ip(&xfd->stream, &pf);
|
||||
//xioinit_ip(&pf, xioparms.preferred_ip);
|
||||
retropt_socket_pf(opts, &pf);
|
||||
if ((result = _xioopen_udp_sendto(argv[1], argv[2], opts, xioflags, xfd,
|
||||
groups, pf, socktype, ipproto))
|
||||
|
@ -451,7 +451,7 @@ int xioopen_udp_datagram(int argc, const char *argv[], struct opt *opts,
|
|||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
xioinit_ip(xfd, &pf);
|
||||
//xioinit_ip(&pf, xioparms.preferred_ip);
|
||||
if ((hostname = strdup(argv[1])) == NULL) {
|
||||
Error1("strdup(\"%s\"): out of memory", argv[1]);
|
||||
return STAT_RETRYLATER;
|
||||
|
@ -516,7 +516,7 @@ int xioopen_udp_recvfrom(int argc, const char *argv[], struct opt *opts,
|
|||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
xioinit_ip(&xfd->stream, &pf);
|
||||
xioinit_ip(&pf, xioparms.default_ip);
|
||||
xfd->stream.howtoend = END_NONE;
|
||||
retropt_socket_pf(opts, &pf);
|
||||
if (pf == PF_UNSPEC) {
|
||||
|
@ -541,8 +541,7 @@ int xioopen_udp_recvfrom(int argc, const char *argv[], struct opt *opts,
|
|||
|
||||
if ((result =
|
||||
xioresolve(NULL, argv[1], pf, socktype, ipproto, &us, &uslen,
|
||||
ai_flags2,
|
||||
xfd->stream.para.socket.ip.res_opts))
|
||||
ai_flags2, xfd->stream.para.socket.ip.res_opts))
|
||||
!= STAT_OK) {
|
||||
return result;
|
||||
}
|
||||
|
@ -602,7 +601,7 @@ int xioopen_udp_recv(int argc, const char *argv[], struct opt *opts,
|
|||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
xioinit_ip(&xfd->stream, &pf);
|
||||
//xioinit_ip(&pf, xioparms.default_ip);
|
||||
retropt_socket_pf(opts, &pf);
|
||||
if (pf == PF_UNSPEC) {
|
||||
#if WITH_IP4 && WITH_IP6
|
||||
|
|
|
@ -95,9 +95,11 @@ int xioinitialize(void) {
|
|||
switch (preferred_ip[0]) {
|
||||
case '4':
|
||||
case '6':
|
||||
xioparms.preferred_ip = preferred_ip[0]; break;
|
||||
xioparms.preferred_ip = preferred_ip[0];
|
||||
break;
|
||||
default:
|
||||
xioparms.preferred_ip = '0'; break;
|
||||
xioparms.preferred_ip = '0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -386,9 +386,9 @@ xiofile_t *xioopen(const char *addr, /* address specification */
|
|||
int xioflags) {
|
||||
xiofile_t *xfd;
|
||||
|
||||
if (xioinitialize() < 0) {
|
||||
return NULL;
|
||||
}
|
||||
//if (xioinitialize() < 0) {
|
||||
// return NULL;
|
||||
//}
|
||||
|
||||
Debug1("xioopen(\"%s\")", addr);
|
||||
|
||||
|
|
Loading…
Reference in a new issue