1
0
Fork 0
mirror of https://repo.or.cz/socat.git synced 2025-07-17 16:43:24 +00:00

Reworked IPAPP clients

This commit is contained in:
Gerhard 2025-02-10 12:48:04 +01:00
parent 63f67101f4
commit 7b26406d96
16 changed files with 1660 additions and 649 deletions

View file

@ -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: