mirror of
https://repo.or.cz/socat.git
synced 2025-05-23 21:22:42 +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.
|
||||
Test: UNIX_L_BIND
|
||||
|
||||
Removed unused bytes variable from gettimestamp(), corrected #elsif and
|
||||
socks4 record length.
|
||||
Removed unused bytes variable from gettimestamp(), corrected #elsif,
|
||||
and socks4 record length.
|
||||
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:
|
||||
POSIXMQ-RECV now takes option o-nonblock; this, in combination with -T,
|
||||
makes it possible to terminate Socat in case the queue is empty.
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# it is required for test.sh
|
||||
# for TCP, use this script as:
|
||||
# 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
|
||||
#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 */
|
||||
|
||||
|
||||
/* 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
|
||||
|
||||
/* 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;
|
||||
}
|
||||
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",
|
||||
hints.ai_flags, hints.ai_family,
|
||||
hints.ai_socktype, hints.ai_protocol,
|
||||
error_num);
|
||||
gai_strerror(error_num));
|
||||
if (numnode)
|
||||
free(numnode);
|
||||
|
||||
|
@ -760,6 +833,9 @@ void xiofreeaddrinfo(struct addrinfo **ai_sorted) {
|
|||
int ain;
|
||||
struct addrinfo *res;
|
||||
|
||||
if (ai_sorted == NULL)
|
||||
return;
|
||||
|
||||
/* Find the original *res from getaddrinfo past NULL */
|
||||
ain = 0;
|
||||
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 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 void xiofreeaddrinfo(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_lowport = { "lowport", NULL, OPT_LOWPORT, GROUP_IPAPP, PH_LATE, TYPE_BOOL, OFUNC_SPEC };
|
||||
|
||||
|
||||
#if _WITH_IP4 || _WITH_IP6
|
||||
/* we expect the form "host:port" */
|
||||
int xioopen_ipapp_connect(
|
||||
|
@ -31,20 +32,18 @@ int xioopen_ipapp_connect(
|
|||
{
|
||||
struct single *sfd = &xxfd->stream;
|
||||
struct opt *opts0 = NULL;
|
||||
const char *hostname = argv[1], *portname = argv[2];
|
||||
int pf = addrdesc->arg3;
|
||||
int socktype = addrdesc->arg1;
|
||||
int ipproto = addrdesc->arg2;
|
||||
int pf = addrdesc->arg3;
|
||||
const char *hostname = argv[1], *portname = argv[2];
|
||||
bool dofork = false;
|
||||
int maxchildren = 0;
|
||||
union sockaddr_union us_sa, *us = &us_sa;
|
||||
socklen_t uslen = sizeof(us_sa);
|
||||
struct addrinfo **themarr, *themp;
|
||||
char infobuff[256];
|
||||
struct addrinfo **bindarr = NULL;
|
||||
struct addrinfo **themarr = NULL;
|
||||
uint16_t bindport = 0;
|
||||
bool needbind = false;
|
||||
bool lowport = false;
|
||||
int level;
|
||||
int i;
|
||||
int level = E_ERROR;
|
||||
int result;
|
||||
|
||||
if (argc != 3) {
|
||||
|
@ -52,97 +51,84 @@ int xioopen_ipapp_connect(
|
|||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
if (sfd->howtoend == END_UNSPEC)
|
||||
sfd->howtoend = END_SHUTDOWN;
|
||||
/* Apply and retrieve some options */
|
||||
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)
|
||||
return -1;
|
||||
applyopts(sfd, -1, opts, PH_INIT);
|
||||
opts0 = opts; /* save remaining options for each loop */
|
||||
opts = NULL;
|
||||
|
||||
retropt_bool(opts, OPT_FORK, &dofork);
|
||||
if (dofork) {
|
||||
if (!(xioflags & XIO_MAYFORK)) {
|
||||
Error("option fork not allowed here");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
sfd->flags |= XIO_DOESFORK;
|
||||
}
|
||||
Notice2("opening connection to %s:%s", hostname, portname);
|
||||
|
||||
retropt_int(opts, OPT_MAX_CHILDREN, &maxchildren);
|
||||
|
||||
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)));
|
||||
do { /* loop over retries and/or forks */
|
||||
int _errno;
|
||||
|
||||
#if WITH_RETRY
|
||||
if (sfd->forever || sfd->retry) {
|
||||
level = E_INFO;
|
||||
} else if (themarr[i] != NULL) {
|
||||
level = E_WARN;
|
||||
} else
|
||||
if (sfd->forever || sfd->retry) {
|
||||
level = E_NOTICE;
|
||||
} else
|
||||
#endif /* WITH_RETRY */
|
||||
level = E_ERROR;
|
||||
level = E_WARN;
|
||||
|
||||
result =
|
||||
_xioopen_connect(sfd,
|
||||
needbind?us:NULL, uslen,
|
||||
themp->ai_addr, themp->ai_addrlen,
|
||||
opts, pf?pf:themp->ai_family, socktype, ipproto,
|
||||
lowport, level);
|
||||
if (result == STAT_OK)
|
||||
break;
|
||||
themp = themarr[i++];
|
||||
if (themp == NULL) {
|
||||
result = STAT_RETRYLATER;
|
||||
}
|
||||
}
|
||||
opts = copyopts(opts0, GROUP_ALL);
|
||||
|
||||
result =
|
||||
_xioopen_ipapp_prepare(&opts, opts0, hostname, portname,
|
||||
pf, socktype, ipproto,
|
||||
sfd->para.socket.ip.ai_flags,
|
||||
&themarr, &bindarr, &bindport, &needbind, &lowport);
|
||||
switch (result) {
|
||||
case STAT_OK: break;
|
||||
#if WITH_RETRY
|
||||
case STAT_RETRYLATER:
|
||||
case STAT_RETRYNOW:
|
||||
if (sfd->forever || sfd->retry) {
|
||||
--sfd->retry;
|
||||
if (result == STAT_RETRYLATER) {
|
||||
if (sfd->forever || sfd->retry--) {
|
||||
if (result == STAT_RETRYLATER)
|
||||
Nanosleep(&sfd->intervall, NULL);
|
||||
}
|
||||
dropopts(opts, PH_ALL); free(opts); opts = copyopts(opts0, GROUP_ALL);
|
||||
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||
xiofreeaddrinfo(themarr);
|
||||
freeopts(opts);
|
||||
continue;
|
||||
}
|
||||
#endif /* WITH_RETRY */
|
||||
default:
|
||||
/* FALLTHROUGH */
|
||||
case STAT_NORETRY:
|
||||
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -155,16 +141,18 @@ int xioopen_ipapp_connect(
|
|||
so Notice is too weak */
|
||||
}
|
||||
while ((pid = xio_fork(false, level, sfd->shutup)) < 0) {
|
||||
if (sfd->forever || --sfd->retry) {
|
||||
Nanosleep(&sfd->intervall, NULL); continue;
|
||||
if (sfd->forever || sfd->retry--) {
|
||||
Nanosleep(&sfd->intervall, NULL);
|
||||
continue;
|
||||
}
|
||||
xiofreeaddrinfo(themarr);
|
||||
free(opts0);
|
||||
freeopts(opts);
|
||||
freeopts(opts0);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
if (pid == 0) { /* child process */
|
||||
sfd->forever = false; sfd->retry = 0;
|
||||
sfd->forever = false;
|
||||
sfd->retry = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -176,109 +164,266 @@ int xioopen_ipapp_connect(
|
|||
Info1("all %d allowed children are active, waiting", maxchildren);
|
||||
Nanosleep(&sfd->intervall, NULL);
|
||||
}
|
||||
dropopts(opts, PH_ALL); free(opts); opts = copyopts(opts0, GROUP_ALL);
|
||||
freeopts(opts);
|
||||
continue; /* with next socket() bind() connect() */
|
||||
} else
|
||||
#endif /* WITH_RETRY */
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
} while (true); /* end of loop over retries and/or forks */
|
||||
/* only "active" process breaks (master without fork, or child) */
|
||||
xiofreeaddrinfo(themarr);
|
||||
|
||||
if ((result = _xio_openlate(sfd, opts)) < 0) {
|
||||
free(opts0);free(opts);
|
||||
return result;
|
||||
}
|
||||
free(opts0); free(opts);
|
||||
return 0;
|
||||
Notice2("successfully connected to %s:%s", hostname, portname);
|
||||
|
||||
result = _xio_openlate(sfd, opts);
|
||||
freeopts(opts);
|
||||
freeopts(opts0);
|
||||
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:
|
||||
PH_EARLY
|
||||
OPT_PROTOCOL_FAMILY, OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT
|
||||
*/
|
||||
int
|
||||
_xioopen_ipapp_prepare(
|
||||
struct opt *opts,
|
||||
struct opt **opts0,
|
||||
const char *hostname,
|
||||
const char *portname,
|
||||
int *pf,
|
||||
int protocol,
|
||||
const int ai_flags[2],
|
||||
struct addrinfo ***themarr,
|
||||
union sockaddr_union *us,
|
||||
socklen_t *uslen,
|
||||
bool *needbind,
|
||||
bool *lowport,
|
||||
int socktype) {
|
||||
OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT
|
||||
returns STAT_OK, STAT_RETRYLATER, or STAT_NORETRY (+errno)
|
||||
*/
|
||||
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, /* always from getaddrinfo(); xiofreeaddrinfo()! */
|
||||
struct addrinfo ***bindarr, /* on bind from getaddrinfo(); xiofreeaddrinfo()! */
|
||||
uint16_t *bindport, /* for bind without address */
|
||||
bool *needbind,
|
||||
bool *lowport)
|
||||
{
|
||||
uint16_t port;
|
||||
int rc;
|
||||
|
||||
retropt_socket_pf(opts, pf);
|
||||
*opts = copyopts(opts0, GROUP_ALL);
|
||||
|
||||
if (hostname != NULL || portname != NULL) {
|
||||
rc = xiogetaddrinfo(hostname, portname, *pf, socktype, protocol,
|
||||
rc = xiogetaddrinfo(hostname, portname, pf, socktype, protocol,
|
||||
themarr, ai_flags);
|
||||
if (rc == EAI_AGAIN) {
|
||||
Warn4("_xioopen_ipapp_prepare(node=\"%s\", service=\"%s\", pf=%d, ...): %s",
|
||||
hostname?hostname:"NULL", portname?portname:"NULL",
|
||||
*pf, gai_strerror(rc));
|
||||
pf, gai_strerror(rc));
|
||||
errno = EAGAIN;
|
||||
return STAT_RETRYLATER;
|
||||
} else if (rc != 0) {
|
||||
Error4("_xioopen_ipapp_prepare(node=\"%s\", service=\"%s\", pf=%d, ...): %s",
|
||||
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? */
|
||||
}
|
||||
}
|
||||
|
||||
applyopts(NULL, -1, opts, PH_EARLY);
|
||||
applyopts(NULL, -1, *opts, PH_EARLY);
|
||||
|
||||
/* 3 means: IP address AND port accepted */
|
||||
if (retropt_bind(opts, (*pf!=PF_UNSPEC)?*pf:(**themarr)->ai_family,
|
||||
socktype, protocol, (struct sockaddr *)us, uslen, 3,
|
||||
ai_flags)
|
||||
if (retropt_bind_ip(*opts, pf, socktype, protocol, bindarr, 3, ai_flags)
|
||||
!= STAT_NOACTION) {
|
||||
*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) {
|
||||
switch ((*pf!=PF_UNSPEC)?*pf:(**themarr)->ai_family) {
|
||||
if (retropt_2bytes(*opts, OPT_SOURCEPORT, &port) >= 0) {
|
||||
if (*bindarr) {
|
||||
struct addrinfo **bindp;
|
||||
bindp = *bindarr;
|
||||
switch ((*bindp)->ai_family) {
|
||||
#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 */
|
||||
#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 */
|
||||
default: Error("unsupported protocol family");
|
||||
default:
|
||||
Error("unsupported protocol family");
|
||||
errno = EPROTONOSUPPORT;
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
} else {
|
||||
*bindport = port;
|
||||
}
|
||||
*needbind = true;
|
||||
}
|
||||
|
||||
retropt_bool(opts, OPT_LOWPORT, lowport);
|
||||
|
||||
*opts0 = copyopts(opts, GROUP_ALL);
|
||||
retropt_bool(*opts, OPT_LOWPORT, lowport);
|
||||
|
||||
return STAT_OK;
|
||||
}
|
||||
#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
|
||||
/*
|
||||
applies and consumes the following options:
|
||||
|
|
|
@ -15,11 +15,9 @@ extern const struct optdesc opt_sourceport;
|
|||
extern const struct optdesc opt_lowport;
|
||||
|
||||
extern int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, const struct addrdesc *addrdesc);
|
||||
extern int _xioopen_ipapp_prepare(struct opt *opts, struct opt **opts0, const char *hostname, const char *portname, int *pf, int protocol, const int ai_flags[2], struct addrinfo ***themlist, union sockaddr_union *us, socklen_t *uslen, bool *needbind, bool *lowport, int socktype);
|
||||
extern int _xioopen_ip4app_connect(const char *hostname, const char *portname,
|
||||
struct single *xfd,
|
||||
int socktype, int ipproto, void *protname,
|
||||
struct opt *opts);
|
||||
extern int _xioopen_ipapp_init(struct single *sfd, int xioflags, struct opt *opts, bool *dofork, int *maxchildren, int *pf, int *socktype, int *protocol);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
|
||||
|
|
162
xio-openssl.c
162
xio-openssl.c
|
@ -238,13 +238,13 @@ static int xioopen_openssl_connect(
|
|||
int socktype = SOCK_STREAM;
|
||||
int ipproto = IPPROTO_TCP;
|
||||
bool dofork = false;
|
||||
union sockaddr_union us_sa, *us = &us_sa;
|
||||
socklen_t uslen = sizeof(us_sa);
|
||||
struct addrinfo **themarr, *themp;
|
||||
int maxchildren = 0;
|
||||
struct addrinfo **bindarr = NULL;
|
||||
struct addrinfo **themarr = NULL;
|
||||
uint16_t bindport = 0;
|
||||
bool needbind = false;
|
||||
bool lowport = false;
|
||||
int level = E_ERROR;
|
||||
int i;
|
||||
SSL_CTX* ctx;
|
||||
bool opt_ver = true; /* verify peer certificate */
|
||||
char *opt_cert = NULL; /* file name of client certificate */
|
||||
|
@ -254,7 +254,7 @@ static int xioopen_openssl_connect(
|
|||
int result;
|
||||
|
||||
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;
|
||||
}
|
||||
sfd->flags |= XIO_DOESCONVERT;
|
||||
|
@ -272,14 +272,6 @@ static int xioopen_openssl_connect(
|
|||
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_COMMONNAME, (char **)&opt_commonname);
|
||||
#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;
|
||||
ipproto = IPPROTO_UDP;
|
||||
}
|
||||
retropt_int(opts, OPT_SO_TYPE, &socktype);
|
||||
retropt_int(opts, OPT_SO_PROTOTYPE, &ipproto);
|
||||
|
||||
result =
|
||||
_xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto,
|
||||
sfd->para.socket.ip.ai_flags,
|
||||
&themarr, us, &uslen,
|
||||
&needbind, &lowport, socktype);
|
||||
if (result != STAT_OK) return STAT_NORETRY;
|
||||
/* Apply and retrieve some options */
|
||||
result = _xioopen_ipapp_init(sfd, xioflags, opts,
|
||||
&dofork, &maxchildren,
|
||||
&pf, &socktype, &ipproto);
|
||||
if (result != STAT_OK)
|
||||
return result;
|
||||
|
||||
if (xioparms.logopt == 'm') {
|
||||
Info("starting connect loop, switching to syslog");
|
||||
diag_set('y', xioparms.syslogfac); xioparms.logopt = 'y';
|
||||
} else {
|
||||
Info("starting connect loop");
|
||||
}
|
||||
opts0 = opts; /* save remaining options for each loop */
|
||||
opts = NULL;
|
||||
|
||||
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") */
|
||||
i = 0;
|
||||
themp = themarr[i++];
|
||||
while (themp != NULL) {
|
||||
do { /* loop over retries (failed connect and SSL handshake attempts) and/or forks */
|
||||
int _errno;
|
||||
|
||||
#if WITH_RETRY
|
||||
if (sfd->forever || sfd->retry || themarr[i] != NULL) {
|
||||
level = E_INFO;
|
||||
} else
|
||||
if (sfd->forever || sfd->retry) {
|
||||
level = E_NOTICE;
|
||||
} else
|
||||
#endif /* WITH_RETRY */
|
||||
level = E_ERROR;
|
||||
level = E_WARN;
|
||||
|
||||
/* 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_addr->sa_family, socktype, ipproto, lowport, level);
|
||||
if (result == STAT_OK)
|
||||
break;
|
||||
themp = themarr[i++];
|
||||
if (themp == NULL) {
|
||||
result = STAT_RETRYLATER;
|
||||
}
|
||||
}
|
||||
opts = copyopts(opts0, GROUP_ALL);
|
||||
|
||||
result =
|
||||
_xioopen_ipapp_prepare(&opts, opts0, hostname, portname,
|
||||
pf, socktype, ipproto,
|
||||
sfd->para.socket.ip.ai_flags,
|
||||
&themarr, &bindarr, &bindport, &needbind, &lowport);
|
||||
switch (result) {
|
||||
case STAT_OK: break;
|
||||
#if WITH_RETRY
|
||||
case STAT_RETRYLATER:
|
||||
case STAT_RETRYNOW:
|
||||
if (sfd->forever || sfd->retry) {
|
||||
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
|
||||
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 */
|
||||
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) {
|
||||
Nanosleep(&sfd->intervall, NULL);
|
||||
}
|
||||
--sfd->retry;
|
||||
freeopts(opts);
|
||||
continue;
|
||||
}
|
||||
xiofreeaddrinfo(themarr);
|
||||
return STAT_NORETRY;
|
||||
#endif /* WITH_RETRY */
|
||||
default:
|
||||
xiofreeaddrinfo(themarr);
|
||||
return result;
|
||||
}
|
||||
/*! isn't this too early? */
|
||||
if ((result = _xio_openlate(sfd, opts)) < 0) {
|
||||
xiofreeaddrinfo(themarr);
|
||||
Error4("%s:%s:%s: %s", argv[0], hostname, portname,
|
||||
_errno?strerror(_errno):"(See above)");
|
||||
freeopts(opts0);
|
||||
freeopts(opts);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -392,19 +394,19 @@ static int xioopen_openssl_connect(
|
|||
#if WITH_RETRY
|
||||
case STAT_RETRYLATER:
|
||||
case STAT_RETRYNOW:
|
||||
if (sfd->forever || sfd->retry) {
|
||||
Close(sfd->fd);
|
||||
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
|
||||
if (sfd->forever || sfd->retry--) {
|
||||
if (result == STAT_RETRYLATER) {
|
||||
Nanosleep(&sfd->intervall, NULL);
|
||||
}
|
||||
--sfd->retry;
|
||||
freeopts(opts);
|
||||
Close(sfd->fd);
|
||||
continue;
|
||||
}
|
||||
#endif /* WITH_RETRY */
|
||||
default:
|
||||
xiofreeaddrinfo(themarr);
|
||||
return STAT_NORETRY;
|
||||
freeopts(opts);
|
||||
freeopts(opts0);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (dofork) {
|
||||
|
@ -419,15 +421,19 @@ static int xioopen_openssl_connect(
|
|||
level = E_WARN;
|
||||
}
|
||||
while ((pid = xio_fork(false, level, sfd->shutup)) < 0) {
|
||||
if (sfd->forever || --sfd->retry) {
|
||||
Nanosleep(&sfd->intervall, NULL); continue;
|
||||
if (sfd->forever || sfd->retry--) {
|
||||
Nanosleep(&sfd->intervall, NULL);
|
||||
freeopts(opts);
|
||||
continue;
|
||||
}
|
||||
xiofreeaddrinfo(themarr);
|
||||
freeopts(opts);
|
||||
freeopts(opts0);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
if (pid == 0) { /* child process */
|
||||
sfd->forever = false; sfd->retry = 0;
|
||||
sfd->forever = false;
|
||||
sfd->retry = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -437,21 +443,29 @@ static int xioopen_openssl_connect(
|
|||
sfd->para.openssl.ssl = NULL;
|
||||
/* with and without retry */
|
||||
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() */
|
||||
}
|
||||
#endif /* WITH_RETRY */
|
||||
break;
|
||||
|
||||
} while (true); /* drop out on success */
|
||||
xiofreeaddrinfo(themarr);
|
||||
|
||||
openssl_conn_loginfo(sfd->para.openssl.ssl);
|
||||
|
||||
free((void *)opt_commonname);
|
||||
free((void *)opt_snihost);
|
||||
|
||||
/* fill in the fd structure */
|
||||
return STAT_OK;
|
||||
Notice2("successfully connected to SSL server %s:%s", hostname, portname);
|
||||
|
||||
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,
|
||||
const struct addrdesc *addrdesc)
|
||||
{
|
||||
/* we expect the form: host:host:port */
|
||||
/* we expect the form: host:host:port */
|
||||
struct single *sfd = &xxfd->stream;
|
||||
struct opt *opts0 = NULL;
|
||||
struct proxyvars struct_proxyvars = { 0 }, *proxyvars = &struct_proxyvars;
|
||||
/* variables to be filled with address option values */
|
||||
bool dofork = false;
|
||||
int maxchildren = 0;
|
||||
/* */
|
||||
int pf = PF_UNSPEC;
|
||||
union sockaddr_union us_sa, *us = &us_sa;
|
||||
socklen_t uslen = sizeof(us_sa);
|
||||
struct addrinfo **themarr, *themp;
|
||||
int i;
|
||||
struct addrinfo **bindarr = NULL;
|
||||
struct addrinfo **themarr = NULL;
|
||||
uint16_t bindport = 0;
|
||||
const char *proxyname; char *proxyport = NULL;
|
||||
const char *targetname, *targetport;
|
||||
int ipproto = IPPROTO_TCP;
|
||||
|
@ -112,90 +112,123 @@ static int xioopen_proxy_connect(
|
|||
targetname = argv[2];
|
||||
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 ((proxyport = strdup(PROXYPORT)) == NULL) {
|
||||
errno = ENOMEM; return -1;
|
||||
}
|
||||
}
|
||||
|
||||
result = _xioopen_proxy_prepare(proxyvars, opts, targetname, targetport,
|
||||
sfd->para.socket.ip.ai_flags);
|
||||
if (result != STAT_OK)
|
||||
return result;
|
||||
|
||||
Notice4("opening connection to %s:%u via proxy %s:%s",
|
||||
proxyvars->targetaddr, proxyvars->targetport, proxyname, proxyport);
|
||||
|
||||
i = 0;
|
||||
do { /* loop over retries (failed connect and proxy-request attempts) */
|
||||
|
||||
level = E_INFO;
|
||||
|
||||
result =
|
||||
_xioopen_ipapp_prepare(opts, &opts0, proxyname, proxyport,
|
||||
&pf, ipproto,
|
||||
sfd->para.socket.ip.ai_flags,
|
||||
&themarr, us, &uslen,
|
||||
&needbind, &lowport, socktype);
|
||||
result =
|
||||
_xioopen_ipapp_init(sfd, xioflags, opts,
|
||||
&dofork, &maxchildren,
|
||||
&pf, &socktype, &ipproto);
|
||||
if (result != STAT_OK)
|
||||
return result;
|
||||
|
||||
/* Loop over themlist */
|
||||
i = 0;
|
||||
themp = themarr[i++];
|
||||
while (themp != NULL) {
|
||||
Notice4("opening connection to %s:%u via proxy %s:%s",
|
||||
proxyvars->targetaddr, proxyvars->targetport, proxyname, proxyport);
|
||||
#if WITH_RETRY
|
||||
if (sfd->forever || sfd->retry || themarr[i] != NULL) {
|
||||
level = E_INFO;
|
||||
} else
|
||||
#endif /* WITH_RETRY */
|
||||
level = E_ERROR;
|
||||
result = _xioopen_proxy_init(proxyvars, opts, targetname, targetport);
|
||||
if (result != STAT_OK)
|
||||
return result;
|
||||
|
||||
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;
|
||||
}
|
||||
opts0 = opts; /* save remaining options for each loop */
|
||||
opts = NULL;
|
||||
|
||||
Notice4("opening connection to %s:%s via proxy %s:%s",
|
||||
targetname, targetport, proxyname, proxyport);
|
||||
|
||||
do { /* loop over retries (failed connect and proxy-request attempts)
|
||||
and/or forks */
|
||||
int _errno;
|
||||
|
||||
#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) {
|
||||
case STAT_OK: break;
|
||||
#if WITH_RETRY
|
||||
case STAT_RETRYLATER:
|
||||
case STAT_RETRYNOW:
|
||||
if (sfd->forever || sfd->retry) {
|
||||
--sfd->retry;
|
||||
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 */
|
||||
default:
|
||||
/* FALLTHROUGH */
|
||||
case STAT_NORETRY:
|
||||
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||
xiofreeaddrinfo(themarr);
|
||||
freeopts(opts);
|
||||
freeopts(opts0);
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
switch (result) {
|
||||
|
@ -204,11 +237,16 @@ static int xioopen_proxy_connect(
|
|||
case STAT_RETRYLATER:
|
||||
case STAT_RETRYNOW:
|
||||
if (sfd->forever || sfd->retry--) {
|
||||
if (result == STAT_RETRYLATER) Nanosleep(&sfd->intervall, NULL);
|
||||
if (result == STAT_RETRYLATER)
|
||||
Nanosleep(&sfd->intervall, NULL);
|
||||
freeopts(opts);
|
||||
continue;
|
||||
}
|
||||
#endif /* WITH_RETRY */
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
freeopts(opts);
|
||||
freeopts(opts0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -225,21 +263,32 @@ static int xioopen_proxy_connect(
|
|||
}
|
||||
while ((pid = xio_fork(false, level, sfd->shutup)) < 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (pid == 0) { /* child process */
|
||||
sfd->forever = false; sfd->retry = 0;
|
||||
sfd->forever = false;
|
||||
sfd->retry = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* parent process */
|
||||
Close(sfd->fd);
|
||||
/* With and without retry */
|
||||
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;
|
||||
} else
|
||||
#endif /* WITH_RETRY */
|
||||
|
@ -248,25 +297,25 @@ static int xioopen_proxy_connect(
|
|||
}
|
||||
|
||||
} 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",
|
||||
proxyvars->targetaddr, proxyvars->targetport,
|
||||
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 opt *opts,
|
||||
const char *targetname,
|
||||
const char *targetport,
|
||||
const int ai_flags[2]) {
|
||||
union sockaddr_union host;
|
||||
socklen_t socklen = sizeof(host);
|
||||
int rc;
|
||||
|
||||
const char *targetport)
|
||||
{
|
||||
retropt_bool(opts, OPT_IGNORECR, &proxyvars->ignorecr);
|
||||
retropt_bool(opts, OPT_PROXY_RESOLVE, &proxyvars->doresolve);
|
||||
retropt_string(opts, OPT_HTTP_VERSION, &proxyvars->version);
|
||||
|
@ -316,6 +365,28 @@ int _xioopen_proxy_prepare(
|
|||
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) {
|
||||
/* currently we only resolve to IPv4 addresses. This is in accordance to
|
||||
RFC 2396; however once it becomes clear how IPv6 addresses should be
|
||||
|
@ -325,6 +396,10 @@ int _xioopen_proxy_prepare(
|
|||
&host, &socklen, ai_flags);
|
||||
if (rc != STAT_OK) {
|
||||
proxyvars->targetaddr = strdup(targetname);
|
||||
if (proxyvars->targetaddr == NULL) {
|
||||
Error1("strdup(\"%s\"): out of memory", targetname);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
} else {
|
||||
#define LEN 16 /* www.xxx.yyy.zzz\0 */
|
||||
if ((proxyvars->targetaddr = Malloc(LEN)) == NULL) {
|
||||
|
@ -337,8 +412,6 @@ int _xioopen_proxy_prepare(
|
|||
((unsigned char *)&host.ip4.sin_addr.s_addr)[3]);
|
||||
#undef LEN
|
||||
}
|
||||
} else {
|
||||
proxyvars->targetaddr = strdup(targetname);
|
||||
}
|
||||
|
||||
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 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]);
|
||||
int _xioopen_proxy_connect(struct single *xfd,
|
||||
struct proxyvars *proxyvars,
|
||||
int level);
|
||||
extern int _xioopen_proxy_connect(struct single *xfd, struct proxyvars *proxyvars, int level);
|
||||
|
||||
#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 UNIX and abstract sockets: uses tmpname() to find a free file system
|
||||
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,
|
||||
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);
|
||||
|
||||
if (xiobind(sfd, us, uslen, opts, pf, alt, level) < 0) {
|
||||
return -1;
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
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",
|
||||
sfd->fd, timeout.tv_sec, timeout.tv_usec, strerror(errno));
|
||||
Close(sfd->fd);
|
||||
errno = _errno;
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
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)),
|
||||
strerror(ETIMEDOUT));
|
||||
Close(sfd->fd);
|
||||
errno = _errno;
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
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)),
|
||||
themlen, strerror(errno));
|
||||
#endif
|
||||
_errno = errno;
|
||||
Close(sfd->fd);
|
||||
errno = _errno;
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
/* otherwise OK or network error */
|
||||
result = Getsockopt(sfd->fd, SOL_SOCKET, SO_ERROR, &err, &errlen);
|
||||
if (result != 0) {
|
||||
_errno = errno;
|
||||
Msg2(level, "getsockopt(%d, SOL_SOCKET, SO_ERROR, ...): %s",
|
||||
sfd->fd, strerror(err));
|
||||
Close(sfd->fd);
|
||||
errno = _errno;
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
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)),
|
||||
themlen, strerror(err));
|
||||
Close(sfd->fd);
|
||||
errno = err;
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
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)),
|
||||
themlen, strerror(errno));
|
||||
Close(sfd->fd);
|
||||
errno = _errno;
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
} else { /* result >= 0 */
|
||||
|
@ -1679,9 +1687,7 @@ int xiocheckrange(union sockaddr_union *sa, struct xiorange *range) {
|
|||
int xiocheckpeer(xiosingle_t *sfd,
|
||||
union sockaddr_union *pa, union sockaddr_union *la) {
|
||||
char infobuff[256];
|
||||
#if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP
|
||||
int result;
|
||||
#endif
|
||||
|
||||
#if WITH_IP4 || WITH_IP6
|
||||
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
|
||||
ev. generates an appropriate error message.
|
||||
returns 0 on success or -1 if an error occurred. */
|
||||
int
|
||||
xiosocket(struct opt *opts, int pf, int socktype, int proto, int msglevel) {
|
||||
returns 0 on success or -1 (and errno) if an error occurred. */
|
||||
int xiosocket(struct opt *opts, int pf, int socktype, int proto, int msglevel) {
|
||||
int result;
|
||||
|
||||
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 UNIX and abstract sockets: uses a method similar to tmpname() to
|
||||
find a free file system entry.
|
||||
On success returns STAT_OK, otherwise errno is set.
|
||||
*/
|
||||
int xiobind(
|
||||
struct single *sfd,
|
||||
|
@ -2154,18 +2160,20 @@ int xiobind(
|
|||
usrname = strndup(us->un.sun_path, sizeof(us->un.sun_path));
|
||||
if (usrname == NULL) {
|
||||
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));
|
||||
errno = _errno;
|
||||
return -1;
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
}
|
||||
|
||||
do { /* loop over tempnam bind() attempts */
|
||||
sockname = xio_tempnam(usrname, abstract);
|
||||
if (sockname == NULL) {
|
||||
int _errno = errno;
|
||||
Error2("tempnam(\"%s\"): %s", usrname, strerror(errno));
|
||||
free(usrname);
|
||||
errno = _errno;
|
||||
return -1;
|
||||
}
|
||||
strncpy(us->un.sun_path+(abstract?1:0), sockname, sizeof(us->un.sun_path));
|
||||
|
@ -2179,8 +2187,10 @@ int xiobind(
|
|||
infobuff, sizeof(infobuff)),
|
||||
uslen, strerror(errno));
|
||||
if (errno != EADDRINUSE) {
|
||||
int _errno = errno;
|
||||
free(usrname);
|
||||
Close(sfd->fd);
|
||||
errno = _errno;
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
} else {
|
||||
|
@ -2193,10 +2203,12 @@ int xiobind(
|
|||
|
||||
if (us != NULL) {
|
||||
if (Bind(sfd->fd, &us->soa, uslen) < 0) {
|
||||
int _errno = errno;
|
||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
|
||||
sfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
|
||||
uslen, strerror(errno));
|
||||
Close(sfd->fd);
|
||||
errno = _errno;
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
|
||||
|
@ -2268,12 +2280,14 @@ int xiobind(
|
|||
do { /* loop over lowport bind() attempts */
|
||||
*port = htons(i);
|
||||
if (Bind(sfd->fd, &sinp->soa, sizeof(*sinp)) < 0) {
|
||||
int _errno = errno;
|
||||
Msg4(errno==EADDRINUSE?E_INFO:level,
|
||||
"bind(%d, {%s}, "F_Zd"): %s", sfd->fd,
|
||||
sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)),
|
||||
sizeof(*sinp), strerror(errno));
|
||||
if (errno != EADDRINUSE) {
|
||||
if (_errno != EADDRINUSE) {
|
||||
Close(sfd->fd);
|
||||
errno = _errno;
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
} else {
|
||||
|
@ -2282,8 +2296,8 @@ int xiobind(
|
|||
--i; if (i < XIO_IPPORT_LOWER) i = IPPORT_RESERVED-1;
|
||||
if (i == N) {
|
||||
Msg(level, "no low port available");
|
||||
/*errno = EADDRINUSE; still assigned */
|
||||
Close(sfd->fd);
|
||||
errno = EADDRINUSE;
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
} while (i != N);
|
||||
|
@ -2294,17 +2308,19 @@ int xiobind(
|
|||
if (us) {
|
||||
applyopts(sfd, sfd->fd, opts, PH_BIND);
|
||||
if (Bind(sfd->fd, &us->soa, uslen) < 0) {
|
||||
int _errno = errno;
|
||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
|
||||
sfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
|
||||
uslen, strerror(errno));
|
||||
Close(sfd->fd);
|
||||
errno = _errno;
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
applyopts(sfd, -1, opts, PH_PASTBIND);
|
||||
return 0;
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
/* 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 ipproto = IPPROTO_TCP;
|
||||
bool dofork = false;
|
||||
union sockaddr_union us_sa, *us = &us_sa;
|
||||
socklen_t uslen = sizeof(us_sa);
|
||||
struct addrinfo **themarr, *themp;
|
||||
int i;
|
||||
int maxchildren = 0;
|
||||
struct addrinfo **bindarr = NULL;
|
||||
struct addrinfo **themarr = NULL;
|
||||
uint16_t bindport = 0;
|
||||
bool needbind = false;
|
||||
bool lowport = false;
|
||||
char infobuff[256];
|
||||
unsigned char buff[BUFF_LEN];
|
||||
struct socks4 *sockhead = (struct socks4 *)buff;
|
||||
size_t buflen = sizeof(buff);
|
||||
|
@ -76,41 +75,43 @@ static int xioopen_socks4_connect(
|
|||
targetname = argv[2];
|
||||
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);
|
||||
|
||||
result = _xioopen_socks4_prepare(targetport, opts, &socksport, sockhead, &buflen);
|
||||
/* Apply and retrieve some options */
|
||||
result = _xioopen_ipapp_init(sfd, xioflags, opts,
|
||||
&dofork, &maxchildren,
|
||||
&pf, &socktype, &ipproto);
|
||||
if (result != STAT_OK)
|
||||
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\"",
|
||||
targetname,
|
||||
ntohs(sockhead->port),
|
||||
targetname, ntohs(sockhead->port),
|
||||
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 =
|
||||
_xioopen_ipapp_prepare(opts, &opts0, sockdname, socksport,
|
||||
&pf, ipproto,
|
||||
_xioopen_ipapp_prepare(&opts, opts0, sockdname, socksport,
|
||||
pf, socktype, ipproto,
|
||||
sfd->para.socket.ip.ai_flags,
|
||||
&themarr, us, &uslen,
|
||||
&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);
|
||||
&themarr, &bindarr, &bindport, &needbind, &lowport);
|
||||
switch (result) {
|
||||
case STAT_OK: break;
|
||||
#if WITH_RETRY
|
||||
|
@ -119,60 +120,78 @@ static int xioopen_socks4_connect(
|
|||
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 */
|
||||
default:
|
||||
/* FALLTHROUGH */
|
||||
case STAT_NORETRY:
|
||||
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||
xiofreeaddrinfo(themarr);
|
||||
freeopts(opts);
|
||||
freeopts(opts0);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* loop over themarr */
|
||||
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 (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;
|
||||
}
|
||||
/* we try to resolve the target address _before_ connecting to the socks
|
||||
server: this may avoid unnecessary connects and timeouts */
|
||||
result =
|
||||
_xioopen_socks4_prepare(sfd, targetname, socks4a, sockhead,
|
||||
(ssize_t *)&buflen, level);
|
||||
switch (result) {
|
||||
case STAT_OK: break;
|
||||
#if WITH_RETRY
|
||||
case STAT_RETRYLATER:
|
||||
case STAT_RETRYNOW:
|
||||
if (sfd->forever || sfd->retry) {
|
||||
--sfd->retry;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
result = _xioopen_socks4_connect(sfd, sockhead, buflen, level);
|
||||
switch (result) {
|
||||
|
@ -181,11 +200,16 @@ static int xioopen_socks4_connect(
|
|||
case STAT_RETRYLATER:
|
||||
case STAT_RETRYNOW:
|
||||
if (sfd->forever || sfd->retry--) {
|
||||
if (result == STAT_RETRYLATER) Nanosleep(&sfd->intervall, NULL);
|
||||
if (result == STAT_RETRYLATER)
|
||||
Nanosleep(&sfd->intervall, NULL);
|
||||
freeopts(opts);
|
||||
continue;
|
||||
}
|
||||
#endif /* WITH_RETRY */
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
freeopts(opts);
|
||||
freeopts(opts0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -202,10 +226,13 @@ static int xioopen_socks4_connect(
|
|||
so Notice is too weak */
|
||||
}
|
||||
while ((pid = xio_fork(false, level, sfd->shutup)) < 0) {
|
||||
if (sfd->forever || --sfd->retry) {
|
||||
if (sfd->forever || sfd->retry--) {
|
||||
Nanosleep(&sfd->intervall, NULL);
|
||||
freeopts(opts);
|
||||
continue;
|
||||
}
|
||||
freeopts(opts);
|
||||
freeopts(opts0);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
|
@ -217,8 +244,13 @@ static int xioopen_socks4_connect(
|
|||
|
||||
/* parent process */
|
||||
Close(sfd->fd);
|
||||
/* with and without retry */
|
||||
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;
|
||||
} else
|
||||
#endif /* WITH_RETRY */
|
||||
|
@ -227,7 +259,15 @@ static int xioopen_socks4_connect(
|
|||
}
|
||||
|
||||
} 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 */
|
||||
|
@ -260,7 +300,13 @@ int _xioopen_opt_socksport(
|
|||
#endif /* WITH_SOCKS4 || WITH_SOCKS4A || WITH_SOCKS5 */
|
||||
#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;
|
||||
|
||||
/* 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() */
|
||||
int
|
||||
_xioopen_socks4_connect0(struct single *sfd,
|
||||
const char *hostname, /* socks target host */
|
||||
int socks4a,
|
||||
struct socks4 *sockhead,
|
||||
ssize_t *headlen, /* get available space,
|
||||
return used length*/
|
||||
int level) {
|
||||
int _xioopen_socks4_prepare(
|
||||
struct single *sfd,
|
||||
const char *hostname, /* socks target host */
|
||||
int socks4a,
|
||||
struct socks4 *sockhead,
|
||||
ssize_t *headlen, /* get available space, return used length*/
|
||||
int level)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (!socks4a) {
|
||||
|
@ -435,16 +481,7 @@ int _xioopen_socks4_connect(struct single *sfd,
|
|||
switch (replyhead->action) {
|
||||
case SOCKS_CD_GRANTED:
|
||||
/* 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");
|
||||
#endif
|
||||
break;
|
||||
|
||||
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 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_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_init(const char *targetport, struct opt *opts, char **socksport, struct socks4 *sockhead, size_t *headlen);
|
||||
extern int _xioopen_socks4_prepare(struct single *xfd, const char *hostname, int socks4a, struct socks4 *sockhead, ssize_t *headlen, int level);
|
||||
extern int _xioopen_socks4_connect(struct single *xfd,
|
||||
struct socks4 *sockhead,
|
||||
size_t headlen,
|
||||
|
|
184
xio-socks5.c
184
xio-socks5.c
|
@ -512,6 +512,7 @@ static int xioopen_socks5(
|
|||
{
|
||||
int socks_command = addrdesc->arg1;
|
||||
bool dofork = false;
|
||||
int maxchildren = 0;
|
||||
int socktype = SOCK_STREAM;
|
||||
int pf = PF_UNSPEC;
|
||||
int ipproto = IPPROTO_TCP;
|
||||
|
@ -519,12 +520,11 @@ static int xioopen_socks5(
|
|||
struct opt *opts0 = NULL;
|
||||
struct single *sfd = &xxfd->stream;
|
||||
const char *socks_server, *target_name, *target_port, *socks_port;
|
||||
union sockaddr_union us_sa, *us = &us_sa;
|
||||
socklen_t uslen = sizeof(us_sa);
|
||||
struct addrinfo **themarr, *themp;
|
||||
struct addrinfo **bindarr = NULL;
|
||||
struct addrinfo **themarr = NULL;
|
||||
uint16_t bindport = 0;
|
||||
bool needbind = false;
|
||||
bool lowport = false;
|
||||
char infobuff[256];
|
||||
|
||||
if (argc < 4 || argc > 5) {
|
||||
xio_syntax(argv[0], 4, argc-1, addrdesc->syntax);
|
||||
|
@ -542,75 +542,115 @@ static int xioopen_socks5(
|
|||
target_port = 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);
|
||||
/* Apply and retrieve some options */
|
||||
result = _xioopen_ipapp_init(sfd, xioflags, opts,
|
||||
&dofork, &maxchildren,
|
||||
&pf, &socktype, &ipproto);
|
||||
if (result != STAT_OK)
|
||||
return result;
|
||||
|
||||
if (_xioopen_opt_socksport(opts, (char **)&socks_port) < 0) {
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
/*! possible memory leak */
|
||||
|
||||
result = _xioopen_ipapp_prepare(opts, &opts0, socks_server, socks_port,
|
||||
&pf, ipproto,
|
||||
sfd->para.socket.ip.ai_flags,
|
||||
&themarr, us, &uslen,
|
||||
&needbind, &lowport, socktype);
|
||||
opts0 = opts;
|
||||
opts = NULL;
|
||||
|
||||
Notice2("connecting to socks5 server %s:%s",
|
||||
socks_server, socks_port);
|
||||
Notice4("opening connection to %s:%s vis socks5 server %s:%s",
|
||||
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 (sfd->forever || sfd->retry) {
|
||||
level = E_INFO;
|
||||
} else {
|
||||
level = E_ERROR;
|
||||
}
|
||||
level = E_NOTICE;
|
||||
} else
|
||||
#endif
|
||||
level = E_WARN;
|
||||
|
||||
/* loop over themarr */
|
||||
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;
|
||||
opts = copyopts(opts0, GROUP_ALL);
|
||||
|
||||
switch(result){
|
||||
break;
|
||||
result =
|
||||
_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
|
||||
case STAT_RETRYLATER:
|
||||
case STAT_RETRYNOW:
|
||||
if (sfd->forever || sfd->retry-- ) {
|
||||
if (result == STAT_RETRYLATER) Nanosleep(&sfd->intervall, NULL);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
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);
|
||||
return result;
|
||||
freeopts(opts);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
xiofreeaddrinfo(themarr);
|
||||
applyopts(sfd, -1, opts, PH_ALL);
|
||||
|
||||
if ((result = _xio_openlate(sfd, opts)) < 0)
|
||||
#endif /* WITH_RETRY */
|
||||
/* FALLTHROUGH */
|
||||
case STAT_NORETRY:
|
||||
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
|
||||
xiofreeaddrinfo(themarr);
|
||||
freeopts(opts);
|
||||
freeopts(opts0);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -622,11 +662,16 @@ static int xioopen_socks5(
|
|||
case STAT_RETRYLATER:
|
||||
case STAT_RETRYNOW:
|
||||
if ( sfd->forever || sfd->retry-- ) {
|
||||
if (result == STAT_RETRYLATER) Nanosleep(&sfd->intervall, NULL);
|
||||
if (result == STAT_RETRYLATER)
|
||||
Nanosleep(&sfd->intervall, NULL);
|
||||
freeopts(opts);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
#endif /* WITH_RETRY */
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
freeopts(opts);
|
||||
freeopts(opts0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -642,12 +687,18 @@ static int xioopen_socks5(
|
|||
level = E_WARN;
|
||||
}
|
||||
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);
|
||||
freeopts(opts);
|
||||
continue;
|
||||
}
|
||||
freeopts(opts);
|
||||
freeopts(opts0);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
if ( pid == 0 ) {
|
||||
sfd->forever = false;
|
||||
sfd->retry = 0;
|
||||
|
@ -656,17 +707,26 @@ static int xioopen_socks5(
|
|||
|
||||
Close(sfd->fd);
|
||||
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;
|
||||
} else
|
||||
#endif
|
||||
#endif /* WITH_RETRY */
|
||||
{
|
||||
break;
|
||||
}
|
||||
} 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 */
|
||||
|
|
|
@ -2912,7 +2912,6 @@ int showleft(const struct opt *opts) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* determines the address group from mode_t */
|
||||
/* does not set GROUP_FD; cannot determine GROUP_TERMIOS ! */
|
||||
groups_t _groupbits(mode_t mode) {
|
||||
|
@ -4690,3 +4689,11 @@ int dumpopts(struct opt *opts)
|
|||
}
|
||||
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 dropopts2(struct opt *opts, unsigned int from, unsigned int to);
|
||||
extern int dumpopts(struct opt *opts);
|
||||
extern void freeopts(struct opt *opts);
|
||||
|
||||
#if HAVE_BASIC_UID_T==1
|
||||
# define retropt_uid(o,c,r) retropt_short(o,c,r)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue