mirror of
https://repo.or.cz/socat.git
synced 2025-06-07 10:36:52 +00:00
Reworked IPAPP clients
This commit is contained in:
parent
63f67101f4
commit
7b26406d96
16 changed files with 1660 additions and 649 deletions
18
CHANGES
18
CHANGES
|
@ -60,10 +60,24 @@ Corrections:
|
||||||
now handled properly.
|
now handled properly.
|
||||||
Test: UNIX_L_BIND
|
Test: UNIX_L_BIND
|
||||||
|
|
||||||
Removed unused bytes variable from gettimestamp(), corrected #elsif and
|
Removed unused bytes variable from gettimestamp(), corrected #elsif,
|
||||||
socks4 record length.
|
and socks4 record length.
|
||||||
Thanks to clang-18 and gcc-13.
|
Thanks to clang-18 and gcc-13.
|
||||||
|
|
||||||
|
Address TCP-CONNECT, when target address resolves to both IPv4 and
|
||||||
|
IPv6, now tries to take into account bind address for protocol
|
||||||
|
selection.
|
||||||
|
|
||||||
|
Reworked and harmonized ipapp client addresses.
|
||||||
|
Tests: TCP_CONNECT_RETRY SCTP_CONNECT_RETRY DCCP_CONNECT_RETRY
|
||||||
|
OPENSSL_CONNECT_RETRY SOCKS4_RETRY SOCKS5_CONNECT_RETRY
|
||||||
|
PROXY_CONNECT_RETRY
|
||||||
|
|
||||||
|
Socks and proxy clients now also support option max-children.
|
||||||
|
Tests: TCP_CONNECT_MAXCHILDREN SCTP_CONNECT_MAXCHILDREN
|
||||||
|
DCCP_CONNECT_MAXCHILDREN OPENSSL_CONNECT_MAXCHILDREN
|
||||||
|
SOCKS4_MAXCHILDREN SOCKS5_CONNECT_MAXCHILDREN PROXY_CONNECT_MAXCHILDREN
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
POSIXMQ-RECV now takes option o-nonblock; this, in combination with -T,
|
POSIXMQ-RECV now takes option o-nonblock; this, in combination with -T,
|
||||||
makes it possible to terminate Socat in case the queue is empty.
|
makes it possible to terminate Socat in case the queue is empty.
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
# it is required for test.sh
|
# it is required for test.sh
|
||||||
# for TCP, use this script as:
|
# for TCP, use this script as:
|
||||||
# socat tcp-l:1080,reuseaddr,crlf system:"socks4echo.sh"
|
# socat tcp-l:1080,reuseaddr,crlf system:"socks4echo.sh"
|
||||||
|
# Then connect with a socks4 request for 32.98.76.54:32109 and user nobody
|
||||||
|
|
||||||
# older bash and ksh do not have -n option to read command; we try dd then
|
# older bash and ksh do not have -n option to read command; we try dd then
|
||||||
#if echo a |read -n 1 null >/dev/null 2>&1; then
|
#if echo a |read -n 1 null >/dev/null 2>&1; then
|
||||||
|
|
80
xio-ip.c
80
xio-ip.c
|
@ -161,6 +161,79 @@ int Res_init(void) {
|
||||||
#endif /* HAVE_RESOLV_H */
|
#endif /* HAVE_RESOLV_H */
|
||||||
|
|
||||||
|
|
||||||
|
/* Looks for a bind option and, if found, passes it to resolver;
|
||||||
|
for IP (v4, v6) and raw (PF_UNSPEC);
|
||||||
|
returns list of addrinfo results;
|
||||||
|
returns STAT_OK if option exists and could be resolved,
|
||||||
|
STAT_NORETRY if option exists but had error,
|
||||||
|
or STAT_NOACTION if it does not exist */
|
||||||
|
int retropt_bind_ip(
|
||||||
|
struct opt *opts,
|
||||||
|
int af,
|
||||||
|
int socktype,
|
||||||
|
int ipproto,
|
||||||
|
struct addrinfo ***bindlist,
|
||||||
|
int feats, /* TCP etc: 1..address allowed,
|
||||||
|
3..address and port allowed
|
||||||
|
*/
|
||||||
|
const int ai_flags[2])
|
||||||
|
{
|
||||||
|
const char portsep[] = ":";
|
||||||
|
const char *ends[] = { portsep, NULL };
|
||||||
|
const char *nests[] = { "[", "]", NULL };
|
||||||
|
bool portallowed;
|
||||||
|
char *bindname, *bindp;
|
||||||
|
char hostname[512], *hostp = hostname, *portp = NULL;
|
||||||
|
size_t hostlen = sizeof(hostname)-1;
|
||||||
|
int parsres;
|
||||||
|
int ai_flags2[2];
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if (retropt_string(opts, OPT_BIND, &bindname) < 0) {
|
||||||
|
return STAT_NOACTION;
|
||||||
|
}
|
||||||
|
bindp = bindname;
|
||||||
|
|
||||||
|
portallowed = (feats>=2);
|
||||||
|
parsres =
|
||||||
|
nestlex((const char **)&bindp, &hostp, &hostlen, ends, NULL, NULL, nests,
|
||||||
|
true, false, false);
|
||||||
|
if (parsres < 0) {
|
||||||
|
Error1("option too long: \"%s\"", bindp);
|
||||||
|
return STAT_NORETRY;
|
||||||
|
} else if (parsres > 0) {
|
||||||
|
Error1("syntax error in \"%s\"", bindp);
|
||||||
|
return STAT_NORETRY;
|
||||||
|
}
|
||||||
|
*hostp++ = '\0';
|
||||||
|
if (!strncmp(bindp, portsep, strlen(portsep))) {
|
||||||
|
if (!portallowed) {
|
||||||
|
Error("port specification not allowed in this bind option");
|
||||||
|
return STAT_NORETRY;
|
||||||
|
} else {
|
||||||
|
portp = bindp + strlen(portsep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set AI_PASSIVE, except when it is explicitely disabled */
|
||||||
|
ai_flags2[0] = ai_flags[0];
|
||||||
|
ai_flags2[1] = ai_flags[1];
|
||||||
|
if (!(ai_flags2[1] & AI_PASSIVE))
|
||||||
|
ai_flags2[0] |= AI_PASSIVE;
|
||||||
|
|
||||||
|
if ((result =
|
||||||
|
xiogetaddrinfo(hostname[0]!='\0'?hostname:NULL, portp,
|
||||||
|
af, socktype, ipproto,
|
||||||
|
bindlist, ai_flags2))
|
||||||
|
!= STAT_OK) {
|
||||||
|
Error2("error resolving bind option \"%s\" with af=%d", bindname, af);
|
||||||
|
return STAT_NORETRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STAT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if WITH_DEVTESTS
|
#if WITH_DEVTESTS
|
||||||
|
|
||||||
/* Have a couple of hard coded sockaddr records, to be copied and adapted when
|
/* Have a couple of hard coded sockaddr records, to be copied and adapted when
|
||||||
|
@ -516,11 +589,11 @@ 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) {
|
||||||
Warn7("getaddrinfo(\"%s\", \"%s\", {0x%02x,%d,%d,%d}, {}): %d",
|
Warn7("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,
|
||||||
error_num);
|
gai_strerror(error_num));
|
||||||
if (numnode)
|
if (numnode)
|
||||||
free(numnode);
|
free(numnode);
|
||||||
|
|
||||||
|
@ -760,6 +833,9 @@ void xiofreeaddrinfo(struct addrinfo **ai_sorted) {
|
||||||
int ain;
|
int ain;
|
||||||
struct addrinfo *res;
|
struct addrinfo *res;
|
||||||
|
|
||||||
|
if (ai_sorted == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
/* Find the original *res from getaddrinfo past NULL */
|
/* Find the original *res from getaddrinfo past NULL */
|
||||||
ain = 0;
|
ain = 0;
|
||||||
while (ai_sorted[ain] != NULL)
|
while (ai_sorted[ain] != NULL)
|
||||||
|
|
1
xio-ip.h
1
xio-ip.h
|
@ -49,6 +49,7 @@ extern const struct optdesc opt_res_nsaddr;
|
||||||
|
|
||||||
extern int xioinit_ip(int *pf, char ipv);
|
extern int xioinit_ip(int *pf, char ipv);
|
||||||
|
|
||||||
|
extern int retropt_bind_ip(struct opt *opts, int af, int socktype, int ipproto, struct addrinfo ***bindlist, int feats, const int ai_flags[2]);
|
||||||
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 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 void xiofreeaddrinfo(struct addrinfo **ai_sorted);
|
||||||
extern int _xio_sort_ip_addresses(struct addrinfo *themlist, struct addrinfo **ai_sorted);
|
extern int _xio_sort_ip_addresses(struct addrinfo *themlist, struct addrinfo **ai_sorted);
|
||||||
|
|
427
xio-ipapp.c
427
xio-ipapp.c
|
@ -19,6 +19,7 @@ const struct optdesc opt_sourceport = { "sourceport", "sp", OPT_SOURCEPORT
|
||||||
/*const struct optdesc opt_port = { "port", NULL, OPT_PORT, GROUP_IPAPP, PH_BIND, TYPE_USHORT, OFUNC_SPEC };*/
|
/*const struct optdesc opt_port = { "port", NULL, OPT_PORT, GROUP_IPAPP, PH_BIND, TYPE_USHORT, OFUNC_SPEC };*/
|
||||||
const struct optdesc opt_lowport = { "lowport", NULL, OPT_LOWPORT, GROUP_IPAPP, PH_LATE, TYPE_BOOL, OFUNC_SPEC };
|
const struct optdesc opt_lowport = { "lowport", NULL, OPT_LOWPORT, GROUP_IPAPP, PH_LATE, TYPE_BOOL, OFUNC_SPEC };
|
||||||
|
|
||||||
|
|
||||||
#if _WITH_IP4 || _WITH_IP6
|
#if _WITH_IP4 || _WITH_IP6
|
||||||
/* we expect the form "host:port" */
|
/* we expect the form "host:port" */
|
||||||
int xioopen_ipapp_connect(
|
int xioopen_ipapp_connect(
|
||||||
|
@ -31,20 +32,18 @@ int xioopen_ipapp_connect(
|
||||||
{
|
{
|
||||||
struct single *sfd = &xxfd->stream;
|
struct single *sfd = &xxfd->stream;
|
||||||
struct opt *opts0 = NULL;
|
struct opt *opts0 = NULL;
|
||||||
|
const char *hostname = argv[1], *portname = argv[2];
|
||||||
|
int pf = addrdesc->arg3;
|
||||||
int socktype = addrdesc->arg1;
|
int socktype = addrdesc->arg1;
|
||||||
int ipproto = addrdesc->arg2;
|
int ipproto = addrdesc->arg2;
|
||||||
int pf = addrdesc->arg3;
|
|
||||||
const char *hostname = argv[1], *portname = argv[2];
|
|
||||||
bool dofork = false;
|
bool dofork = false;
|
||||||
int maxchildren = 0;
|
int maxchildren = 0;
|
||||||
union sockaddr_union us_sa, *us = &us_sa;
|
struct addrinfo **bindarr = NULL;
|
||||||
socklen_t uslen = sizeof(us_sa);
|
struct addrinfo **themarr = NULL;
|
||||||
struct addrinfo **themarr, *themp;
|
uint16_t bindport = 0;
|
||||||
char infobuff[256];
|
|
||||||
bool needbind = false;
|
bool needbind = false;
|
||||||
bool lowport = false;
|
bool lowport = false;
|
||||||
int level;
|
int level = E_ERROR;
|
||||||
int i;
|
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (argc != 3) {
|
if (argc != 3) {
|
||||||
|
@ -52,97 +51,84 @@ int xioopen_ipapp_connect(
|
||||||
return STAT_NORETRY;
|
return STAT_NORETRY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sfd->howtoend == END_UNSPEC)
|
/* Apply and retrieve some options */
|
||||||
sfd->howtoend = END_SHUTDOWN;
|
result = _xioopen_ipapp_init(sfd, xioflags, opts,
|
||||||
|
&dofork, &maxchildren,
|
||||||
|
&pf, &socktype, &ipproto);
|
||||||
|
if (result != STAT_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
if (applyopts_single(sfd, opts, PH_INIT) < 0)
|
opts0 = opts; /* save remaining options for each loop */
|
||||||
return -1;
|
opts = NULL;
|
||||||
applyopts(sfd, -1, opts, PH_INIT);
|
|
||||||
|
|
||||||
retropt_bool(opts, OPT_FORK, &dofork);
|
Notice2("opening connection to %s:%s", hostname, portname);
|
||||||
if (dofork) {
|
|
||||||
if (!(xioflags & XIO_MAYFORK)) {
|
|
||||||
Error("option fork not allowed here");
|
|
||||||
return STAT_NORETRY;
|
|
||||||
}
|
|
||||||
sfd->flags |= XIO_DOESFORK;
|
|
||||||
}
|
|
||||||
|
|
||||||
retropt_int(opts, OPT_MAX_CHILDREN, &maxchildren);
|
do { /* loop over retries and/or forks */
|
||||||
|
int _errno;
|
||||||
if (! dofork && maxchildren) {
|
|
||||||
Error("option max-children not allowed without option fork");
|
|
||||||
return STAT_NORETRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto,
|
|
||||||
sfd->para.socket.ip.ai_flags,
|
|
||||||
&themarr, us, &uslen, &needbind, &lowport,
|
|
||||||
socktype) != STAT_OK) {
|
|
||||||
return STAT_NORETRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dofork) {
|
|
||||||
xiosetchilddied(); /* set SIGCHLD handler */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xioparms.logopt == 'm') {
|
|
||||||
Info("starting connect loop, switching to syslog");
|
|
||||||
diag_set('y', xioparms.syslogfac); xioparms.logopt = 'y';
|
|
||||||
} else {
|
|
||||||
Info("starting connect loop");
|
|
||||||
}
|
|
||||||
|
|
||||||
do { /* loop over retries, and forks */
|
|
||||||
|
|
||||||
/* Loop over themarr (which had been "ai_sorted") */
|
|
||||||
result = STAT_RETRYLATER;
|
|
||||||
i = 0;
|
|
||||||
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 WITH_RETRY
|
||||||
if (sfd->forever || sfd->retry) {
|
if (sfd->forever || sfd->retry) {
|
||||||
level = E_INFO;
|
level = E_NOTICE;
|
||||||
} else if (themarr[i] != NULL) {
|
} else
|
||||||
level = E_WARN;
|
|
||||||
} else
|
|
||||||
#endif /* WITH_RETRY */
|
#endif /* WITH_RETRY */
|
||||||
level = E_ERROR;
|
level = E_WARN;
|
||||||
|
|
||||||
result =
|
opts = copyopts(opts0, GROUP_ALL);
|
||||||
_xioopen_connect(sfd,
|
|
||||||
needbind?us:NULL, uslen,
|
result =
|
||||||
themp->ai_addr, themp->ai_addrlen,
|
_xioopen_ipapp_prepare(&opts, opts0, hostname, portname,
|
||||||
opts, pf?pf:themp->ai_family, socktype, ipproto,
|
pf, socktype, ipproto,
|
||||||
lowport, level);
|
sfd->para.socket.ip.ai_flags,
|
||||||
if (result == STAT_OK)
|
&themarr, &bindarr, &bindport, &needbind, &lowport);
|
||||||
break;
|
|
||||||
themp = themarr[i++];
|
|
||||||
if (themp == NULL) {
|
|
||||||
result = STAT_RETRYLATER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case STAT_OK: break;
|
case STAT_OK: break;
|
||||||
#if WITH_RETRY
|
#if WITH_RETRY
|
||||||
case STAT_RETRYLATER:
|
case STAT_RETRYLATER:
|
||||||
case STAT_RETRYNOW:
|
case STAT_RETRYNOW:
|
||||||
if (sfd->forever || sfd->retry) {
|
if (sfd->forever || sfd->retry--) {
|
||||||
--sfd->retry;
|
if (result == STAT_RETRYLATER)
|
||||||
if (result == STAT_RETRYLATER) {
|
|
||||||
Nanosleep(&sfd->intervall, NULL);
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
}
|
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||||
dropopts(opts, PH_ALL); free(opts); opts = copyopts(opts0, GROUP_ALL);
|
xiofreeaddrinfo(themarr);
|
||||||
|
freeopts(opts);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif /* WITH_RETRY */
|
#endif /* WITH_RETRY */
|
||||||
default:
|
/* FALLTHROUGH */
|
||||||
|
case STAT_NORETRY:
|
||||||
|
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||||
xiofreeaddrinfo(themarr);
|
xiofreeaddrinfo(themarr);
|
||||||
free(opts0);free(opts);
|
freeopts(opts);
|
||||||
|
freeopts(opts0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result =
|
||||||
|
_xioopen_ipapp_connect(sfd, hostname, opts, themarr,
|
||||||
|
needbind, bindarr, bindport, lowport, level);
|
||||||
|
_errno = errno;
|
||||||
|
if (bindarr != NULL)
|
||||||
|
xiofreeaddrinfo(bindarr);
|
||||||
|
xiofreeaddrinfo(themarr);
|
||||||
|
switch (result) {
|
||||||
|
case STAT_OK: break;
|
||||||
|
#if WITH_RETRY
|
||||||
|
case STAT_RETRYLATER:
|
||||||
|
case STAT_RETRYNOW:
|
||||||
|
if (sfd->forever || sfd->retry--) {
|
||||||
|
if (result == STAT_RETRYLATER) {
|
||||||
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
}
|
||||||
|
freeopts(opts);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif /* WITH_RETRY */
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
default:
|
||||||
|
Error4("%s:%s:%s: %s", argv[0], argv[1], argv[2],
|
||||||
|
_errno?strerror(_errno):"(See above)");
|
||||||
|
freeopts(opts);
|
||||||
|
freeopts(opts0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,16 +141,18 @@ int xioopen_ipapp_connect(
|
||||||
so Notice is too weak */
|
so Notice is too weak */
|
||||||
}
|
}
|
||||||
while ((pid = xio_fork(false, level, sfd->shutup)) < 0) {
|
while ((pid = xio_fork(false, level, sfd->shutup)) < 0) {
|
||||||
if (sfd->forever || --sfd->retry) {
|
if (sfd->forever || sfd->retry--) {
|
||||||
Nanosleep(&sfd->intervall, NULL); continue;
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
xiofreeaddrinfo(themarr);
|
freeopts(opts);
|
||||||
free(opts0);
|
freeopts(opts0);
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pid == 0) { /* child process */
|
if (pid == 0) { /* child process */
|
||||||
sfd->forever = false; sfd->retry = 0;
|
sfd->forever = false;
|
||||||
|
sfd->retry = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,109 +164,266 @@ int xioopen_ipapp_connect(
|
||||||
Info1("all %d allowed children are active, waiting", maxchildren);
|
Info1("all %d allowed children are active, waiting", maxchildren);
|
||||||
Nanosleep(&sfd->intervall, NULL);
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
}
|
}
|
||||||
dropopts(opts, PH_ALL); free(opts); opts = copyopts(opts0, GROUP_ALL);
|
freeopts(opts);
|
||||||
continue; /* with next socket() bind() connect() */
|
continue; /* with next socket() bind() connect() */
|
||||||
} else
|
} else
|
||||||
#endif /* WITH_RETRY */
|
#endif /* WITH_RETRY */
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (true);
|
} while (true); /* end of loop over retries and/or forks */
|
||||||
/* only "active" process breaks (master without fork, or child) */
|
/* only "active" process breaks (master without fork, or child) */
|
||||||
xiofreeaddrinfo(themarr);
|
|
||||||
|
|
||||||
if ((result = _xio_openlate(sfd, opts)) < 0) {
|
Notice2("successfully connected to %s:%s", hostname, portname);
|
||||||
free(opts0);free(opts);
|
|
||||||
return result;
|
result = _xio_openlate(sfd, opts);
|
||||||
}
|
freeopts(opts);
|
||||||
free(opts0); free(opts);
|
freeopts(opts0);
|
||||||
return 0;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* returns STAT_OK on success or some other value on failure
|
/* This function performs static initializations for addresses like TCP-CONNECT
|
||||||
|
before start of the outer loop:
|
||||||
|
it retrieves some options
|
||||||
|
returns STAT_OK on success or some other value on failure;
|
||||||
|
applies and consumes the following options:
|
||||||
|
PH_INIT, OPT_FORK, OPT_MAX_CHILDREN, OPT_PROTOCOL_FAMILY, OPT_SO_TYPE,
|
||||||
|
OPT_SO_PROTOTYPE
|
||||||
|
*/
|
||||||
|
int _xioopen_ipapp_init(
|
||||||
|
struct single *sfd,
|
||||||
|
int xioflags,
|
||||||
|
struct opt *opts,
|
||||||
|
bool *dofork,
|
||||||
|
int *maxchildren,
|
||||||
|
int *pf,
|
||||||
|
int *socktype,
|
||||||
|
int *ipproto)
|
||||||
|
{
|
||||||
|
if (sfd->howtoend == END_UNSPEC)
|
||||||
|
sfd->howtoend = END_SHUTDOWN;
|
||||||
|
|
||||||
|
if (applyopts_single(sfd, opts, PH_INIT) < 0)
|
||||||
|
return -1;
|
||||||
|
if (applyopts(sfd, -1, opts, PH_INIT) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
retropt_bool(opts, OPT_FORK, dofork);
|
||||||
|
if (dofork) {
|
||||||
|
if (!(xioflags & XIO_MAYFORK)) {
|
||||||
|
Error1("%s: option fork not allowed here", sfd->addr->defname);
|
||||||
|
return STAT_NORETRY;
|
||||||
|
}
|
||||||
|
sfd->flags |= XIO_DOESFORK;
|
||||||
|
}
|
||||||
|
|
||||||
|
retropt_int(opts, OPT_MAX_CHILDREN, maxchildren);
|
||||||
|
if (! dofork && maxchildren) {
|
||||||
|
Error1("%s: option max-children not allowed without option fork", sfd->addr->defname);
|
||||||
|
return STAT_NORETRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
retropt_socket_pf(opts, pf);
|
||||||
|
retropt_int(opts, OPT_SO_TYPE, socktype);
|
||||||
|
retropt_int(opts, OPT_SO_PROTOTYPE, ipproto);
|
||||||
|
|
||||||
|
if (dofork) {
|
||||||
|
xiosetchilddied(); /* set SIGCHLD handler */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xioparms.logopt == 'm') {
|
||||||
|
Info("starting connect loop, switching to syslog");
|
||||||
|
diag_set('y', xioparms.syslogfac);
|
||||||
|
xioparms.logopt = 'y';
|
||||||
|
} else {
|
||||||
|
Info("starting connect loop");
|
||||||
|
}
|
||||||
|
|
||||||
|
return STAT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This function performs preparations for addresses like TCP-CONNECT
|
||||||
|
at the beginning of the outer (retry/fork) loop:
|
||||||
|
it evaluates some options and performs name resolution of both server
|
||||||
|
(target, "them") address and bind ("us") address.
|
||||||
|
It is intended to be invoked before the connect loop starts;
|
||||||
|
returns STAT_OK on success or some other value on failure;
|
||||||
applies and consumes the following options:
|
applies and consumes the following options:
|
||||||
PH_EARLY
|
PH_EARLY
|
||||||
OPT_PROTOCOL_FAMILY, OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT
|
OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT
|
||||||
*/
|
returns STAT_OK, STAT_RETRYLATER, or STAT_NORETRY (+errno)
|
||||||
int
|
*/
|
||||||
_xioopen_ipapp_prepare(
|
int _xioopen_ipapp_prepare(
|
||||||
struct opt *opts,
|
struct opt **opts,
|
||||||
struct opt **opts0,
|
struct opt *opts0,
|
||||||
const char *hostname,
|
const char *hostname,
|
||||||
const char *portname,
|
const char *portname,
|
||||||
int *pf,
|
int pf,
|
||||||
int protocol,
|
int socktype,
|
||||||
const int ai_flags[2],
|
int protocol,
|
||||||
struct addrinfo ***themarr,
|
const int ai_flags[2],
|
||||||
union sockaddr_union *us,
|
struct addrinfo ***themarr, /* always from getaddrinfo(); xiofreeaddrinfo()! */
|
||||||
socklen_t *uslen,
|
struct addrinfo ***bindarr, /* on bind from getaddrinfo(); xiofreeaddrinfo()! */
|
||||||
bool *needbind,
|
uint16_t *bindport, /* for bind without address */
|
||||||
bool *lowport,
|
bool *needbind,
|
||||||
int socktype) {
|
bool *lowport)
|
||||||
|
{
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
retropt_socket_pf(opts, pf);
|
*opts = copyopts(opts0, GROUP_ALL);
|
||||||
|
|
||||||
if (hostname != NULL || portname != NULL) {
|
if (hostname != NULL || portname != NULL) {
|
||||||
rc = xiogetaddrinfo(hostname, portname, *pf, socktype, protocol,
|
rc = xiogetaddrinfo(hostname, portname, pf, socktype, protocol,
|
||||||
themarr, ai_flags);
|
themarr, ai_flags);
|
||||||
if (rc == EAI_AGAIN) {
|
if (rc == EAI_AGAIN) {
|
||||||
Warn4("_xioopen_ipapp_prepare(node=\"%s\", service=\"%s\", pf=%d, ...): %s",
|
Warn4("_xioopen_ipapp_prepare(node=\"%s\", service=\"%s\", pf=%d, ...): %s",
|
||||||
hostname?hostname:"NULL", portname?portname:"NULL",
|
hostname?hostname:"NULL", portname?portname:"NULL",
|
||||||
*pf, gai_strerror(rc));
|
pf, gai_strerror(rc));
|
||||||
|
errno = EAGAIN;
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
} else if (rc != 0) {
|
} else if (rc != 0) {
|
||||||
Error4("_xioopen_ipapp_prepare(node=\"%s\", service=\"%s\", pf=%d, ...): %s",
|
Error4("_xioopen_ipapp_prepare(node=\"%s\", service=\"%s\", pf=%d, ...): %s",
|
||||||
hostname?hostname:"NULL", portname?portname:"NULL",
|
hostname?hostname:"NULL", portname?portname:"NULL",
|
||||||
*pf, (rc == EAI_SYSTEM)?strerror(errno):gai_strerror(rc));
|
pf, (rc == EAI_SYSTEM)?strerror(errno):gai_strerror(rc));
|
||||||
|
errno = 0; /* unspecified */
|
||||||
return STAT_NORETRY; /*! STAT_RETRYLATER? */
|
return STAT_NORETRY; /*! STAT_RETRYLATER? */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
applyopts(NULL, -1, opts, PH_EARLY);
|
applyopts(NULL, -1, *opts, PH_EARLY);
|
||||||
|
|
||||||
/* 3 means: IP address AND port accepted */
|
/* 3 means: IP address AND port accepted */
|
||||||
if (retropt_bind(opts, (*pf!=PF_UNSPEC)?*pf:(**themarr)->ai_family,
|
if (retropt_bind_ip(*opts, pf, socktype, protocol, bindarr, 3, ai_flags)
|
||||||
socktype, protocol, (struct sockaddr *)us, uslen, 3,
|
|
||||||
ai_flags)
|
|
||||||
!= STAT_NOACTION) {
|
!= STAT_NOACTION) {
|
||||||
*needbind = true;
|
*needbind = true;
|
||||||
} else {
|
|
||||||
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 */
|
|
||||||
#if WITH_IP6
|
|
||||||
case PF_INET6: socket_in6_init(&us->ip6); *uslen = sizeof(us->ip6); break;
|
|
||||||
#endif /* WITH_IP6 */
|
|
||||||
default: Error("unsupported protocol family");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (retropt_2bytes(*opts, OPT_SOURCEPORT, &port) >= 0) {
|
||||||
if (retropt_2bytes(opts, OPT_SOURCEPORT, &port) >= 0) {
|
if (*bindarr) {
|
||||||
switch ((*pf!=PF_UNSPEC)?*pf:(**themarr)->ai_family) {
|
struct addrinfo **bindp;
|
||||||
|
bindp = *bindarr;
|
||||||
|
switch ((*bindp)->ai_family) {
|
||||||
#if WITH_IP4
|
#if WITH_IP4
|
||||||
case PF_INET: us->ip4.sin_port = htons(port); break;
|
case PF_INET: ((struct sockaddr_in *)(*bindp)->ai_addr)->sin_port = htons(port); break;
|
||||||
#endif /* WITH_IP4 */
|
#endif /* WITH_IP4 */
|
||||||
#if WITH_IP6
|
#if WITH_IP6
|
||||||
case PF_INET6: us->ip6.sin6_port = htons(port); break;
|
case PF_INET6: ((struct sockaddr_in6 *)(*bindp)->ai_addr)->sin6_port = htons(port); break;
|
||||||
#endif /* WITH_IP6 */
|
#endif /* WITH_IP6 */
|
||||||
default: Error("unsupported protocol family");
|
default:
|
||||||
|
Error("unsupported protocol family");
|
||||||
|
errno = EPROTONOSUPPORT;
|
||||||
|
return STAT_NORETRY;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*bindport = port;
|
||||||
}
|
}
|
||||||
*needbind = true;
|
*needbind = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
retropt_bool(opts, OPT_LOWPORT, lowport);
|
retropt_bool(*opts, OPT_LOWPORT, lowport);
|
||||||
|
|
||||||
*opts0 = copyopts(opts, GROUP_ALL);
|
|
||||||
|
|
||||||
return STAT_OK;
|
return STAT_OK;
|
||||||
}
|
}
|
||||||
#endif /* _WITH_IP4 || _WITH_IP6 */
|
#endif /* _WITH_IP4 || _WITH_IP6 */
|
||||||
|
|
||||||
|
|
||||||
|
/* Tries to connect to the addresses in themarr, for each one it tries to bind
|
||||||
|
to the addresses in bindarr.
|
||||||
|
Ends on success or when all attempts failed.
|
||||||
|
Returns STAT_OK on success, or STAT_RETRYLATER (+errno) on failure. */
|
||||||
|
int _xioopen_ipapp_connect(struct single *sfd,
|
||||||
|
const char *hostname,
|
||||||
|
struct opt *opts,
|
||||||
|
struct addrinfo **themarr,
|
||||||
|
bool needbind,
|
||||||
|
struct addrinfo **bindarr,
|
||||||
|
uint16_t bindport,
|
||||||
|
bool lowport,
|
||||||
|
int level)
|
||||||
|
{
|
||||||
|
struct addrinfo **themp;
|
||||||
|
struct addrinfo **bindp;
|
||||||
|
union sockaddr_union bindaddr = {0};
|
||||||
|
union sockaddr_union *bindaddrp = NULL;
|
||||||
|
socklen_t bindlen = 0;
|
||||||
|
char infobuff[256];
|
||||||
|
int _errno;
|
||||||
|
int result = STAT_OK;
|
||||||
|
|
||||||
|
--level;
|
||||||
|
|
||||||
|
/* Loop over server addresses (themarr) */
|
||||||
|
themp = themarr;
|
||||||
|
while (*themp != NULL) {
|
||||||
|
Notice1("opening connection to %s",
|
||||||
|
sockaddr_info((*themp)->ai_addr, (*themp)->ai_addrlen,
|
||||||
|
infobuff, sizeof(infobuff)));
|
||||||
|
|
||||||
|
if (*(themp+1) == NULL) {
|
||||||
|
++level; /* last attempt */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loop over array (list) of bind addresses */
|
||||||
|
if (needbind && bindarr != NULL) {
|
||||||
|
/* Bind by hostname, use resolvers results list */
|
||||||
|
bindp = bindarr;
|
||||||
|
while (*bindp != NULL) {
|
||||||
|
if ((*bindp)->ai_family == (*themp)->ai_family)
|
||||||
|
break;
|
||||||
|
++bindp;
|
||||||
|
}
|
||||||
|
if (*bindp == NULL) {
|
||||||
|
Warn3("%s: No bind address with matching address family (%d) of %s available",
|
||||||
|
sfd->addr->defname, (*themp)->ai_family, hostname);
|
||||||
|
++themp;
|
||||||
|
if ((*themp) == NULL) {
|
||||||
|
result = STAT_RETRYLATER;
|
||||||
|
}
|
||||||
|
_errno = ENOPROTOOPT;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bindaddrp = (union sockaddr_union *)(*bindp)->ai_addr;
|
||||||
|
bindlen = (*bindp)->ai_addrlen;
|
||||||
|
} else if (needbind && bindport) {
|
||||||
|
/* Bind by sourceport option */
|
||||||
|
switch ((*themp)->ai_family) {
|
||||||
|
case PF_INET:
|
||||||
|
bindaddr.ip4.sin_family = (*themp)->ai_family;
|
||||||
|
bindaddr.ip4.sin_port = htons(bindport);
|
||||||
|
bindaddrp = &bindaddr;
|
||||||
|
bindlen = sizeof(bindaddr.ip4);
|
||||||
|
break;
|
||||||
|
case PF_INET6:
|
||||||
|
bindaddr.ip6.sin6_family = (*themp)->ai_family;
|
||||||
|
bindaddr.ip6.sin6_port = htons(bindport);
|
||||||
|
bindaddrp = &bindaddr;
|
||||||
|
bindlen = sizeof(bindaddr.ip6);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result =
|
||||||
|
_xioopen_connect(sfd,
|
||||||
|
bindaddrp, bindlen,
|
||||||
|
(*themp)->ai_addr, (*themp)->ai_addrlen,
|
||||||
|
opts, /*pf?pf:*/(*themp)->ai_family, (*themp)->ai_socktype, (*themp)->ai_protocol,
|
||||||
|
lowport, level);
|
||||||
|
if (result == STAT_OK)
|
||||||
|
break;
|
||||||
|
_errno = errno;
|
||||||
|
++themp;
|
||||||
|
if (*themp == NULL)
|
||||||
|
result = STAT_RETRYLATER;
|
||||||
|
} /* end of loop over target addresses */
|
||||||
|
|
||||||
|
if (result != STAT_OK)
|
||||||
|
errno = _errno;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if WITH_TCP && WITH_LISTEN
|
#if WITH_TCP && WITH_LISTEN
|
||||||
/*
|
/*
|
||||||
applies and consumes the following options:
|
applies and consumes the following options:
|
||||||
|
|
|
@ -15,11 +15,9 @@ extern const struct optdesc opt_sourceport;
|
||||||
extern const struct optdesc opt_lowport;
|
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_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 ***themlist, union sockaddr_union *us, socklen_t *uslen, bool *needbind, bool *lowport, int socktype);
|
extern int _xioopen_ipapp_init(struct single *sfd, int xioflags, struct opt *opts, bool *dofork, int *maxchildren, int *pf, int *socktype, int *protocol);
|
||||||
extern int _xioopen_ip4app_connect(const char *hostname, const char *portname,
|
extern int _xioopen_ipapp_prepare(struct opt **opts, struct opt *opts0, const char *hostname, const char *portname, int pf, int socktype, int protocol, const int ai_flags[2], struct addrinfo ***themarr, struct addrinfo ***bindarr, uint16_t *bindport, bool *needbind, bool *lowport);
|
||||||
struct single *xfd,
|
extern int _xioopen_ipapp_connect(struct single *sfd, const char *hostname, struct opt *opts, struct addrinfo **themarr, bool needbind, struct addrinfo **bindarr, uint16_t bindport, bool lowport, int level);
|
||||||
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(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 _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);
|
||||||
|
|
||||||
|
|
162
xio-openssl.c
162
xio-openssl.c
|
@ -238,13 +238,13 @@ static int xioopen_openssl_connect(
|
||||||
int socktype = SOCK_STREAM;
|
int socktype = SOCK_STREAM;
|
||||||
int ipproto = IPPROTO_TCP;
|
int ipproto = IPPROTO_TCP;
|
||||||
bool dofork = false;
|
bool dofork = false;
|
||||||
union sockaddr_union us_sa, *us = &us_sa;
|
int maxchildren = 0;
|
||||||
socklen_t uslen = sizeof(us_sa);
|
struct addrinfo **bindarr = NULL;
|
||||||
struct addrinfo **themarr, *themp;
|
struct addrinfo **themarr = NULL;
|
||||||
|
uint16_t bindport = 0;
|
||||||
bool needbind = false;
|
bool needbind = false;
|
||||||
bool lowport = false;
|
bool lowport = false;
|
||||||
int level = E_ERROR;
|
int level = E_ERROR;
|
||||||
int i;
|
|
||||||
SSL_CTX* ctx;
|
SSL_CTX* ctx;
|
||||||
bool opt_ver = true; /* verify peer certificate */
|
bool opt_ver = true; /* verify peer certificate */
|
||||||
char *opt_cert = NULL; /* file name of client certificate */
|
char *opt_cert = NULL; /* file name of client certificate */
|
||||||
|
@ -254,7 +254,7 @@ static int xioopen_openssl_connect(
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (!(xioflags & XIO_MAYCONVERT)) {
|
if (!(xioflags & XIO_MAYCONVERT)) {
|
||||||
Error("address with data processing not allowed here");
|
Error1("%s: address with data processing not allowed here", argv[0]);
|
||||||
return STAT_NORETRY;
|
return STAT_NORETRY;
|
||||||
}
|
}
|
||||||
sfd->flags |= XIO_DOESCONVERT;
|
sfd->flags |= XIO_DOESCONVERT;
|
||||||
|
@ -272,14 +272,6 @@ static int xioopen_openssl_connect(
|
||||||
return STAT_NORETRY;
|
return STAT_NORETRY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sfd->howtoend == END_UNSPEC)
|
|
||||||
sfd->howtoend = END_SHUTDOWN;
|
|
||||||
if (applyopts_single(sfd, opts, PH_INIT) < 0)
|
|
||||||
return -1;
|
|
||||||
applyopts(sfd, -1, opts, PH_INIT);
|
|
||||||
|
|
||||||
retropt_bool(opts, OPT_FORK, &dofork);
|
|
||||||
|
|
||||||
retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert);
|
retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert);
|
||||||
retropt_string(opts, OPT_OPENSSL_COMMONNAME, (char **)&opt_commonname);
|
retropt_string(opts, OPT_OPENSSL_COMMONNAME, (char **)&opt_commonname);
|
||||||
#if defined(HAVE_SSL_set_tlsext_host_name) || defined(SSL_set_tlsext_host_name)
|
#if defined(HAVE_SSL_set_tlsext_host_name) || defined(SSL_set_tlsext_host_name)
|
||||||
|
@ -315,73 +307,83 @@ static int xioopen_openssl_connect(
|
||||||
socktype = SOCK_DGRAM;
|
socktype = SOCK_DGRAM;
|
||||||
ipproto = IPPROTO_UDP;
|
ipproto = IPPROTO_UDP;
|
||||||
}
|
}
|
||||||
retropt_int(opts, OPT_SO_TYPE, &socktype);
|
|
||||||
retropt_int(opts, OPT_SO_PROTOTYPE, &ipproto);
|
|
||||||
|
|
||||||
result =
|
/* Apply and retrieve some options */
|
||||||
_xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto,
|
result = _xioopen_ipapp_init(sfd, xioflags, opts,
|
||||||
sfd->para.socket.ip.ai_flags,
|
&dofork, &maxchildren,
|
||||||
&themarr, us, &uslen,
|
&pf, &socktype, &ipproto);
|
||||||
&needbind, &lowport, socktype);
|
if (result != STAT_OK)
|
||||||
if (result != STAT_OK) return STAT_NORETRY;
|
return result;
|
||||||
|
|
||||||
if (xioparms.logopt == 'm') {
|
opts0 = opts; /* save remaining options for each loop */
|
||||||
Info("starting connect loop, switching to syslog");
|
opts = NULL;
|
||||||
diag_set('y', xioparms.syslogfac); xioparms.logopt = 'y';
|
|
||||||
} else {
|
|
||||||
Info("starting connect loop");
|
|
||||||
}
|
|
||||||
|
|
||||||
do { /* loop over failed connect and SSL handshake attempts */
|
Notice2("opening OpenSSL connection to %s:%s", hostname, portname);
|
||||||
|
|
||||||
/* Loop over themarr (which had been "ai_sorted") */
|
do { /* loop over retries (failed connect and SSL handshake attempts) and/or forks */
|
||||||
i = 0;
|
int _errno;
|
||||||
themp = themarr[i++];
|
|
||||||
while (themp != NULL) {
|
|
||||||
|
|
||||||
#if WITH_RETRY
|
#if WITH_RETRY
|
||||||
if (sfd->forever || sfd->retry || themarr[i] != NULL) {
|
if (sfd->forever || sfd->retry) {
|
||||||
level = E_INFO;
|
level = E_NOTICE;
|
||||||
} else
|
} else
|
||||||
#endif /* WITH_RETRY */
|
#endif /* WITH_RETRY */
|
||||||
level = E_ERROR;
|
level = E_WARN;
|
||||||
|
|
||||||
/* This cannot fork because we retrieved fork option above */
|
opts = copyopts(opts0, GROUP_ALL);
|
||||||
result =
|
|
||||||
_xioopen_connect(sfd,
|
result =
|
||||||
needbind?us:NULL, uslen,
|
_xioopen_ipapp_prepare(&opts, opts0, hostname, portname,
|
||||||
themp->ai_addr, themp->ai_addrlen,
|
pf, socktype, ipproto,
|
||||||
opts, pf?pf:themp->ai_addr->sa_family, socktype, ipproto, lowport, level);
|
sfd->para.socket.ip.ai_flags,
|
||||||
if (result == STAT_OK)
|
&themarr, &bindarr, &bindport, &needbind, &lowport);
|
||||||
break;
|
|
||||||
themp = themarr[i++];
|
|
||||||
if (themp == NULL) {
|
|
||||||
result = STAT_RETRYLATER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case STAT_OK: break;
|
case STAT_OK: break;
|
||||||
#if WITH_RETRY
|
#if WITH_RETRY
|
||||||
case STAT_RETRYLATER:
|
case STAT_RETRYLATER:
|
||||||
case STAT_RETRYNOW:
|
case STAT_RETRYNOW:
|
||||||
if (sfd->forever || sfd->retry) {
|
if (sfd->forever || sfd->retry--) {
|
||||||
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
|
if (result == STAT_RETRYLATER)
|
||||||
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||||
|
xiofreeaddrinfo(themarr);
|
||||||
|
freeopts(opts);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif /* WITH_RETRY */
|
||||||
|
case STAT_NORETRY:
|
||||||
|
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||||
|
xiofreeaddrinfo(themarr);
|
||||||
|
freeopts(opts);
|
||||||
|
freeopts(opts0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Notice2("opening connection to server %s:%s", hostname, portname);
|
||||||
|
result =
|
||||||
|
_xioopen_ipapp_connect(sfd, hostname, opts, themarr,
|
||||||
|
needbind, bindarr, bindport, lowport, level);
|
||||||
|
_errno = errno;
|
||||||
|
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||||
|
xiofreeaddrinfo(themarr);
|
||||||
|
switch (result) {
|
||||||
|
case STAT_OK: break;
|
||||||
|
#if WITH_RETRY
|
||||||
|
case STAT_RETRYLATER:
|
||||||
|
case STAT_RETRYNOW:
|
||||||
|
if (sfd->forever || sfd->retry--) {
|
||||||
if (result == STAT_RETRYLATER) {
|
if (result == STAT_RETRYLATER) {
|
||||||
Nanosleep(&sfd->intervall, NULL);
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
}
|
}
|
||||||
--sfd->retry;
|
freeopts(opts);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
xiofreeaddrinfo(themarr);
|
|
||||||
return STAT_NORETRY;
|
|
||||||
#endif /* WITH_RETRY */
|
#endif /* WITH_RETRY */
|
||||||
default:
|
default:
|
||||||
xiofreeaddrinfo(themarr);
|
Error4("%s:%s:%s: %s", argv[0], hostname, portname,
|
||||||
return result;
|
_errno?strerror(_errno):"(See above)");
|
||||||
}
|
freeopts(opts0);
|
||||||
/*! isn't this too early? */
|
freeopts(opts);
|
||||||
if ((result = _xio_openlate(sfd, opts)) < 0) {
|
|
||||||
xiofreeaddrinfo(themarr);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,19 +394,19 @@ static int xioopen_openssl_connect(
|
||||||
#if WITH_RETRY
|
#if WITH_RETRY
|
||||||
case STAT_RETRYLATER:
|
case STAT_RETRYLATER:
|
||||||
case STAT_RETRYNOW:
|
case STAT_RETRYNOW:
|
||||||
if (sfd->forever || sfd->retry) {
|
if (sfd->forever || sfd->retry--) {
|
||||||
Close(sfd->fd);
|
|
||||||
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
|
|
||||||
if (result == STAT_RETRYLATER) {
|
if (result == STAT_RETRYLATER) {
|
||||||
Nanosleep(&sfd->intervall, NULL);
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
}
|
}
|
||||||
--sfd->retry;
|
freeopts(opts);
|
||||||
|
Close(sfd->fd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif /* WITH_RETRY */
|
#endif /* WITH_RETRY */
|
||||||
default:
|
default:
|
||||||
xiofreeaddrinfo(themarr);
|
freeopts(opts);
|
||||||
return STAT_NORETRY;
|
freeopts(opts0);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dofork) {
|
if (dofork) {
|
||||||
|
@ -419,15 +421,19 @@ static int xioopen_openssl_connect(
|
||||||
level = E_WARN;
|
level = E_WARN;
|
||||||
}
|
}
|
||||||
while ((pid = xio_fork(false, level, sfd->shutup)) < 0) {
|
while ((pid = xio_fork(false, level, sfd->shutup)) < 0) {
|
||||||
if (sfd->forever || --sfd->retry) {
|
if (sfd->forever || sfd->retry--) {
|
||||||
Nanosleep(&sfd->intervall, NULL); continue;
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
freeopts(opts);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
xiofreeaddrinfo(themarr);
|
freeopts(opts);
|
||||||
|
freeopts(opts0);
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pid == 0) { /* child process */
|
if (pid == 0) { /* child process */
|
||||||
sfd->forever = false; sfd->retry = 0;
|
sfd->forever = false;
|
||||||
|
sfd->retry = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,21 +443,29 @@ static int xioopen_openssl_connect(
|
||||||
sfd->para.openssl.ssl = NULL;
|
sfd->para.openssl.ssl = NULL;
|
||||||
/* with and without retry */
|
/* with and without retry */
|
||||||
Nanosleep(&sfd->intervall, NULL);
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
|
while (maxchildren > 0 && num_child >= maxchildren) {
|
||||||
|
Info1("all %d allowed children are active, waiting", maxchildren);
|
||||||
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
}
|
||||||
|
freeopts(opts);
|
||||||
continue; /* with next socket() bind() connect() */
|
continue; /* with next socket() bind() connect() */
|
||||||
}
|
}
|
||||||
#endif /* WITH_RETRY */
|
#endif /* WITH_RETRY */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
} while (true); /* drop out on success */
|
} while (true); /* drop out on success */
|
||||||
xiofreeaddrinfo(themarr);
|
|
||||||
|
|
||||||
openssl_conn_loginfo(sfd->para.openssl.ssl);
|
openssl_conn_loginfo(sfd->para.openssl.ssl);
|
||||||
|
|
||||||
free((void *)opt_commonname);
|
free((void *)opt_commonname);
|
||||||
free((void *)opt_snihost);
|
free((void *)opt_snihost);
|
||||||
|
|
||||||
/* fill in the fd structure */
|
Notice2("successfully connected to SSL server %s:%s", hostname, portname);
|
||||||
return STAT_OK;
|
|
||||||
|
result = _xio_openlate(sfd, opts);
|
||||||
|
freeopts(opts);
|
||||||
|
freeopts(opts0);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
231
xio-proxy.c
231
xio-proxy.c
|
@ -83,18 +83,18 @@ static int xioopen_proxy_connect(
|
||||||
xiofile_t *xxfd,
|
xiofile_t *xxfd,
|
||||||
const struct addrdesc *addrdesc)
|
const struct addrdesc *addrdesc)
|
||||||
{
|
{
|
||||||
/* we expect the form: host:host:port */
|
/* we expect the form: host:host:port */
|
||||||
struct single *sfd = &xxfd->stream;
|
struct single *sfd = &xxfd->stream;
|
||||||
struct opt *opts0 = NULL;
|
struct opt *opts0 = NULL;
|
||||||
struct proxyvars struct_proxyvars = { 0 }, *proxyvars = &struct_proxyvars;
|
struct proxyvars struct_proxyvars = { 0 }, *proxyvars = &struct_proxyvars;
|
||||||
/* variables to be filled with address option values */
|
/* variables to be filled with address option values */
|
||||||
bool dofork = false;
|
bool dofork = false;
|
||||||
|
int maxchildren = 0;
|
||||||
/* */
|
/* */
|
||||||
int pf = PF_UNSPEC;
|
int pf = PF_UNSPEC;
|
||||||
union sockaddr_union us_sa, *us = &us_sa;
|
struct addrinfo **bindarr = NULL;
|
||||||
socklen_t uslen = sizeof(us_sa);
|
struct addrinfo **themarr = NULL;
|
||||||
struct addrinfo **themarr, *themp;
|
uint16_t bindport = 0;
|
||||||
int i;
|
|
||||||
const char *proxyname; char *proxyport = NULL;
|
const char *proxyname; char *proxyport = NULL;
|
||||||
const char *targetname, *targetport;
|
const char *targetname, *targetport;
|
||||||
int ipproto = IPPROTO_TCP;
|
int ipproto = IPPROTO_TCP;
|
||||||
|
@ -112,90 +112,123 @@ static int xioopen_proxy_connect(
|
||||||
targetname = argv[2];
|
targetname = argv[2];
|
||||||
targetport = argv[3];
|
targetport = argv[3];
|
||||||
|
|
||||||
if (sfd->howtoend == END_UNSPEC)
|
|
||||||
sfd->howtoend = END_SHUTDOWN;
|
|
||||||
if (applyopts_single(sfd, opts, PH_INIT) < 0)
|
|
||||||
return -1;
|
|
||||||
applyopts(sfd, 1, opts, PH_INIT);
|
|
||||||
|
|
||||||
retropt_int(opts, OPT_SO_TYPE, &socktype);
|
|
||||||
|
|
||||||
retropt_bool(opts, OPT_FORK, &dofork);
|
|
||||||
|
|
||||||
if (retropt_string(opts, OPT_PROXYPORT, &proxyport) < 0) {
|
if (retropt_string(opts, OPT_PROXYPORT, &proxyport) < 0) {
|
||||||
if ((proxyport = strdup(PROXYPORT)) == NULL) {
|
if ((proxyport = strdup(PROXYPORT)) == NULL) {
|
||||||
errno = ENOMEM; return -1;
|
errno = ENOMEM; return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result = _xioopen_proxy_prepare(proxyvars, opts, targetname, targetport,
|
result =
|
||||||
sfd->para.socket.ip.ai_flags);
|
_xioopen_ipapp_init(sfd, xioflags, opts,
|
||||||
if (result != STAT_OK)
|
&dofork, &maxchildren,
|
||||||
return result;
|
&pf, &socktype, &ipproto);
|
||||||
|
|
||||||
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,
|
|
||||||
sfd->para.socket.ip.ai_flags,
|
|
||||||
&themarr, us, &uslen,
|
|
||||||
&needbind, &lowport, socktype);
|
|
||||||
if (result != STAT_OK)
|
if (result != STAT_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
/* Loop over themlist */
|
result = _xioopen_proxy_init(proxyvars, opts, targetname, targetport);
|
||||||
i = 0;
|
if (result != STAT_OK)
|
||||||
themp = themarr[i++];
|
return result;
|
||||||
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 || themarr[i] != NULL) {
|
|
||||||
level = E_INFO;
|
|
||||||
} else
|
|
||||||
#endif /* WITH_RETRY */
|
|
||||||
level = E_ERROR;
|
|
||||||
|
|
||||||
result =
|
opts0 = opts; /* save remaining options for each loop */
|
||||||
_xioopen_connect(sfd,
|
opts = NULL;
|
||||||
needbind?us:NULL, uslen,
|
|
||||||
themp->ai_addr, themp->ai_addrlen,
|
Notice4("opening connection to %s:%s via proxy %s:%s",
|
||||||
opts, pf?pf:themp->ai_family, socktype, IPPROTO_TCP, lowport, level);
|
targetname, targetport, proxyname, proxyport);
|
||||||
if (result == STAT_OK)
|
|
||||||
break;
|
do { /* loop over retries (failed connect and proxy-request attempts)
|
||||||
themp = themarr[i++];
|
and/or forks */
|
||||||
if (themp == NULL) {
|
int _errno;
|
||||||
result = STAT_RETRYLATER;
|
|
||||||
}
|
#if WITH_RETRY
|
||||||
|
if (sfd->forever || sfd->retry) {
|
||||||
|
level = E_NOTICE;
|
||||||
|
} else
|
||||||
|
#endif /* WITH_RETRY */
|
||||||
|
level = E_WARN;
|
||||||
|
|
||||||
|
opts = copyopts(opts0, GROUP_ALL);
|
||||||
|
|
||||||
|
result =
|
||||||
|
_xioopen_ipapp_prepare(&opts, opts0, proxyname, proxyport,
|
||||||
|
pf, socktype, ipproto,
|
||||||
|
sfd->para.socket.ip.ai_flags,
|
||||||
|
&themarr, &bindarr, &bindport, &needbind, &lowport);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case STAT_OK: break;
|
case STAT_OK: break;
|
||||||
#if WITH_RETRY
|
#if WITH_RETRY
|
||||||
case STAT_RETRYLATER:
|
case STAT_RETRYLATER:
|
||||||
case STAT_RETRYNOW:
|
case STAT_RETRYNOW:
|
||||||
if (sfd->forever || sfd->retry) {
|
if (sfd->forever || sfd->retry--) {
|
||||||
--sfd->retry;
|
|
||||||
if (result == STAT_RETRYLATER)
|
if (result == STAT_RETRYLATER)
|
||||||
Nanosleep(&sfd->intervall, NULL);
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||||
|
xiofreeaddrinfo(themarr);
|
||||||
|
freeopts(opts);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif /* WITH_RETRY */
|
#endif /* WITH_RETRY */
|
||||||
default:
|
/* FALLTHROUGH */
|
||||||
|
case STAT_NORETRY:
|
||||||
|
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||||
xiofreeaddrinfo(themarr);
|
xiofreeaddrinfo(themarr);
|
||||||
|
freeopts(opts);
|
||||||
|
freeopts(opts0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
xiofreeaddrinfo(themarr);
|
|
||||||
applyopts(sfd, -1, opts, PH_ALL);
|
|
||||||
|
|
||||||
if ((result = _xio_openlate(sfd, opts)) < 0)
|
result =
|
||||||
|
_xioopen_proxy_prepare(proxyvars, opts, targetname, targetport,
|
||||||
|
sfd->para.socket.ip.ai_flags);
|
||||||
|
switch (result) {
|
||||||
|
case STAT_OK: break;
|
||||||
|
#if WITH_RETRY
|
||||||
|
case STAT_RETRYLATER:
|
||||||
|
case STAT_RETRYNOW:
|
||||||
|
if (sfd->forever || sfd->retry--) {
|
||||||
|
if (result == STAT_RETRYLATER)
|
||||||
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||||
|
xiofreeaddrinfo(themarr);
|
||||||
|
freeopts(opts);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif /* WITH_RETRY */
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
default:
|
||||||
|
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||||
|
xiofreeaddrinfo(themarr);
|
||||||
|
freeopts(opts);
|
||||||
|
freeopts(opts0);
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Notice2("opening connection to proxy %s:%s", proxyname, proxyport);
|
||||||
|
result =
|
||||||
|
_xioopen_ipapp_connect(sfd, proxyname, opts, themarr,
|
||||||
|
needbind, bindarr, bindport, lowport, level);
|
||||||
|
_errno = errno;
|
||||||
|
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||||
|
xiofreeaddrinfo(themarr);
|
||||||
|
switch (result) {
|
||||||
|
case STAT_OK: break;
|
||||||
|
#if WITH_RETRY
|
||||||
|
case STAT_RETRYLATER:
|
||||||
|
case STAT_RETRYNOW:
|
||||||
|
if (sfd->forever || sfd->retry--) {
|
||||||
|
if (result == STAT_RETRYLATER)
|
||||||
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
freeopts(opts);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif /* WITH_RETRY */
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
default:
|
||||||
|
Error4("%s:%s:...,proxyport=%s: %s", argv[0], proxyname, proxyport,
|
||||||
|
_errno?strerror(_errno):"(See above)");
|
||||||
|
freeopts(opts0);
|
||||||
|
freeopts(opts);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
result = _xioopen_proxy_connect(sfd, proxyvars, level);
|
result = _xioopen_proxy_connect(sfd, proxyvars, level);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
@ -204,11 +237,16 @@ static int xioopen_proxy_connect(
|
||||||
case STAT_RETRYLATER:
|
case STAT_RETRYLATER:
|
||||||
case STAT_RETRYNOW:
|
case STAT_RETRYNOW:
|
||||||
if (sfd->forever || sfd->retry--) {
|
if (sfd->forever || sfd->retry--) {
|
||||||
if (result == STAT_RETRYLATER) Nanosleep(&sfd->intervall, NULL);
|
if (result == STAT_RETRYLATER)
|
||||||
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
freeopts(opts);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif /* WITH_RETRY */
|
#endif /* WITH_RETRY */
|
||||||
|
/* FALLTHROUGH */
|
||||||
default:
|
default:
|
||||||
|
freeopts(opts);
|
||||||
|
freeopts(opts0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,21 +263,32 @@ static int xioopen_proxy_connect(
|
||||||
}
|
}
|
||||||
while ((pid = xio_fork(false, level, sfd->shutup)) < 0) {
|
while ((pid = xio_fork(false, level, sfd->shutup)) < 0) {
|
||||||
if (sfd->forever || --sfd->retry) {
|
if (sfd->forever || --sfd->retry) {
|
||||||
Nanosleep(&sfd->intervall, NULL); continue;
|
if (sfd->retry > 0)
|
||||||
|
--sfd->retry;
|
||||||
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
freeopts(opts);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
freeopts(opts);
|
||||||
|
freeopts(opts0);
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pid == 0) { /* child process */
|
if (pid == 0) { /* child process */
|
||||||
sfd->forever = false; sfd->retry = 0;
|
sfd->forever = false;
|
||||||
|
sfd->retry = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parent process */
|
/* parent process */
|
||||||
Close(sfd->fd);
|
Close(sfd->fd);
|
||||||
|
/* With and without retry */
|
||||||
Nanosleep(&sfd->intervall, NULL);
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
dropopts(opts, PH_ALL);
|
while (maxchildren > 0 && num_child >= maxchildren) {
|
||||||
opts = copyopts(opts0, GROUP_ALL);
|
Info1("all %d allowed children are active, waiting", maxchildren);
|
||||||
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
}
|
||||||
|
freeopts(opts);
|
||||||
continue;
|
continue;
|
||||||
} else
|
} else
|
||||||
#endif /* WITH_RETRY */
|
#endif /* WITH_RETRY */
|
||||||
|
@ -248,25 +297,25 @@ static int xioopen_proxy_connect(
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (true); /* end of complete open loop - drop out on success */
|
} while (true); /* end of complete open loop - drop out on success */
|
||||||
|
/* Only "active" process breaks (master without fork, or child) */
|
||||||
|
|
||||||
Notice4("successfully connected to %s:%u via proxy %s:%s",
|
Notice4("successfully connected to %s:%u via proxy %s:%s",
|
||||||
proxyvars->targetaddr, proxyvars->targetport,
|
proxyvars->targetaddr, proxyvars->targetport,
|
||||||
proxyname, proxyport);
|
proxyname, proxyport);
|
||||||
|
|
||||||
return 0;
|
result = _xio_openlate(sfd, opts);
|
||||||
|
freeopts(opts);
|
||||||
|
freeopts(opts0);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int _xioopen_proxy_prepare(
|
int _xioopen_proxy_init(
|
||||||
struct proxyvars *proxyvars,
|
struct proxyvars *proxyvars,
|
||||||
struct opt *opts,
|
struct opt *opts,
|
||||||
const char *targetname,
|
const char *targetname,
|
||||||
const char *targetport,
|
const char *targetport)
|
||||||
const int ai_flags[2]) {
|
{
|
||||||
union sockaddr_union host;
|
|
||||||
socklen_t socklen = sizeof(host);
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
retropt_bool(opts, OPT_IGNORECR, &proxyvars->ignorecr);
|
retropt_bool(opts, OPT_IGNORECR, &proxyvars->ignorecr);
|
||||||
retropt_bool(opts, OPT_PROXY_RESOLVE, &proxyvars->doresolve);
|
retropt_bool(opts, OPT_PROXY_RESOLVE, &proxyvars->doresolve);
|
||||||
retropt_string(opts, OPT_HTTP_VERSION, &proxyvars->version);
|
retropt_string(opts, OPT_HTTP_VERSION, &proxyvars->version);
|
||||||
|
@ -316,6 +365,28 @@ int _xioopen_proxy_prepare(
|
||||||
Close(authfd);
|
Close(authfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!proxyvars->doresolve) {
|
||||||
|
proxyvars->targetaddr = strdup(targetname);
|
||||||
|
if (proxyvars->targetaddr == NULL) {
|
||||||
|
Error1("strdup(\"%s\"): out of memory", targetname);
|
||||||
|
return STAT_RETRYLATER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return STAT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _xioopen_proxy_prepare(
|
||||||
|
struct proxyvars *proxyvars,
|
||||||
|
struct opt *opts,
|
||||||
|
const char *targetname,
|
||||||
|
const char *targetport,
|
||||||
|
const int ai_flags[2])
|
||||||
|
{
|
||||||
|
union sockaddr_union host;
|
||||||
|
socklen_t socklen = sizeof(host);
|
||||||
|
int rc;
|
||||||
|
|
||||||
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
|
||||||
|
@ -325,6 +396,10 @@ int _xioopen_proxy_prepare(
|
||||||
&host, &socklen, ai_flags);
|
&host, &socklen, ai_flags);
|
||||||
if (rc != STAT_OK) {
|
if (rc != STAT_OK) {
|
||||||
proxyvars->targetaddr = strdup(targetname);
|
proxyvars->targetaddr = strdup(targetname);
|
||||||
|
if (proxyvars->targetaddr == NULL) {
|
||||||
|
Error1("strdup(\"%s\"): out of memory", targetname);
|
||||||
|
return STAT_RETRYLATER;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
#define LEN 16 /* www.xxx.yyy.zzz\0 */
|
#define LEN 16 /* www.xxx.yyy.zzz\0 */
|
||||||
if ((proxyvars->targetaddr = Malloc(LEN)) == NULL) {
|
if ((proxyvars->targetaddr = Malloc(LEN)) == NULL) {
|
||||||
|
@ -337,8 +412,6 @@ int _xioopen_proxy_prepare(
|
||||||
((unsigned char *)&host.ip4.sin_addr.s_addr)[3]);
|
((unsigned char *)&host.ip4.sin_addr.s_addr)[3]);
|
||||||
#undef LEN
|
#undef LEN
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
proxyvars->targetaddr = strdup(targetname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
proxyvars->targetport = htons(parseport(targetport, IPPROTO_TCP));
|
proxyvars->targetport = htons(parseport(targetport, IPPROTO_TCP));
|
||||||
|
|
|
@ -25,9 +25,8 @@ extern const struct optdesc opt_proxy_authorization_file;
|
||||||
|
|
||||||
extern const struct addrdesc xioaddr_proxy_connect;
|
extern const struct addrdesc xioaddr_proxy_connect;
|
||||||
|
|
||||||
|
extern int _xioopen_proxy_init(struct proxyvars *proxyvars, struct opt *opts, const char *targetname, const char *targetport);
|
||||||
extern int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts, const char *targetname, const char *targetport, const int ai_flags[2]);
|
extern int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts, const char *targetname, const char *targetport, const int ai_flags[2]);
|
||||||
int _xioopen_proxy_connect(struct single *xfd,
|
extern int _xioopen_proxy_connect(struct single *xfd, struct proxyvars *proxyvars, int level);
|
||||||
struct proxyvars *proxyvars,
|
|
||||||
int level);
|
|
||||||
|
|
||||||
#endif /* !defined(__xio_proxy_h_included) */
|
#endif /* !defined(__xio_proxy_h_included) */
|
||||||
|
|
40
xio-socket.c
40
xio-socket.c
|
@ -805,7 +805,7 @@ int xiogetpacketinfo(struct single *sfd, int fd)
|
||||||
with IP sockets: lowport (selects randomly a free port from 640 to 1023)
|
with IP sockets: lowport (selects randomly a free port from 640 to 1023)
|
||||||
with UNIX and abstract sockets: uses tmpname() to find a free file system
|
with UNIX and abstract sockets: uses tmpname() to find a free file system
|
||||||
entry.
|
entry.
|
||||||
returns 0 on success.
|
Returns STAT_OK on success, or STAT_RETRYLATER (+errno) on failure.
|
||||||
*/
|
*/
|
||||||
int _xioopen_connect(struct single *sfd, union sockaddr_union *us, size_t uslen,
|
int _xioopen_connect(struct single *sfd, union sockaddr_union *us, size_t uslen,
|
||||||
struct sockaddr *them, size_t themlen,
|
struct sockaddr *them, size_t themlen,
|
||||||
|
@ -835,7 +835,7 @@ int _xioopen_connect(struct single *sfd, union sockaddr_union *us, size_t uslen,
|
||||||
applyopts_cloexec(sfd->fd, opts);
|
applyopts_cloexec(sfd->fd, opts);
|
||||||
|
|
||||||
if (xiobind(sfd, us, uslen, opts, pf, alt, level) < 0) {
|
if (xiobind(sfd, us, uslen, opts, pf, alt, level) < 0) {
|
||||||
return -1;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyopts(sfd, -1, opts, PH_CONNECT);
|
applyopts(sfd, -1, opts, PH_CONNECT);
|
||||||
|
@ -875,6 +875,7 @@ int _xioopen_connect(struct single *sfd, union sockaddr_union *us, size_t uslen,
|
||||||
Msg4(level, "xiopoll({%d,POLLOUT|POLLERR},,{"F_tv_sec"."F_tv_usec"): %s",
|
Msg4(level, "xiopoll({%d,POLLOUT|POLLERR},,{"F_tv_sec"."F_tv_usec"): %s",
|
||||||
sfd->fd, timeout.tv_sec, timeout.tv_usec, strerror(errno));
|
sfd->fd, timeout.tv_sec, timeout.tv_usec, strerror(errno));
|
||||||
Close(sfd->fd);
|
Close(sfd->fd);
|
||||||
|
errno = _errno;
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
|
@ -882,6 +883,7 @@ int _xioopen_connect(struct single *sfd, union sockaddr_union *us, size_t uslen,
|
||||||
sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
||||||
strerror(ETIMEDOUT));
|
strerror(ETIMEDOUT));
|
||||||
Close(sfd->fd);
|
Close(sfd->fd);
|
||||||
|
errno = _errno;
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
if (writefd.revents & POLLERR) {
|
if (writefd.revents & POLLERR) {
|
||||||
|
@ -897,15 +899,19 @@ int _xioopen_connect(struct single *sfd, union sockaddr_union *us, size_t uslen,
|
||||||
sfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
sfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
||||||
themlen, strerror(errno));
|
themlen, strerror(errno));
|
||||||
#endif
|
#endif
|
||||||
|
_errno = errno;
|
||||||
Close(sfd->fd);
|
Close(sfd->fd);
|
||||||
|
errno = _errno;
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
/* otherwise OK or network error */
|
/* otherwise OK or network error */
|
||||||
result = Getsockopt(sfd->fd, SOL_SOCKET, SO_ERROR, &err, &errlen);
|
result = Getsockopt(sfd->fd, SOL_SOCKET, SO_ERROR, &err, &errlen);
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
|
_errno = errno;
|
||||||
Msg2(level, "getsockopt(%d, SOL_SOCKET, SO_ERROR, ...): %s",
|
Msg2(level, "getsockopt(%d, SOL_SOCKET, SO_ERROR, ...): %s",
|
||||||
sfd->fd, strerror(err));
|
sfd->fd, strerror(err));
|
||||||
Close(sfd->fd);
|
Close(sfd->fd);
|
||||||
|
errno = _errno;
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
Debug2("getsockopt(%d, SOL_SOCKET, SO_ERROR, { %d }) -> 0",
|
Debug2("getsockopt(%d, SOL_SOCKET, SO_ERROR, { %d }) -> 0",
|
||||||
|
@ -915,6 +921,7 @@ int _xioopen_connect(struct single *sfd, union sockaddr_union *us, size_t uslen,
|
||||||
sfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
sfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
||||||
themlen, strerror(err));
|
themlen, strerror(err));
|
||||||
Close(sfd->fd);
|
Close(sfd->fd);
|
||||||
|
errno = err;
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
Fcntl_l(sfd->fd, F_SETFL, fcntl_flags);
|
Fcntl_l(sfd->fd, F_SETFL, fcntl_flags);
|
||||||
|
@ -945,6 +952,7 @@ int _xioopen_connect(struct single *sfd, union sockaddr_union *us, size_t uslen,
|
||||||
sfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
sfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
||||||
themlen, strerror(errno));
|
themlen, strerror(errno));
|
||||||
Close(sfd->fd);
|
Close(sfd->fd);
|
||||||
|
errno = _errno;
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
} else { /* result >= 0 */
|
} else { /* result >= 0 */
|
||||||
|
@ -1679,9 +1687,7 @@ int xiocheckrange(union sockaddr_union *sa, struct xiorange *range) {
|
||||||
int xiocheckpeer(xiosingle_t *sfd,
|
int xiocheckpeer(xiosingle_t *sfd,
|
||||||
union sockaddr_union *pa, union sockaddr_union *la) {
|
union sockaddr_union *pa, union sockaddr_union *la) {
|
||||||
char infobuff[256];
|
char infobuff[256];
|
||||||
#if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP
|
|
||||||
int result;
|
int result;
|
||||||
#endif
|
|
||||||
|
|
||||||
#if WITH_IP4 || WITH_IP6
|
#if WITH_IP4 || WITH_IP6
|
||||||
if (sfd->para.socket.dorange) {
|
if (sfd->para.socket.dorange) {
|
||||||
|
@ -2091,9 +2097,8 @@ int xiosetsockaddrenv(const char *lr,
|
||||||
|
|
||||||
/* retrieves options so-type and so-prototype from opts, calls socket, and
|
/* retrieves options so-type and so-prototype from opts, calls socket, and
|
||||||
ev. generates an appropriate error message.
|
ev. generates an appropriate error message.
|
||||||
returns 0 on success or -1 if an error occurred. */
|
returns 0 on success or -1 (and errno) if an error occurred. */
|
||||||
int
|
int xiosocket(struct opt *opts, int pf, int socktype, int proto, int msglevel) {
|
||||||
xiosocket(struct opt *opts, int pf, int socktype, int proto, int msglevel) {
|
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
retropt_int(opts, OPT_SO_TYPE, &socktype);
|
retropt_int(opts, OPT_SO_TYPE, &socktype);
|
||||||
|
@ -2118,6 +2123,7 @@ xiosocket(struct opt *opts, int pf, int socktype, int proto, int msglevel) {
|
||||||
with IP sockets: lowport (selects randomly a free port from 640 to 1023)
|
with IP sockets: lowport (selects randomly a free port from 640 to 1023)
|
||||||
with UNIX and abstract sockets: uses a method similar to tmpname() to
|
with UNIX and abstract sockets: uses a method similar to tmpname() to
|
||||||
find a free file system entry.
|
find a free file system entry.
|
||||||
|
On success returns STAT_OK, otherwise errno is set.
|
||||||
*/
|
*/
|
||||||
int xiobind(
|
int xiobind(
|
||||||
struct single *sfd,
|
struct single *sfd,
|
||||||
|
@ -2154,18 +2160,20 @@ int xiobind(
|
||||||
usrname = strndup(us->un.sun_path, sizeof(us->un.sun_path));
|
usrname = strndup(us->un.sun_path, sizeof(us->un.sun_path));
|
||||||
if (usrname == NULL) {
|
if (usrname == NULL) {
|
||||||
int _errno = errno;
|
int _errno = errno;
|
||||||
Error2("strndup(\"%s\", "F_Zu"): out of memory",
|
Msg2(level, "strndup(\"%s\", "F_Zu"): out of memory",
|
||||||
us->un.sun_path, sizeof(us->un.sun_path));
|
us->un.sun_path, sizeof(us->un.sun_path));
|
||||||
errno = _errno;
|
errno = _errno;
|
||||||
return -1;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
do { /* loop over tempnam bind() attempts */
|
do { /* loop over tempnam bind() attempts */
|
||||||
sockname = xio_tempnam(usrname, abstract);
|
sockname = xio_tempnam(usrname, abstract);
|
||||||
if (sockname == NULL) {
|
if (sockname == NULL) {
|
||||||
|
int _errno = errno;
|
||||||
Error2("tempnam(\"%s\"): %s", usrname, strerror(errno));
|
Error2("tempnam(\"%s\"): %s", usrname, strerror(errno));
|
||||||
free(usrname);
|
free(usrname);
|
||||||
|
errno = _errno;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
strncpy(us->un.sun_path+(abstract?1:0), sockname, sizeof(us->un.sun_path));
|
strncpy(us->un.sun_path+(abstract?1:0), sockname, sizeof(us->un.sun_path));
|
||||||
|
@ -2179,8 +2187,10 @@ int xiobind(
|
||||||
infobuff, sizeof(infobuff)),
|
infobuff, sizeof(infobuff)),
|
||||||
uslen, strerror(errno));
|
uslen, strerror(errno));
|
||||||
if (errno != EADDRINUSE) {
|
if (errno != EADDRINUSE) {
|
||||||
|
int _errno = errno;
|
||||||
free(usrname);
|
free(usrname);
|
||||||
Close(sfd->fd);
|
Close(sfd->fd);
|
||||||
|
errno = _errno;
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -2193,10 +2203,12 @@ int xiobind(
|
||||||
|
|
||||||
if (us != NULL) {
|
if (us != NULL) {
|
||||||
if (Bind(sfd->fd, &us->soa, uslen) < 0) {
|
if (Bind(sfd->fd, &us->soa, uslen) < 0) {
|
||||||
|
int _errno = errno;
|
||||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
|
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
|
||||||
sfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
|
sfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
|
||||||
uslen, strerror(errno));
|
uslen, strerror(errno));
|
||||||
Close(sfd->fd);
|
Close(sfd->fd);
|
||||||
|
errno = _errno;
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
|
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
|
||||||
|
@ -2268,12 +2280,14 @@ int xiobind(
|
||||||
do { /* loop over lowport bind() attempts */
|
do { /* loop over lowport bind() attempts */
|
||||||
*port = htons(i);
|
*port = htons(i);
|
||||||
if (Bind(sfd->fd, &sinp->soa, sizeof(*sinp)) < 0) {
|
if (Bind(sfd->fd, &sinp->soa, sizeof(*sinp)) < 0) {
|
||||||
|
int _errno = errno;
|
||||||
Msg4(errno==EADDRINUSE?E_INFO:level,
|
Msg4(errno==EADDRINUSE?E_INFO:level,
|
||||||
"bind(%d, {%s}, "F_Zd"): %s", sfd->fd,
|
"bind(%d, {%s}, "F_Zd"): %s", sfd->fd,
|
||||||
sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)),
|
sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)),
|
||||||
sizeof(*sinp), strerror(errno));
|
sizeof(*sinp), strerror(errno));
|
||||||
if (errno != EADDRINUSE) {
|
if (_errno != EADDRINUSE) {
|
||||||
Close(sfd->fd);
|
Close(sfd->fd);
|
||||||
|
errno = _errno;
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -2282,8 +2296,8 @@ int xiobind(
|
||||||
--i; if (i < XIO_IPPORT_LOWER) i = IPPORT_RESERVED-1;
|
--i; if (i < XIO_IPPORT_LOWER) i = IPPORT_RESERVED-1;
|
||||||
if (i == N) {
|
if (i == N) {
|
||||||
Msg(level, "no low port available");
|
Msg(level, "no low port available");
|
||||||
/*errno = EADDRINUSE; still assigned */
|
|
||||||
Close(sfd->fd);
|
Close(sfd->fd);
|
||||||
|
errno = EADDRINUSE;
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
} while (i != N);
|
} while (i != N);
|
||||||
|
@ -2294,17 +2308,19 @@ int xiobind(
|
||||||
if (us) {
|
if (us) {
|
||||||
applyopts(sfd, sfd->fd, opts, PH_BIND);
|
applyopts(sfd, sfd->fd, opts, PH_BIND);
|
||||||
if (Bind(sfd->fd, &us->soa, uslen) < 0) {
|
if (Bind(sfd->fd, &us->soa, uslen) < 0) {
|
||||||
|
int _errno = errno;
|
||||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
|
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
|
||||||
sfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
|
sfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
|
||||||
uslen, strerror(errno));
|
uslen, strerror(errno));
|
||||||
Close(sfd->fd);
|
Close(sfd->fd);
|
||||||
|
errno = _errno;
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
applyopts(sfd, -1, opts, PH_PASTBIND);
|
applyopts(sfd, -1, opts, PH_PASTBIND);
|
||||||
return 0;
|
return STAT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handles the SO_REUSEADDR socket option for TCP LISTEN addresses depending on
|
/* Handles the SO_REUSEADDR socket option for TCP LISTEN addresses depending on
|
||||||
|
|
205
xio-socks.c
205
xio-socks.c
|
@ -54,13 +54,12 @@ static int xioopen_socks4_connect(
|
||||||
int pf = PF_UNSPEC;
|
int pf = PF_UNSPEC;
|
||||||
int ipproto = IPPROTO_TCP;
|
int ipproto = IPPROTO_TCP;
|
||||||
bool dofork = false;
|
bool dofork = false;
|
||||||
union sockaddr_union us_sa, *us = &us_sa;
|
int maxchildren = 0;
|
||||||
socklen_t uslen = sizeof(us_sa);
|
struct addrinfo **bindarr = NULL;
|
||||||
struct addrinfo **themarr, *themp;
|
struct addrinfo **themarr = NULL;
|
||||||
int i;
|
uint16_t bindport = 0;
|
||||||
bool needbind = false;
|
bool needbind = false;
|
||||||
bool lowport = false;
|
bool lowport = false;
|
||||||
char infobuff[256];
|
|
||||||
unsigned char buff[BUFF_LEN];
|
unsigned char buff[BUFF_LEN];
|
||||||
struct socks4 *sockhead = (struct socks4 *)buff;
|
struct socks4 *sockhead = (struct socks4 *)buff;
|
||||||
size_t buflen = sizeof(buff);
|
size_t buflen = sizeof(buff);
|
||||||
|
@ -76,41 +75,43 @@ static int xioopen_socks4_connect(
|
||||||
targetname = argv[2];
|
targetname = argv[2];
|
||||||
targetport = argv[3];
|
targetport = argv[3];
|
||||||
|
|
||||||
if (sfd->howtoend == END_UNSPEC)
|
/* Apply and retrieve some options */
|
||||||
sfd->howtoend = END_SHUTDOWN;
|
result = _xioopen_ipapp_init(sfd, xioflags, opts,
|
||||||
if (applyopts_single(sfd, opts, PH_INIT) < 0) return -1;
|
&dofork, &maxchildren,
|
||||||
applyopts(sfd, 1, opts, PH_INIT);
|
&pf, &socktype, &ipproto);
|
||||||
|
|
||||||
retropt_int(opts, OPT_SO_TYPE, &socktype);
|
|
||||||
|
|
||||||
retropt_bool(opts, OPT_FORK, &dofork);
|
|
||||||
|
|
||||||
result = _xioopen_socks4_prepare(targetport, opts, &socksport, sockhead, &buflen);
|
|
||||||
if (result != STAT_OK)
|
if (result != STAT_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
result = _xioopen_socks4_init(targetport, opts, &socksport, sockhead,
|
||||||
|
&buflen);
|
||||||
|
if (result != STAT_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
opts0 = opts; /* save remaining options for each loop */
|
||||||
|
opts = NULL;
|
||||||
|
|
||||||
Notice5("opening connection to %s:%u via socks4 server %s:%s as user \"%s\"",
|
Notice5("opening connection to %s:%u via socks4 server %s:%s as user \"%s\"",
|
||||||
targetname,
|
targetname, ntohs(sockhead->port),
|
||||||
ntohs(sockhead->port),
|
|
||||||
sockdname, socksport, sockhead->userid);
|
sockdname, socksport, sockhead->userid);
|
||||||
|
|
||||||
i = 0;
|
do { /* loop over retries (failed connect and socks-request attempts)
|
||||||
do { /* loop over retries (failed connect and socks-request attempts) */
|
and/or forks */
|
||||||
|
int _errno;
|
||||||
|
|
||||||
level = E_INFO;
|
#if WITH_RETRY
|
||||||
|
if (sfd->forever || sfd->retry) {
|
||||||
|
level = E_NOTICE;
|
||||||
|
} else
|
||||||
|
#endif /* WITH_RETRY */
|
||||||
|
level = E_WARN;
|
||||||
|
|
||||||
|
opts = copyopts(opts0, GROUP_ALL);
|
||||||
|
|
||||||
result =
|
result =
|
||||||
_xioopen_ipapp_prepare(opts, &opts0, sockdname, socksport,
|
_xioopen_ipapp_prepare(&opts, opts0, sockdname, socksport,
|
||||||
&pf, ipproto,
|
pf, socktype, ipproto,
|
||||||
sfd->para.socket.ip.ai_flags,
|
sfd->para.socket.ip.ai_flags,
|
||||||
&themarr, us, &uslen,
|
&themarr, &bindarr, &bindport, &needbind, &lowport);
|
||||||
&needbind, &lowport, socktype);
|
|
||||||
|
|
||||||
/* we try to resolve the target address _before_ connecting to the socks
|
|
||||||
server: this avoids unnecessary socks connects and timeouts */
|
|
||||||
result =
|
|
||||||
_xioopen_socks4_connect0(sfd, targetname, socks4a, sockhead,
|
|
||||||
(ssize_t *)&buflen, level);
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case STAT_OK: break;
|
case STAT_OK: break;
|
||||||
#if WITH_RETRY
|
#if WITH_RETRY
|
||||||
|
@ -119,60 +120,78 @@ static int xioopen_socks4_connect(
|
||||||
if (sfd->forever || sfd->retry--) {
|
if (sfd->forever || sfd->retry--) {
|
||||||
if (result == STAT_RETRYLATER)
|
if (result == STAT_RETRYLATER)
|
||||||
Nanosleep(&sfd->intervall, NULL);
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||||
|
xiofreeaddrinfo(themarr);
|
||||||
|
freeopts(opts);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif /* WITH_RETRY */
|
#endif /* WITH_RETRY */
|
||||||
default:
|
/* FALLTHROUGH */
|
||||||
|
case STAT_NORETRY:
|
||||||
|
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||||
|
xiofreeaddrinfo(themarr);
|
||||||
|
freeopts(opts);
|
||||||
|
freeopts(opts0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* loop over themarr */
|
/* we try to resolve the target address _before_ connecting to the socks
|
||||||
i = 0;
|
server: this may avoid unnecessary connects and timeouts */
|
||||||
themp = themarr[i++];
|
result =
|
||||||
while (themp != NULL) {
|
_xioopen_socks4_prepare(sfd, targetname, socks4a, sockhead,
|
||||||
Notice1("opening connection to %s",
|
(ssize_t *)&buflen, level);
|
||||||
sockaddr_info(themp->ai_addr, themp->ai_addrlen,
|
|
||||||
infobuff, sizeof(infobuff)));
|
|
||||||
#if WITH_RETRY
|
|
||||||
if (sfd->forever || sfd->retry || themarr[i] != NULL) {
|
|
||||||
level = E_INFO;
|
|
||||||
} else
|
|
||||||
#endif /* WITH_RETRY */
|
|
||||||
level = E_ERROR;
|
|
||||||
|
|
||||||
/* this cannot fork because we retrieved fork option above */
|
|
||||||
result =
|
|
||||||
_xioopen_connect(sfd,
|
|
||||||
needbind?us:NULL, uslen,
|
|
||||||
themp->ai_addr, themp->ai_addrlen,
|
|
||||||
opts, pf?pf:themp->ai_family, socktype, IPPROTO_TCP, lowport, level);
|
|
||||||
if (result == STAT_OK)
|
|
||||||
break;
|
|
||||||
themp = themarr[i++];
|
|
||||||
if (themp == NULL)
|
|
||||||
result = STAT_RETRYLATER;
|
|
||||||
}
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case STAT_OK: break;
|
case STAT_OK: break;
|
||||||
#if WITH_RETRY
|
#if WITH_RETRY
|
||||||
case STAT_RETRYLATER:
|
case STAT_RETRYLATER:
|
||||||
case STAT_RETRYNOW:
|
case STAT_RETRYNOW:
|
||||||
if (sfd->forever || sfd->retry) {
|
if (sfd->forever || sfd->retry--) {
|
||||||
--sfd->retry;
|
|
||||||
if (result == STAT_RETRYLATER)
|
if (result == STAT_RETRYLATER)
|
||||||
Nanosleep(&sfd->intervall, NULL);
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||||
|
xiofreeaddrinfo(themarr);
|
||||||
|
freeopts(opts);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif /* WITH_RETRY */
|
#endif /* WITH_RETRY */
|
||||||
|
/* FALLTHROUGH */
|
||||||
default:
|
default:
|
||||||
|
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||||
xiofreeaddrinfo(themarr);
|
xiofreeaddrinfo(themarr);
|
||||||
|
freeopts(opts);
|
||||||
|
freeopts(opts0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
xiofreeaddrinfo(themarr);
|
|
||||||
applyopts(sfd, -1, opts, PH_ALL);
|
|
||||||
|
|
||||||
if ((result = _xio_openlate(sfd, opts)) < 0)
|
Notice2("opening connection to sockd %s:%s", sockdname, socksport);
|
||||||
|
result =
|
||||||
|
_xioopen_ipapp_connect(sfd, sockdname, opts, themarr,
|
||||||
|
needbind, bindarr, bindport, lowport, level);
|
||||||
|
_errno = errno;
|
||||||
|
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||||
|
xiofreeaddrinfo(themarr);
|
||||||
|
switch (result) {
|
||||||
|
case STAT_OK: break;
|
||||||
|
#if WITH_RETRY
|
||||||
|
case STAT_RETRYLATER:
|
||||||
|
case STAT_RETRYNOW:
|
||||||
|
if (sfd->forever || sfd->retry--) {
|
||||||
|
if (result == STAT_RETRYLATER) {
|
||||||
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
}
|
||||||
|
freeopts(opts);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif /* WITH_RETRY */
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
default:
|
||||||
|
errno = _errno;
|
||||||
|
Error4("%s:%s:...,socksport=%s: %s", argv[0], sockdname, socksport,
|
||||||
|
_errno?strerror(_errno):"(See above)");
|
||||||
|
freeopts(opts0);
|
||||||
|
freeopts(opts);
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
result = _xioopen_socks4_connect(sfd, sockhead, buflen, level);
|
result = _xioopen_socks4_connect(sfd, sockhead, buflen, level);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
@ -181,11 +200,16 @@ static int xioopen_socks4_connect(
|
||||||
case STAT_RETRYLATER:
|
case STAT_RETRYLATER:
|
||||||
case STAT_RETRYNOW:
|
case STAT_RETRYNOW:
|
||||||
if (sfd->forever || sfd->retry--) {
|
if (sfd->forever || sfd->retry--) {
|
||||||
if (result == STAT_RETRYLATER) Nanosleep(&sfd->intervall, NULL);
|
if (result == STAT_RETRYLATER)
|
||||||
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
freeopts(opts);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif /* WITH_RETRY */
|
#endif /* WITH_RETRY */
|
||||||
|
/* FALLTHROUGH */
|
||||||
default:
|
default:
|
||||||
|
freeopts(opts);
|
||||||
|
freeopts(opts0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,10 +226,13 @@ static int xioopen_socks4_connect(
|
||||||
so Notice is too weak */
|
so Notice is too weak */
|
||||||
}
|
}
|
||||||
while ((pid = xio_fork(false, level, sfd->shutup)) < 0) {
|
while ((pid = xio_fork(false, level, sfd->shutup)) < 0) {
|
||||||
if (sfd->forever || --sfd->retry) {
|
if (sfd->forever || sfd->retry--) {
|
||||||
Nanosleep(&sfd->intervall, NULL);
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
freeopts(opts);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
freeopts(opts);
|
||||||
|
freeopts(opts0);
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,8 +244,13 @@ static int xioopen_socks4_connect(
|
||||||
|
|
||||||
/* parent process */
|
/* parent process */
|
||||||
Close(sfd->fd);
|
Close(sfd->fd);
|
||||||
|
/* with and without retry */
|
||||||
Nanosleep(&sfd->intervall, NULL);
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
|
while (maxchildren > 0 && num_child >= maxchildren) {
|
||||||
|
Info1("all %d allowed children are active, waiting", maxchildren);
|
||||||
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
}
|
||||||
|
freeopts(opts);
|
||||||
continue;
|
continue;
|
||||||
} else
|
} else
|
||||||
#endif /* WITH_RETRY */
|
#endif /* WITH_RETRY */
|
||||||
|
@ -227,7 +259,15 @@ static int xioopen_socks4_connect(
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (true); /* end of complete open loop - drop out on success */
|
} while (true); /* end of complete open loop - drop out on success */
|
||||||
return 0;
|
/* only "active" process breaks (master without fork, or child) */
|
||||||
|
|
||||||
|
Notice4("successfully connected to %s:%s via sockd %s:%s",
|
||||||
|
targetname, targetport, sockdname, socksport);
|
||||||
|
|
||||||
|
result = _xio_openlate(sfd, opts);
|
||||||
|
freeopts(opts);
|
||||||
|
freeopts(opts0);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* WITH_SOCKS4 || WITH_SOCKS4A */
|
#endif /* WITH_SOCKS4 || WITH_SOCKS4A */
|
||||||
|
@ -260,7 +300,13 @@ int _xioopen_opt_socksport(
|
||||||
#endif /* WITH_SOCKS4 || WITH_SOCKS4A || WITH_SOCKS5 */
|
#endif /* WITH_SOCKS4 || WITH_SOCKS4A || WITH_SOCKS5 */
|
||||||
#if WITH_SOCKS4 || WITH_SOCKS4A
|
#if WITH_SOCKS4 || WITH_SOCKS4A
|
||||||
|
|
||||||
int _xioopen_socks4_prepare(const char *targetport, struct opt *opts, char **socksport, struct socks4 *sockhead, size_t *headlen) {
|
int _xioopen_socks4_init(
|
||||||
|
const char *targetport,
|
||||||
|
struct opt *opts,
|
||||||
|
char **socksport,
|
||||||
|
struct socks4 *sockhead,
|
||||||
|
size_t *headlen)
|
||||||
|
{
|
||||||
char *userid;
|
char *userid;
|
||||||
|
|
||||||
/* generate socks header - points to final target */
|
/* generate socks header - points to final target */
|
||||||
|
@ -286,14 +332,14 @@ int _xioopen_socks4_prepare(const char *targetport, struct opt *opts, char **soc
|
||||||
|
|
||||||
|
|
||||||
/* called within retry/fork loop, before connect() */
|
/* called within retry/fork loop, before connect() */
|
||||||
int
|
int _xioopen_socks4_prepare(
|
||||||
_xioopen_socks4_connect0(struct single *sfd,
|
struct single *sfd,
|
||||||
const char *hostname, /* socks target host */
|
const char *hostname, /* socks target host */
|
||||||
int socks4a,
|
int socks4a,
|
||||||
struct socks4 *sockhead,
|
struct socks4 *sockhead,
|
||||||
ssize_t *headlen, /* get available space,
|
ssize_t *headlen, /* get available space, return used length*/
|
||||||
return used length*/
|
int level)
|
||||||
int level) {
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (!socks4a) {
|
if (!socks4a) {
|
||||||
|
@ -435,16 +481,7 @@ int _xioopen_socks4_connect(struct single *sfd,
|
||||||
switch (replyhead->action) {
|
switch (replyhead->action) {
|
||||||
case SOCKS_CD_GRANTED:
|
case SOCKS_CD_GRANTED:
|
||||||
/* Notice("socks: connect request succeeded"); */
|
/* Notice("socks: connect request succeeded"); */
|
||||||
#if 0
|
|
||||||
if (Getsockname(sfd->fd, (struct sockaddr *)&us, &uslen) < 0) {
|
|
||||||
Warn4("getsockname(%d, %p, {%d}): %s",
|
|
||||||
sfd->fd, &us, uslen, strerror(errno));
|
|
||||||
}
|
|
||||||
Notice1("successfully connected from %s via socks4",
|
|
||||||
sockaddr_info((struct sockaddr *)&us, infobuff, sizeof(infobuff)));
|
|
||||||
#else
|
|
||||||
Notice("successfully connected via socks4");
|
Notice("successfully connected via socks4");
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SOCKS_CD_FAILED:
|
case SOCKS_CD_FAILED:
|
||||||
|
|
11
xio-socks.h
11
xio-socks.h
|
@ -21,15 +21,8 @@ extern const struct addrdesc xioaddr_socks4_connect;
|
||||||
extern const struct addrdesc xioaddr_socks4a_connect;
|
extern const struct addrdesc xioaddr_socks4a_connect;
|
||||||
|
|
||||||
extern int _xioopen_opt_socksport(struct opt *opts, char **socksport);
|
extern int _xioopen_opt_socksport(struct opt *opts, char **socksport);
|
||||||
extern int _xioopen_socks4_prepare(const char *targetport, struct opt *opts, char **socksport, struct socks4 *sockhead, size_t *headlen);
|
extern int _xioopen_socks4_init(const char *targetport, struct opt *opts, char **socksport, struct socks4 *sockhead, size_t *headlen);
|
||||||
extern int
|
extern int _xioopen_socks4_prepare(struct single *xfd, const char *hostname, int socks4a, struct socks4 *sockhead, ssize_t *headlen, int level);
|
||||||
_xioopen_socks4_connect0(struct single *xfd,
|
|
||||||
const char *hostname, /* socks target host */
|
|
||||||
int socks4a,
|
|
||||||
struct socks4 *sockhead,
|
|
||||||
ssize_t *headlen, /* get available space,
|
|
||||||
return used length*/
|
|
||||||
int level);
|
|
||||||
extern int _xioopen_socks4_connect(struct single *xfd,
|
extern int _xioopen_socks4_connect(struct single *xfd,
|
||||||
struct socks4 *sockhead,
|
struct socks4 *sockhead,
|
||||||
size_t headlen,
|
size_t headlen,
|
||||||
|
|
184
xio-socks5.c
184
xio-socks5.c
|
@ -512,6 +512,7 @@ static int xioopen_socks5(
|
||||||
{
|
{
|
||||||
int socks_command = addrdesc->arg1;
|
int socks_command = addrdesc->arg1;
|
||||||
bool dofork = false;
|
bool dofork = false;
|
||||||
|
int maxchildren = 0;
|
||||||
int socktype = SOCK_STREAM;
|
int socktype = SOCK_STREAM;
|
||||||
int pf = PF_UNSPEC;
|
int pf = PF_UNSPEC;
|
||||||
int ipproto = IPPROTO_TCP;
|
int ipproto = IPPROTO_TCP;
|
||||||
|
@ -519,12 +520,11 @@ static int xioopen_socks5(
|
||||||
struct opt *opts0 = NULL;
|
struct opt *opts0 = NULL;
|
||||||
struct single *sfd = &xxfd->stream;
|
struct single *sfd = &xxfd->stream;
|
||||||
const char *socks_server, *target_name, *target_port, *socks_port;
|
const char *socks_server, *target_name, *target_port, *socks_port;
|
||||||
union sockaddr_union us_sa, *us = &us_sa;
|
struct addrinfo **bindarr = NULL;
|
||||||
socklen_t uslen = sizeof(us_sa);
|
struct addrinfo **themarr = NULL;
|
||||||
struct addrinfo **themarr, *themp;
|
uint16_t bindport = 0;
|
||||||
bool needbind = false;
|
bool needbind = false;
|
||||||
bool lowport = false;
|
bool lowport = false;
|
||||||
char infobuff[256];
|
|
||||||
|
|
||||||
if (argc < 4 || argc > 5) {
|
if (argc < 4 || argc > 5) {
|
||||||
xio_syntax(argv[0], 4, argc-1, addrdesc->syntax);
|
xio_syntax(argv[0], 4, argc-1, addrdesc->syntax);
|
||||||
|
@ -542,75 +542,115 @@ static int xioopen_socks5(
|
||||||
target_port = argv[3];
|
target_port = argv[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sfd->howtoend == END_UNSPEC)
|
/* Apply and retrieve some options */
|
||||||
sfd->howtoend = END_SHUTDOWN;
|
result = _xioopen_ipapp_init(sfd, xioflags, opts,
|
||||||
if (applyopts_single(sfd, opts, PH_INIT) < 0) return -1;
|
&dofork, &maxchildren,
|
||||||
applyopts(sfd, -1, opts, PH_INIT);
|
&pf, &socktype, &ipproto);
|
||||||
|
if (result != STAT_OK)
|
||||||
retropt_int(opts, OPT_SO_TYPE, &socktype);
|
return result;
|
||||||
retropt_bool(opts, OPT_FORK, &dofork);
|
|
||||||
|
|
||||||
if (_xioopen_opt_socksport(opts, (char **)&socks_port) < 0) {
|
if (_xioopen_opt_socksport(opts, (char **)&socks_port) < 0) {
|
||||||
return STAT_NORETRY;
|
return STAT_NORETRY;
|
||||||
}
|
}
|
||||||
/*! possible memory leak */
|
/*! possible memory leak */
|
||||||
|
|
||||||
result = _xioopen_ipapp_prepare(opts, &opts0, socks_server, socks_port,
|
opts0 = opts;
|
||||||
&pf, ipproto,
|
opts = NULL;
|
||||||
sfd->para.socket.ip.ai_flags,
|
|
||||||
&themarr, us, &uslen,
|
|
||||||
&needbind, &lowport, socktype);
|
|
||||||
|
|
||||||
Notice2("connecting to socks5 server %s:%s",
|
Notice4("opening connection to %s:%s vis socks5 server %s:%s",
|
||||||
socks_server, socks_port);
|
target_name, target_port, socks_server, socks_port);
|
||||||
|
|
||||||
do {
|
do { /* loop over retries (failed connect and socks-request attempts)
|
||||||
|
and/or forks */
|
||||||
|
int _errno;
|
||||||
#if WITH_RETRY
|
#if WITH_RETRY
|
||||||
if (sfd->forever || sfd->retry) {
|
if (sfd->forever || sfd->retry) {
|
||||||
level = E_INFO;
|
level = E_NOTICE;
|
||||||
} else {
|
} else
|
||||||
level = E_ERROR;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
level = E_WARN;
|
||||||
|
|
||||||
/* loop over themarr */
|
opts = copyopts(opts0, GROUP_ALL);
|
||||||
themp = themarr[0];
|
|
||||||
while (themp != NULL) {
|
|
||||||
Notice1("opening connection to %s",
|
|
||||||
sockaddr_info(themp->ai_addr, themp->ai_addrlen,
|
|
||||||
infobuff, sizeof(infobuff)));
|
|
||||||
result = _xioopen_connect(sfd, 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;
|
|
||||||
|
|
||||||
switch(result){
|
result =
|
||||||
break;
|
_xioopen_ipapp_prepare(&opts, opts0, socks_server, socks_port,
|
||||||
|
pf, socktype, ipproto,
|
||||||
|
sfd->para.socket.ip.ai_flags,
|
||||||
|
&themarr, &bindarr, &bindport, &needbind,
|
||||||
|
&lowport);
|
||||||
|
switch (result) {
|
||||||
|
case STAT_OK: break;
|
||||||
#if WITH_RETRY
|
#if WITH_RETRY
|
||||||
case STAT_RETRYLATER:
|
case STAT_RETRYLATER:
|
||||||
case STAT_RETRYNOW:
|
case STAT_RETRYNOW:
|
||||||
if (sfd->forever || sfd->retry-- ) {
|
if (sfd->forever || sfd->retry--) {
|
||||||
if (result == STAT_RETRYLATER) Nanosleep(&sfd->intervall, NULL);
|
if (result == STAT_RETRYLATER)
|
||||||
continue;
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
}
|
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
xiofreeaddrinfo(themarr);
|
xiofreeaddrinfo(themarr);
|
||||||
return result;
|
freeopts(opts);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
#endif /* WITH_RETRY */
|
||||||
xiofreeaddrinfo(themarr);
|
/* FALLTHROUGH */
|
||||||
applyopts(sfd, -1, opts, PH_ALL);
|
case STAT_NORETRY:
|
||||||
|
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||||
if ((result = _xio_openlate(sfd, opts)) < 0)
|
xiofreeaddrinfo(themarr);
|
||||||
|
freeopts(opts);
|
||||||
|
freeopts(opts0);
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
if ((result = _xioopen_socks5_handshake(sfd, level)) != STAT_OK) {
|
Notice2("opening connection to socks5 server %s:%s",
|
||||||
|
socks_server, socks_port);
|
||||||
|
result =
|
||||||
|
_xioopen_ipapp_connect(sfd, socks_server, opts, themarr,
|
||||||
|
needbind, bindarr, bindport, lowport, level);
|
||||||
|
_errno = errno;
|
||||||
|
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||||
|
xiofreeaddrinfo(themarr);
|
||||||
|
switch (result) {
|
||||||
|
case STAT_OK: break;
|
||||||
|
#if WITH_RETRY
|
||||||
|
case STAT_RETRYLATER:
|
||||||
|
case STAT_RETRYNOW:
|
||||||
|
if (sfd->forever || sfd->retry--) {
|
||||||
|
if (result == STAT_RETRYLATER) {
|
||||||
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
}
|
||||||
|
freeopts(opts);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif /* WITH_RETRY */
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
default:
|
||||||
|
Error4("%s:%s:%s:...: %s",
|
||||||
|
argv[0], socks_server, socks_port,
|
||||||
|
_errno?strerror(_errno):"(See above)");
|
||||||
|
freeopts(opts0);
|
||||||
|
freeopts(opts);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = _xioopen_socks5_handshake(sfd, level);
|
||||||
|
switch (result) {
|
||||||
|
case STAT_OK: break;
|
||||||
|
#if WITH_RETRY
|
||||||
|
case STAT_RETRYLATER:
|
||||||
|
case STAT_RETRYNOW:
|
||||||
|
if (sfd->forever || sfd->retry--) {
|
||||||
|
if (result == STAT_RETRYLATER) {
|
||||||
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
}
|
||||||
|
freeopts(opts);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif /* WITH_RETRY */
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
default:
|
||||||
|
Error3("%s:%s:%s: Connection failed", argv[0], socks_server, socks_port);
|
||||||
|
freeopts(opts0);
|
||||||
|
freeopts(opts);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -622,11 +662,16 @@ static int xioopen_socks5(
|
||||||
case STAT_RETRYLATER:
|
case STAT_RETRYLATER:
|
||||||
case STAT_RETRYNOW:
|
case STAT_RETRYNOW:
|
||||||
if ( sfd->forever || sfd->retry-- ) {
|
if ( sfd->forever || sfd->retry-- ) {
|
||||||
if (result == STAT_RETRYLATER) Nanosleep(&sfd->intervall, NULL);
|
if (result == STAT_RETRYLATER)
|
||||||
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
freeopts(opts);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* WITH_RETRY */
|
||||||
|
/* FALLTHROUGH */
|
||||||
default:
|
default:
|
||||||
|
freeopts(opts);
|
||||||
|
freeopts(opts0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,12 +687,18 @@ static int xioopen_socks5(
|
||||||
level = E_WARN;
|
level = E_WARN;
|
||||||
}
|
}
|
||||||
while ((pid = xio_fork(false, level, sfd->shutup)) < 0) {
|
while ((pid = xio_fork(false, level, sfd->shutup)) < 0) {
|
||||||
if (sfd->forever || --sfd->retry) {
|
if (sfd->forever || sfd->retry) {
|
||||||
|
if (sfd->retry > 0)
|
||||||
|
--sfd->retry;
|
||||||
Nanosleep(&sfd->intervall, NULL);
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
freeopts(opts);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
freeopts(opts);
|
||||||
|
freeopts(opts0);
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( pid == 0 ) {
|
if ( pid == 0 ) {
|
||||||
sfd->forever = false;
|
sfd->forever = false;
|
||||||
sfd->retry = 0;
|
sfd->retry = 0;
|
||||||
|
@ -656,17 +707,26 @@ static int xioopen_socks5(
|
||||||
|
|
||||||
Close(sfd->fd);
|
Close(sfd->fd);
|
||||||
Nanosleep(&sfd->intervall, NULL);
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
dropopts(opts, PH_ALL);
|
while (maxchildren > 0 && num_child >= maxchildren) {
|
||||||
opts = copyopts(opts0, GROUP_ALL);
|
Info1("all %d allowed children are active, waiting", maxchildren);
|
||||||
|
Nanosleep(&sfd->intervall, NULL);
|
||||||
|
}
|
||||||
|
freeopts(opts);
|
||||||
continue;
|
continue;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif /* WITH_RETRY */
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (true);
|
} while (true);
|
||||||
|
|
||||||
return 0;
|
Notice4("successfully connected to %s:%s via socks5 server %s:%s",
|
||||||
|
target_name, target_port, socks_server, socks_port);
|
||||||
|
|
||||||
|
result = _xio_openlate(sfd, opts);
|
||||||
|
freeopts(opts);
|
||||||
|
freeopts(opts0);
|
||||||
|
return STAT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* WITH_SOCKS5 */
|
#endif /* WITH_SOCKS5 */
|
||||||
|
|
|
@ -2912,7 +2912,6 @@ int showleft(const struct opt *opts) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* determines the address group from mode_t */
|
/* determines the address group from mode_t */
|
||||||
/* does not set GROUP_FD; cannot determine GROUP_TERMIOS ! */
|
/* does not set GROUP_FD; cannot determine GROUP_TERMIOS ! */
|
||||||
groups_t _groupbits(mode_t mode) {
|
groups_t _groupbits(mode_t mode) {
|
||||||
|
@ -4690,3 +4689,11 @@ int dumpopts(struct opt *opts)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Better with type specific free function */
|
||||||
|
void freeopts(
|
||||||
|
struct opt *opts)
|
||||||
|
{
|
||||||
|
free(opts);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
|
@ -1031,6 +1031,7 @@ extern groups_t _groupbits(mode_t mode);
|
||||||
extern int dropopts(struct opt *opts, unsigned int phase);
|
extern int dropopts(struct opt *opts, unsigned int phase);
|
||||||
extern int dropopts2(struct opt *opts, unsigned int from, unsigned int to);
|
extern int dropopts2(struct opt *opts, unsigned int from, unsigned int to);
|
||||||
extern int dumpopts(struct opt *opts);
|
extern int dumpopts(struct opt *opts);
|
||||||
|
extern void freeopts(struct opt *opts);
|
||||||
|
|
||||||
#if HAVE_BASIC_UID_T==1
|
#if HAVE_BASIC_UID_T==1
|
||||||
# define retropt_uid(o,c,r) retropt_short(o,c,r)
|
# define retropt_uid(o,c,r) retropt_short(o,c,r)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue