1
0
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:
Hajimu UMEMOTO 2009-03-29 17:55:11 +00:00
parent 6180d3185d
commit bc42149220
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=190525

View File

@ -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)
{