mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-02 12:20:51 +00:00
Query DNS only once per an address family.
Obtained from: KAME MFC after: 2 weeks
This commit is contained in:
parent
6180d3185d
commit
bc42149220
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=190525
@ -102,7 +102,6 @@ __FBSDID("$FreeBSD$");
|
||||
# define FAITH
|
||||
#endif
|
||||
|
||||
#define SUCCESS 0
|
||||
#define ANY 0
|
||||
#define YES 1
|
||||
#define NO 0
|
||||
@ -179,11 +178,6 @@ static const struct explore explore[] = {
|
||||
{ PF_INET, SOCK_STREAM, IPPROTO_SCTP, "sctp", 0x03 },
|
||||
{ PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP, "sctp", 0x07 },
|
||||
{ PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
|
||||
{ PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
|
||||
{ PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
|
||||
{ PF_UNSPEC, SOCK_STREAM, IPPROTO_SCTP, "sctp", 0x03 },
|
||||
{ PF_UNSPEC, SOCK_SEQPACKET, IPPROTO_SCTP, "sctp", 0x07 },
|
||||
{ PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 },
|
||||
{ -1, 0, 0, NULL, 0 },
|
||||
};
|
||||
|
||||
@ -233,6 +227,8 @@ typedef union {
|
||||
} querybuf;
|
||||
|
||||
static int str2number(const char *, int *);
|
||||
static int explore_copy(const struct addrinfo *, const struct addrinfo *,
|
||||
struct addrinfo **);
|
||||
static int explore_null(const struct addrinfo *,
|
||||
const char *, struct addrinfo **);
|
||||
static int explore_numeric(const struct addrinfo *, const char *,
|
||||
@ -243,6 +239,7 @@ static int get_canonname(const struct addrinfo *,
|
||||
struct addrinfo *, const char *);
|
||||
static struct addrinfo *get_ai(const struct addrinfo *,
|
||||
const struct afd *, const char *);
|
||||
static struct addrinfo *copy_ai(const struct addrinfo *);
|
||||
static int get_portmatch(const struct addrinfo *, const char *);
|
||||
static int get_port(struct addrinfo *, const char *, int);
|
||||
static const struct afd *find_afd(int);
|
||||
@ -371,12 +368,23 @@ getaddrinfo(const char *hostname, const char *servname,
|
||||
struct addrinfo sentinel;
|
||||
struct addrinfo *cur;
|
||||
int error = 0;
|
||||
struct addrinfo ai;
|
||||
struct addrinfo ai0;
|
||||
struct addrinfo ai, ai0, *afai;
|
||||
struct addrinfo *pai;
|
||||
const struct afd *afd;
|
||||
const struct explore *ex;
|
||||
struct addrinfo *afailist[sizeof(afdl)/sizeof(afdl[0])];
|
||||
struct addrinfo *afai_unspec;
|
||||
int found;
|
||||
int numeric = 0;
|
||||
|
||||
/* ensure we return NULL on errors */
|
||||
*res = NULL;
|
||||
|
||||
memset(&ai, 0, sizeof(ai));
|
||||
|
||||
memset(afailist, 0, sizeof(afailist));
|
||||
afai_unspec = NULL;
|
||||
|
||||
memset(&sentinel, 0, sizeof(sentinel));
|
||||
cur = &sentinel;
|
||||
pai = &ai;
|
||||
@ -416,15 +424,18 @@ getaddrinfo(const char *hostname, const char *servname,
|
||||
*/
|
||||
if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
|
||||
for (ex = explore; ex->e_af >= 0; ex++) {
|
||||
if (pai->ai_family != ex->e_af)
|
||||
if (!MATCH_FAMILY(pai->ai_family, ex->e_af,
|
||||
WILD_AF(ex)))
|
||||
continue;
|
||||
if (ex->e_socktype == ANY)
|
||||
if (!MATCH(pai->ai_socktype, ex->e_socktype,
|
||||
WILD_SOCKTYPE(ex)))
|
||||
continue;
|
||||
if (ex->e_protocol == ANY)
|
||||
if (!MATCH(pai->ai_protocol, ex->e_protocol,
|
||||
WILD_PROTOCOL(ex)))
|
||||
continue;
|
||||
if (pai->ai_socktype == ex->e_socktype &&
|
||||
pai->ai_protocol == ex->e_protocol)
|
||||
break;
|
||||
|
||||
/* matched */
|
||||
break;
|
||||
}
|
||||
|
||||
if (ex->e_af < 0)
|
||||
@ -460,49 +471,48 @@ getaddrinfo(const char *hostname, const char *servname,
|
||||
|
||||
ai0 = *pai;
|
||||
|
||||
/* NULL hostname, or numeric hostname */
|
||||
for (ex = explore; ex->e_af >= 0; ex++) {
|
||||
/*
|
||||
* NULL hostname, or numeric hostname.
|
||||
* If numeric representation of AF1 can be interpreted as FQDN
|
||||
* representation of AF2, we need to think again about the code below.
|
||||
*/
|
||||
found = 0;
|
||||
for (afd = afdl; afd->a_af; afd++) {
|
||||
*pai = ai0;
|
||||
|
||||
/* PF_UNSPEC entries are prepared for DNS queries only */
|
||||
if (ex->e_af == PF_UNSPEC)
|
||||
continue;
|
||||
|
||||
if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
|
||||
continue;
|
||||
if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
|
||||
continue;
|
||||
if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
|
||||
if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1))
|
||||
continue;
|
||||
|
||||
if (pai->ai_family == PF_UNSPEC)
|
||||
pai->ai_family = ex->e_af;
|
||||
if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
|
||||
pai->ai_socktype = ex->e_socktype;
|
||||
if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
|
||||
pai->ai_protocol = ex->e_protocol;
|
||||
pai->ai_family = afd->a_af;
|
||||
|
||||
if (hostname == NULL)
|
||||
error = explore_null(pai, servname, &cur->ai_next);
|
||||
else
|
||||
if (hostname == NULL) {
|
||||
error = explore_null(pai, servname,
|
||||
&afailist[afd - afdl]);
|
||||
|
||||
/*
|
||||
* Errors from explore_null should be unexpected and
|
||||
* be caught to avoid returning an incomplete result.
|
||||
*/
|
||||
if (error != 0)
|
||||
goto bad;
|
||||
} else {
|
||||
error = explore_numeric_scope(pai, hostname, servname,
|
||||
&cur->ai_next);
|
||||
&afailist[afd - afdl]);
|
||||
|
||||
if (error)
|
||||
goto free;
|
||||
/*
|
||||
* explore_numeric_scope returns an error for address
|
||||
* families that do not match that of hostname.
|
||||
* Thus we should not catch the error at this moment.
|
||||
*/
|
||||
}
|
||||
|
||||
while (cur && cur->ai_next)
|
||||
cur = cur->ai_next;
|
||||
if (!error && afailist[afd - afdl])
|
||||
found++;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* If numreic representation of AF1 can be interpreted as FQDN
|
||||
* representation of AF2, we need to think again about the code below.
|
||||
*/
|
||||
if (sentinel.ai_next) {
|
||||
if (found) {
|
||||
numeric = 1;
|
||||
goto good;
|
||||
goto globcopy;
|
||||
}
|
||||
|
||||
if (hostname == NULL)
|
||||
@ -515,42 +525,55 @@ getaddrinfo(const char *hostname, const char *servname,
|
||||
|
||||
/*
|
||||
* hostname as alphabetical name.
|
||||
* we would like to prefer AF_INET6 than AF_INET, so we'll make a
|
||||
* outer loop by AFs.
|
||||
*/
|
||||
*pai = ai0;
|
||||
error = explore_fqdn(pai, hostname, servname, &afai_unspec);
|
||||
|
||||
globcopy:
|
||||
for (ex = explore; ex->e_af >= 0; ex++) {
|
||||
*pai = ai0;
|
||||
|
||||
/* require exact match for family field */
|
||||
if (pai->ai_family != ex->e_af)
|
||||
if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
|
||||
continue;
|
||||
|
||||
if (!MATCH(pai->ai_socktype, ex->e_socktype,
|
||||
WILD_SOCKTYPE(ex))) {
|
||||
WILD_SOCKTYPE(ex)))
|
||||
continue;
|
||||
}
|
||||
if (!MATCH(pai->ai_protocol, ex->e_protocol,
|
||||
WILD_PROTOCOL(ex))) {
|
||||
WILD_PROTOCOL(ex)))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pai->ai_family == PF_UNSPEC)
|
||||
pai->ai_family = ex->e_af;
|
||||
if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
|
||||
pai->ai_socktype = ex->e_socktype;
|
||||
if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
|
||||
pai->ai_protocol = ex->e_protocol;
|
||||
|
||||
error = explore_fqdn(pai, hostname, servname,
|
||||
&cur->ai_next);
|
||||
/*
|
||||
* if the servname does not match socktype/protocol, ignore it.
|
||||
*/
|
||||
if (get_portmatch(pai, servname) != 0)
|
||||
continue;
|
||||
|
||||
if (afai_unspec)
|
||||
afai = afai_unspec;
|
||||
else {
|
||||
if ((afd = find_afd(pai->ai_family)) == NULL)
|
||||
continue;
|
||||
/* XXX assumes that afd points inside afdl[] */
|
||||
afai = afailist[afd - afdl];
|
||||
}
|
||||
if (!afai)
|
||||
continue;
|
||||
|
||||
error = explore_copy(pai, afai, &cur->ai_next);
|
||||
if (error != 0)
|
||||
goto bad;
|
||||
|
||||
while (cur && cur->ai_next)
|
||||
cur = cur->ai_next;
|
||||
}
|
||||
|
||||
/* XXX inhibit errors if we have the result */
|
||||
if (sentinel.ai_next)
|
||||
error = 0;
|
||||
|
||||
good:
|
||||
/*
|
||||
* ensure we return either:
|
||||
* - error == 0, non-NULL *res
|
||||
@ -586,16 +609,22 @@ getaddrinfo(const char *hostname, const char *servname,
|
||||
}
|
||||
}
|
||||
*res = sentinel.ai_next;
|
||||
return SUCCESS;
|
||||
} else
|
||||
error = EAI_FAIL;
|
||||
}
|
||||
free:
|
||||
|
||||
bad:
|
||||
if (sentinel.ai_next)
|
||||
freeaddrinfo(sentinel.ai_next);
|
||||
*res = NULL;
|
||||
return error;
|
||||
if (afai_unspec)
|
||||
freeaddrinfo(afai_unspec);
|
||||
for (afd = afdl; afd->a_af; afd++) {
|
||||
if (afailist[afd - afdl])
|
||||
freeaddrinfo(afailist[afd - afdl]);
|
||||
}
|
||||
if (!*res)
|
||||
if (sentinel.ai_next)
|
||||
freeaddrinfo(sentinel.ai_next);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1047,6 +1076,41 @@ gai_addr2scopetype(struct sockaddr *sa)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
explore_copy(const struct addrinfo *pai, const struct addrinfo *src0,
|
||||
struct addrinfo **res)
|
||||
{
|
||||
int error;
|
||||
struct addrinfo sentinel, *cur;
|
||||
const struct addrinfo *src;
|
||||
|
||||
error = 0;
|
||||
sentinel.ai_next = NULL;
|
||||
cur = &sentinel;
|
||||
|
||||
for (src = src0; src != NULL; src = src->ai_next) {
|
||||
if (src->ai_family != pai->ai_family)
|
||||
continue;
|
||||
|
||||
cur->ai_next = copy_ai(src);
|
||||
if (!cur->ai_next) {
|
||||
error = EAI_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
cur->ai_next->ai_socktype = pai->ai_socktype;
|
||||
cur->ai_next->ai_protocol = pai->ai_protocol;
|
||||
cur = cur->ai_next;
|
||||
}
|
||||
|
||||
*res = sentinel.ai_next;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
freeaddrinfo(sentinel.ai_next);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* hostname == NULL.
|
||||
* passive socket -> anyaddr (0.0.0.0 or ::)
|
||||
@ -1075,12 +1139,6 @@ explore_null(const struct addrinfo *pai, const char *servname,
|
||||
} else
|
||||
_close(s);
|
||||
|
||||
/*
|
||||
* if the servname does not match socktype/protocol, ignore it.
|
||||
*/
|
||||
if (get_portmatch(pai, servname) != 0)
|
||||
return 0;
|
||||
|
||||
afd = find_afd(pai->ai_family);
|
||||
if (afd == NULL)
|
||||
return 0;
|
||||
@ -1117,12 +1175,6 @@ explore_numeric(const struct addrinfo *pai, const char *hostname,
|
||||
*res = NULL;
|
||||
ai = NULL;
|
||||
|
||||
/*
|
||||
* if the servname does not match socktype/protocol, ignore it.
|
||||
*/
|
||||
if (get_portmatch(pai, servname) != 0)
|
||||
return 0;
|
||||
|
||||
afd = find_afd(pai->ai_family);
|
||||
if (afd == NULL)
|
||||
return 0;
|
||||
@ -1189,12 +1241,6 @@ explore_numeric_scope(const struct addrinfo *pai, const char *hostname,
|
||||
char *cp, *hostname2 = NULL, *scope, *addr;
|
||||
struct sockaddr_in6 *sin6;
|
||||
|
||||
/*
|
||||
* if the servname does not match socktype/protocol, ignore it.
|
||||
*/
|
||||
if (get_portmatch(pai, servname) != 0)
|
||||
return 0;
|
||||
|
||||
afd = find_afd(pai->ai_family);
|
||||
if (afd == NULL)
|
||||
return 0;
|
||||
@ -1227,6 +1273,8 @@ explore_numeric_scope(const struct addrinfo *pai, const char *hostname,
|
||||
sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
|
||||
if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) {
|
||||
free(hostname2);
|
||||
freeaddrinfo(*res);
|
||||
*res = NULL;
|
||||
return(EAI_NONAME); /* XXX: is return OK? */
|
||||
}
|
||||
sin6->sin6_scope_id = scopeid;
|
||||
@ -1235,6 +1283,10 @@ explore_numeric_scope(const struct addrinfo *pai, const char *hostname,
|
||||
|
||||
free(hostname2);
|
||||
|
||||
if (error && *res) {
|
||||
freeaddrinfo(*res);
|
||||
*res = NULL;
|
||||
}
|
||||
return error;
|
||||
#endif
|
||||
}
|
||||
@ -1318,6 +1370,38 @@ get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr)
|
||||
return ai;
|
||||
}
|
||||
|
||||
/* XXX need to malloc() the same way we do from other functions! */
|
||||
static struct addrinfo *
|
||||
copy_ai(const struct addrinfo *pai)
|
||||
{
|
||||
struct addrinfo *ai;
|
||||
size_t l;
|
||||
|
||||
l = sizeof(*ai) + pai->ai_addrlen;
|
||||
if ((ai = (struct addrinfo *)malloc(l)) == NULL)
|
||||
return NULL;
|
||||
memset(ai, 0, l);
|
||||
memcpy(ai, pai, sizeof(*ai));
|
||||
ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
|
||||
memcpy(ai->ai_addr, pai->ai_addr, pai->ai_addrlen);
|
||||
|
||||
if (pai->ai_canonname) {
|
||||
l = strlen(pai->ai_canonname) + 1;
|
||||
if ((ai->ai_canonname = malloc(l)) == NULL) {
|
||||
free(ai);
|
||||
return NULL;
|
||||
}
|
||||
strlcpy(ai->ai_canonname, pai->ai_canonname, l);
|
||||
} else {
|
||||
/* just to make sure */
|
||||
ai->ai_canonname = NULL;
|
||||
}
|
||||
|
||||
ai->ai_next = NULL;
|
||||
|
||||
return ai;
|
||||
}
|
||||
|
||||
static int
|
||||
get_portmatch(const struct addrinfo *ai, const char *servname)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user