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

Reworked domain name resolution, centralized IPv4/IPv6 sorting

This commit is contained in:
Gerhard Rieger 2024-08-21 20:53:15 +02:00
parent 127280088c
commit ec0e1ca20c
10 changed files with 258 additions and 183 deletions

View file

@ -39,12 +39,11 @@ int xioopen_ipapp_connect(
int maxchildren = 0;
union sockaddr_union us_sa, *us = &us_sa;
socklen_t uslen = sizeof(us_sa);
struct addrinfo *themlist, *themp;
struct addrinfo **themarr, *themp;
char infobuff[256];
bool needbind = false;
bool lowport = false;
int level;
struct addrinfo **ai_sorted;
int i;
int result;
@ -78,7 +77,7 @@ int xioopen_ipapp_connect(
if (_xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto,
sfd->para.socket.ip.ai_flags,
&themlist, us, &uslen, &needbind, &lowport,
&themarr, us, &uslen, &needbind, &lowport,
socktype) != STAT_OK) {
return STAT_NORETRY;
}
@ -94,33 +93,22 @@ int xioopen_ipapp_connect(
Info("starting connect loop");
}
/* Count addrinfo entries */
themp = themlist;
i = 0;
while (themp != NULL) {
++i;
themp = themp->ai_next;
}
ai_sorted = Calloc((i+1), sizeof(struct addrinfo *));
if (ai_sorted == NULL)
return STAT_RETRYLATER;
/* Generate a list of addresses sorted by preferred ip version */
_xio_sort_ip_addresses(themlist, ai_sorted);
do { /* loop over retries, and forks */
/* Loop over themlist - no, over ai_sorted */
/* Loop over themarr (which had been "ai_sorted") */
result = STAT_RETRYLATER;
i = 0;
themp = ai_sorted[i++];
themp = themarr[i++];
while (themp != NULL) {
Notice1("opening connection to %s",
sockaddr_info(themp->ai_addr, themp->ai_addrlen,
infobuff, sizeof(infobuff)));
#if WITH_RETRY
if (sfd->forever || sfd->retry || ai_sorted[i] != NULL) {
if (sfd->forever || sfd->retry) {
level = E_INFO;
} else if (themarr[i] != NULL) {
level = E_WARN;
} else
#endif /* WITH_RETRY */
level = E_ERROR;
@ -133,7 +121,7 @@ int xioopen_ipapp_connect(
lowport, level);
if (result == STAT_OK)
break;
themp = ai_sorted[i++];
themp = themarr[i++];
if (themp == NULL) {
result = STAT_RETRYLATER;
}
@ -153,7 +141,7 @@ int xioopen_ipapp_connect(
}
#endif /* WITH_RETRY */
default:
free(ai_sorted);
xiofreeaddrinfo(themarr);
free(opts0);free(opts);
return result;
}
@ -170,7 +158,7 @@ int xioopen_ipapp_connect(
if (sfd->forever || --sfd->retry) {
Nanosleep(&sfd->intervall, NULL); continue;
}
free(ai_sorted);
xiofreeaddrinfo(themarr);
free(opts0);
return STAT_RETRYLATER;
}
@ -197,8 +185,7 @@ int xioopen_ipapp_connect(
}
} while (true);
/* only "active" process breaks (master without fork, or child) */
free(ai_sorted);
xiofreeaddrinfo(themlist);
xiofreeaddrinfo(themarr);
if ((result = _xio_openlate(sfd, opts)) < 0) {
free(opts0);free(opts);
@ -223,7 +210,7 @@ int
int *pf,
int protocol,
const int ai_flags[2],
struct addrinfo **themlist,
struct addrinfo ***themarr,
union sockaddr_union *us,
socklen_t *uslen,
bool *needbind,
@ -236,7 +223,7 @@ int
if (hostname != NULL || portname != NULL) {
rc = xiogetaddrinfo(hostname, portname, *pf, socktype, protocol,
themlist, ai_flags);
themarr, ai_flags);
if (rc == EAI_AGAIN) {
Warn4("_xioopen_ipapp_prepare(node=\"%s\", service=\"%s\", pf=%d, ...): %s",
hostname?hostname:"NULL", portname?portname:"NULL",
@ -253,13 +240,13 @@ int
applyopts(NULL, -1, opts, PH_EARLY);
/* 3 means: IP address AND port accepted */
if (retropt_bind(opts, (*pf!=PF_UNSPEC)?*pf:(*themlist)->ai_family,
if (retropt_bind(opts, (*pf!=PF_UNSPEC)?*pf:(**themarr)->ai_family,
socktype, protocol, (struct sockaddr *)us, uslen, 3,
ai_flags)
!= STAT_NOACTION) {
*needbind = true;
} else {
switch ((*pf!=PF_UNSPEC)?*pf:(*themlist)->ai_family) {
switch ((*pf!=PF_UNSPEC)?*pf:(**themarr)->ai_family) {
#if WITH_IP4
case PF_INET: socket_in_init(&us->ip4); *uslen = sizeof(us->ip4); break;
#endif /* WITH_IP4 */
@ -271,7 +258,7 @@ int
}
if (retropt_2bytes(opts, OPT_SOURCEPORT, &port) >= 0) {
switch ((*pf!=PF_UNSPEC)?*pf:(*themlist)->ai_family) {
switch ((*pf!=PF_UNSPEC)?*pf:(**themarr)->ai_family) {
#if WITH_IP4
case PF_INET: us->ip4.sin_port = htons(port); break;
#endif /* WITH_IP4 */
@ -397,60 +384,4 @@ int xioopen_ipapp_listen(
}
#endif /* WITH_IP4 && WITH_TCP && WITH_LISTEN */
/* Sort the records of an addrinfo list themp (as returned by getaddrinfo),
return the sorted list in the array ai_sorted (takes at most n entries
including the terminating NULL)
Returns 0 on success. */
int _xio_sort_ip_addresses(
struct addrinfo *themlist,
struct addrinfo **ai_sorted)
{
struct addrinfo *themp;
int i;
int ipv[3];
int ipi = 0;
/* Make a simple array of IP version preferences */
switch (xioparms.preferred_ip) {
case '0':
ipv[0] = PF_UNSPEC;
ipv[1] = -1;
break;
case '4':
ipv[0] = PF_INET;
ipv[1] = PF_INET6;
ipv[2] = -1;
break;
case '6':
ipv[0] = PF_INET6;
ipv[1] = PF_INET;
ipv[2] = -1;
break;
default:
Error("INTERNAL: undefined preferred_ip value");
return -1;
}
/* Create the sorted list */
ipi = 0;
i = 0;
while (ipv[ipi] >= 0) {
themp = themlist;
while (themp != NULL) {
if (ipv[ipi] == PF_UNSPEC) {
ai_sorted[i] = themp;
++i;
} else if (ipv[ipi] == themp->ai_family) {
ai_sorted[i] = themp;
++i;
}
themp = themp->ai_next;
}
++ipi;
}
ai_sorted[i] = NULL;
return 0;
}
#endif /* WITH_TCP || WITH_UDP */