PR/32373, PR/25827: Add SRV lookup in getaddrinfo(3)
Per DNS-SD (RFC 2782), but only enabled if AI_SRV is set.
This commit is contained in:
parent
0a312e0850
commit
c641632a69
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: getaddrinfo.c,v 1.102 2013/05/03 19:24:52 christos Exp $ */
|
||||
/* $NetBSD: getaddrinfo.c,v 1.103 2013/05/03 19:31:13 christos Exp $ */
|
||||
/* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */
|
||||
|
||||
/*
|
||||
@ -55,7 +55,7 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
__RCSID("$NetBSD: getaddrinfo.c,v 1.102 2013/05/03 19:24:52 christos Exp $");
|
||||
__RCSID("$NetBSD: getaddrinfo.c,v 1.103 2013/05/03 19:31:13 christos Exp $");
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include "namespace.h"
|
||||
@ -191,6 +191,13 @@ struct res_target {
|
||||
int n; /* result length */
|
||||
};
|
||||
|
||||
struct srvinfo {
|
||||
struct srvinfo *next;
|
||||
char name[MAXDNAME];
|
||||
int port, pri, weight;
|
||||
};
|
||||
|
||||
static int gai_srvok(const char *);
|
||||
static int str2number(const char *);
|
||||
static int explore_fqdn(const struct addrinfo *, const char *,
|
||||
const char *, struct addrinfo **, struct servent_data *);
|
||||
@ -217,6 +224,12 @@ static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *);
|
||||
static struct addrinfo *getanswer(const querybuf *, int, const char *, int,
|
||||
const struct addrinfo *);
|
||||
static void aisort(struct addrinfo *s, res_state res);
|
||||
static struct addrinfo * _dns_query(struct res_target *,
|
||||
const struct addrinfo *, res_state, int);
|
||||
static struct addrinfo * _dns_srv_lookup(const char *, const char *,
|
||||
const struct addrinfo *);
|
||||
static struct addrinfo * _dns_host_lookup(const char *,
|
||||
const struct addrinfo *);
|
||||
static int _dns_getaddrinfo(void *, void *, va_list);
|
||||
static void _sethtent(FILE **);
|
||||
static void _endhtent(FILE **);
|
||||
@ -319,6 +332,58 @@ freeaddrinfo(struct addrinfo *ai)
|
||||
} while (ai);
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't want localization to affect us
|
||||
*/
|
||||
#define PERIOD '.'
|
||||
#define hyphenchar(c) ((c) == '-')
|
||||
#define periodchar(c) ((c) == PERIOD)
|
||||
#define underschar(c) ((c) == '_')
|
||||
#define alphachar(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
|
||||
#define digitchar(c) ((c) >= '0' && (c) <= '9')
|
||||
|
||||
#define firstchar(c) (alphachar(c) || digitchar(c) || underschar(c))
|
||||
#define lastchar(c) (alphachar(c) || digitchar(c))
|
||||
#define middlechar(c) (lastchar(c) || hyphenchar(c))
|
||||
|
||||
static int
|
||||
gai_srvok(const char *dn)
|
||||
{
|
||||
int nch, pch, ch;
|
||||
|
||||
for (pch = PERIOD, nch = ch = *dn++; ch != '\0'; pch = ch, ch = nch) {
|
||||
if (periodchar(ch))
|
||||
continue;
|
||||
if (periodchar(pch)) {
|
||||
if (!firstchar(ch))
|
||||
return 0;
|
||||
} else if (periodchar(nch) || nch == '\0') {
|
||||
if (!lastchar(ch))
|
||||
return 0;
|
||||
} else if (!middlechar(ch))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static in_port_t *
|
||||
getport(struct addrinfo *ai) {
|
||||
static in_port_t p;
|
||||
|
||||
switch (ai->ai_family) {
|
||||
case AF_INET:
|
||||
return &((struct sockaddr_in *)(void *)ai->ai_addr)->sin_port;
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
return &((struct sockaddr_in6 *)(void *)ai->ai_addr)->sin6_port;
|
||||
#endif
|
||||
default:
|
||||
p = 0;
|
||||
/* XXX: abort()? */
|
||||
return &p;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
str2number(const char *p)
|
||||
{
|
||||
@ -589,7 +654,7 @@ explore_fqdn(const struct addrinfo *pai, const char *hostname,
|
||||
return 0;
|
||||
|
||||
switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
|
||||
default_dns_files, hostname, pai)) {
|
||||
default_dns_files, hostname, pai, servname)) {
|
||||
case NS_TRYAGAIN:
|
||||
error = EAI_AGAIN;
|
||||
goto free;
|
||||
@ -602,6 +667,9 @@ explore_fqdn(const struct addrinfo *pai, const char *hostname,
|
||||
case NS_SUCCESS:
|
||||
error = 0;
|
||||
for (cur = result; cur; cur = cur->ai_next) {
|
||||
/* Check for already filled port. */
|
||||
if (*getport(cur))
|
||||
continue;
|
||||
GET_PORT(cur, servname, svd);
|
||||
/* canonname should be filled already */
|
||||
}
|
||||
@ -990,21 +1058,8 @@ get_port(const struct addrinfo *ai, const char *servname, int matchonly,
|
||||
port = sp->s_port;
|
||||
}
|
||||
|
||||
if (!matchonly) {
|
||||
switch (ai->ai_family) {
|
||||
case AF_INET:
|
||||
((struct sockaddr_in *)(void *)
|
||||
ai->ai_addr)->sin_port = port;
|
||||
break;
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
((struct sockaddr_in6 *)(void *)
|
||||
ai->ai_addr)->sin6_port = port;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (!matchonly)
|
||||
*getport(__UNCONST(ai)) = port;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1107,7 +1162,7 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
|
||||
const struct addrinfo *pai)
|
||||
{
|
||||
struct addrinfo sentinel, *cur;
|
||||
struct addrinfo ai;
|
||||
struct addrinfo ai, *aip;
|
||||
const struct afd *afd;
|
||||
char *canonname;
|
||||
const HEADER *hp;
|
||||
@ -1120,6 +1175,8 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
|
||||
char tbuf[MAXDNAME];
|
||||
int (*name_ok) (const char *);
|
||||
char hostbuf[8*1024];
|
||||
int port, pri, weight;
|
||||
struct srvinfo *srvlist, *srv, *csrv;
|
||||
|
||||
_DIAGASSERT(answer != NULL);
|
||||
_DIAGASSERT(qname != NULL);
|
||||
@ -1136,6 +1193,9 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
|
||||
case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/
|
||||
name_ok = res_hnok;
|
||||
break;
|
||||
case T_SRV:
|
||||
name_ok = gai_srvok;
|
||||
break;
|
||||
default:
|
||||
return NULL; /* XXX should be abort(); */
|
||||
}
|
||||
@ -1175,6 +1235,7 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
|
||||
}
|
||||
haveanswer = 0;
|
||||
had_error = 0;
|
||||
srvlist = NULL;
|
||||
while (ancount-- > 0 && cp < eom && !had_error) {
|
||||
n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
|
||||
if ((n < 0) || !(*name_ok)(bp)) {
|
||||
@ -1277,17 +1338,116 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
|
||||
cur = cur->ai_next;
|
||||
cp += n;
|
||||
break;
|
||||
case T_SRV:
|
||||
/* Add to SRV list. Insertion sort on priority. */
|
||||
pri = _getshort(cp);
|
||||
cp += INT16SZ;
|
||||
weight = _getshort(cp);
|
||||
cp += INT16SZ;
|
||||
port = _getshort(cp);
|
||||
cp += INT16SZ;
|
||||
n = dn_expand(answer->buf, eom, cp, tbuf,
|
||||
(int)sizeof(tbuf));
|
||||
if ((n < 0) || !res_hnok(tbuf)) {
|
||||
had_error++;
|
||||
continue;
|
||||
}
|
||||
cp += n;
|
||||
if (strlen(tbuf) + 1 >= MAXDNAME) {
|
||||
had_error++;
|
||||
continue;
|
||||
}
|
||||
srv = malloc(sizeof(*srv));
|
||||
if (!srv) {
|
||||
had_error++;
|
||||
continue;
|
||||
}
|
||||
strlcpy(srv->name, tbuf, sizeof(srv->name));
|
||||
srv->pri = pri;
|
||||
srv->weight = weight;
|
||||
srv->port = port;
|
||||
/* Weight 0 is sorted before other weights. */
|
||||
if (!srvlist
|
||||
|| srv->pri < srvlist->pri
|
||||
|| (srv->pri == srvlist->pri &&
|
||||
(!srv->weight || srvlist->weight))) {
|
||||
srv->next = srvlist;
|
||||
srvlist = srv;
|
||||
} else {
|
||||
for (csrv = srvlist;
|
||||
csrv->next && csrv->next->pri <= srv->pri;
|
||||
csrv = csrv->next) {
|
||||
if (csrv->next->pri == srv->pri
|
||||
&& (!srv->weight ||
|
||||
csrv->next->weight))
|
||||
break;
|
||||
}
|
||||
srv->next = csrv->next;
|
||||
csrv->next = srv;
|
||||
}
|
||||
continue; /* Don't add to haveanswer yet. */
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
if (!had_error)
|
||||
haveanswer++;
|
||||
}
|
||||
|
||||
if (srvlist) {
|
||||
res_state res;
|
||||
/*
|
||||
* Check for explicit rejection.
|
||||
*/
|
||||
if (!srvlist->next && !srvlist->name[0]) {
|
||||
free(srvlist);
|
||||
h_errno = HOST_NOT_FOUND;
|
||||
return NULL;
|
||||
}
|
||||
res = __res_get_state();
|
||||
if (res == NULL) {
|
||||
h_errno = NETDB_INTERNAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (srvlist) {
|
||||
struct res_target q, q2;
|
||||
|
||||
srv = srvlist;
|
||||
srvlist = srvlist->next;
|
||||
|
||||
/*
|
||||
* Since res_* doesn't give the additional
|
||||
* section, we always look up.
|
||||
*/
|
||||
memset(&q, 0, sizeof(q));
|
||||
memset(&q2, 0, sizeof(q2));
|
||||
|
||||
q.name = srv->name;
|
||||
q.qclass = C_IN;
|
||||
q.qtype = T_AAAA;
|
||||
q.next = &q2;
|
||||
q2.name = srv->name;
|
||||
q2.qclass = C_IN;
|
||||
q2.qtype = T_A;
|
||||
|
||||
aip = _dns_query(&q, pai, res, 0);
|
||||
|
||||
if (aip != NULL) {
|
||||
cur->ai_next = aip;
|
||||
while (cur && cur->ai_next) {
|
||||
cur = cur->ai_next;
|
||||
*getport(cur) = htons(srv->port);
|
||||
haveanswer++;
|
||||
}
|
||||
}
|
||||
free(srv);
|
||||
}
|
||||
__res_put_state(res);
|
||||
}
|
||||
if (haveanswer) {
|
||||
if (!canonname)
|
||||
(void)get_canonname(pai, sentinel.ai_next, qname);
|
||||
else
|
||||
(void)get_canonname(pai, sentinel.ai_next, canonname);
|
||||
if (!sentinel.ai_next->ai_canonname)
|
||||
(void)get_canonname(pai, sentinel.ai_next,
|
||||
canonname ? canonname : qname);
|
||||
h_errno = NETDB_SUCCESS;
|
||||
return sentinel.ai_next;
|
||||
}
|
||||
@ -1327,109 +1487,136 @@ aisort(struct addrinfo *s, res_state res)
|
||||
s->ai_next = head.ai_next;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
_dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
|
||||
static struct addrinfo *
|
||||
_dns_query(struct res_target *q, const struct addrinfo *pai,
|
||||
res_state res, int dosearch)
|
||||
{
|
||||
struct addrinfo *ai;
|
||||
querybuf *buf, *buf2;
|
||||
const char *name;
|
||||
const struct addrinfo *pai;
|
||||
struct addrinfo sentinel, *cur;
|
||||
struct res_target q, q2;
|
||||
res_state res;
|
||||
struct res_target *q2 = q->next;
|
||||
querybuf *buf, *buf2;
|
||||
struct addrinfo sentinel, *cur, *ai;
|
||||
|
||||
name = va_arg(ap, char *);
|
||||
pai = va_arg(ap, const struct addrinfo *);
|
||||
#ifdef DNS_DEBUG
|
||||
struct res_target *iter;
|
||||
for (iter = q; iter; iter = iter->next)
|
||||
printf("Query type %d for %s\n", iter->qtype, iter->name);
|
||||
#endif
|
||||
|
||||
buf = malloc(sizeof(*buf));
|
||||
if (buf == NULL) {
|
||||
h_errno = NETDB_INTERNAL;
|
||||
return NULL;
|
||||
}
|
||||
buf2 = malloc(sizeof(*buf2));
|
||||
if (buf2 == NULL) {
|
||||
free(buf);
|
||||
h_errno = NETDB_INTERNAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(&q, 0, sizeof(q));
|
||||
memset(&q2, 0, sizeof(q2));
|
||||
memset(&sentinel, 0, sizeof(sentinel));
|
||||
cur = &sentinel;
|
||||
|
||||
buf = malloc(sizeof(*buf));
|
||||
if (buf == NULL) {
|
||||
h_errno = NETDB_INTERNAL;
|
||||
return NS_NOTFOUND;
|
||||
}
|
||||
buf2 = malloc(sizeof(*buf2));
|
||||
if (buf2 == NULL) {
|
||||
free(buf);
|
||||
h_errno = NETDB_INTERNAL;
|
||||
return NS_NOTFOUND;
|
||||
q->answer = buf->buf;
|
||||
q->anslen = sizeof(buf->buf);
|
||||
if (q2) {
|
||||
q2->answer = buf2->buf;
|
||||
q2->anslen = sizeof(buf2->buf);
|
||||
}
|
||||
|
||||
switch (pai->ai_family) {
|
||||
case AF_UNSPEC:
|
||||
/* prefer IPv6 */
|
||||
q.name = name;
|
||||
q.qclass = C_IN;
|
||||
q.qtype = T_AAAA;
|
||||
q.answer = buf->buf;
|
||||
q.anslen = sizeof(buf->buf);
|
||||
q.next = &q2;
|
||||
q2.name = name;
|
||||
q2.qclass = C_IN;
|
||||
q2.qtype = T_A;
|
||||
q2.answer = buf2->buf;
|
||||
q2.anslen = sizeof(buf2->buf);
|
||||
break;
|
||||
case AF_INET:
|
||||
q.name = name;
|
||||
q.qclass = C_IN;
|
||||
q.qtype = T_A;
|
||||
q.answer = buf->buf;
|
||||
q.anslen = sizeof(buf->buf);
|
||||
break;
|
||||
case AF_INET6:
|
||||
q.name = name;
|
||||
q.qclass = C_IN;
|
||||
q.qtype = T_AAAA;
|
||||
q.answer = buf->buf;
|
||||
q.anslen = sizeof(buf->buf);
|
||||
break;
|
||||
default:
|
||||
free(buf);
|
||||
free(buf2);
|
||||
return NS_UNAVAIL;
|
||||
if (dosearch) {
|
||||
if (res_searchN(q->name, q, res) < 0)
|
||||
goto out;
|
||||
} else {
|
||||
if (res_queryN(q->name, q, res) < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = __res_get_state();
|
||||
if (res == NULL) {
|
||||
free(buf);
|
||||
free(buf2);
|
||||
return NS_NOTFOUND;
|
||||
}
|
||||
|
||||
if (res_searchN(name, &q, res) < 0) {
|
||||
__res_put_state(res);
|
||||
free(buf);
|
||||
free(buf2);
|
||||
return NS_NOTFOUND;
|
||||
}
|
||||
ai = getanswer(buf, q.n, q.name, q.qtype, pai);
|
||||
ai = getanswer(buf, q->n, q->name, q->qtype, pai);
|
||||
if (ai) {
|
||||
cur->ai_next = ai;
|
||||
while (cur && cur->ai_next)
|
||||
cur = cur->ai_next;
|
||||
}
|
||||
if (q.next) {
|
||||
ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai);
|
||||
if (q2) {
|
||||
ai = getanswer(buf2, q2->n, q2->name, q2->qtype, pai);
|
||||
if (ai)
|
||||
cur->ai_next = ai;
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
free(buf2);
|
||||
if (sentinel.ai_next == NULL) {
|
||||
__res_put_state(res);
|
||||
switch (h_errno) {
|
||||
case HOST_NOT_FOUND:
|
||||
return NS_NOTFOUND;
|
||||
case TRY_AGAIN:
|
||||
return NS_TRYAGAIN;
|
||||
default:
|
||||
return NS_UNAVAIL;
|
||||
return sentinel.ai_next;
|
||||
out:
|
||||
free(buf);
|
||||
free(buf2);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static struct addrinfo *
|
||||
_dns_srv_lookup(const char *name, const char *servname,
|
||||
const struct addrinfo *pai)
|
||||
{
|
||||
static const char * const srvprotos[] = { "tcp", "udp" };
|
||||
static const int srvnottype[] = { SOCK_DGRAM, SOCK_STREAM };
|
||||
static const int nsrvprotos = 2;
|
||||
struct addrinfo sentinel, *cur, *ai;
|
||||
struct servent *serv, sv;
|
||||
struct servent_data svd;
|
||||
struct res_target q;
|
||||
res_state res;
|
||||
char *tname;
|
||||
int i;
|
||||
|
||||
res = __res_get_state();
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(&svd, 0, sizeof(svd));
|
||||
memset(&sentinel, 0, sizeof(sentinel));
|
||||
cur = &sentinel;
|
||||
|
||||
/*
|
||||
* Iterate over supported SRV protocols.
|
||||
* (currently UDP and TCP only)
|
||||
*/
|
||||
for (i = 0; i < nsrvprotos; i++) {
|
||||
/*
|
||||
* Check that the caller didn't specify a hint
|
||||
* which precludes this protocol.
|
||||
*/
|
||||
if (pai->ai_socktype == srvnottype[i])
|
||||
continue;
|
||||
/*
|
||||
* If the caller specified a port,
|
||||
* then lookup the database for the
|
||||
* official service name.
|
||||
*/
|
||||
serv = getservbyname_r(servname, srvprotos[i], &sv, &svd);
|
||||
if (serv == NULL)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Construct service DNS name.
|
||||
*/
|
||||
if (asprintf(&tname, "_%s._%s.%s", serv->s_name, serv->s_proto,
|
||||
name) < 0)
|
||||
continue;
|
||||
|
||||
memset(&q, 0, sizeof(q));
|
||||
q.name = tname;
|
||||
q.qclass = C_IN;
|
||||
q.qtype = T_SRV;
|
||||
|
||||
/*
|
||||
* Do SRV query.
|
||||
*/
|
||||
ai = _dns_query(&q, pai, res, 1);
|
||||
if (ai) {
|
||||
cur->ai_next = ai;
|
||||
while (cur && cur->ai_next)
|
||||
cur = cur->ai_next;
|
||||
}
|
||||
free(tname);
|
||||
}
|
||||
|
||||
if (res->nsort)
|
||||
@ -1437,7 +1624,114 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
|
||||
|
||||
__res_put_state(res);
|
||||
|
||||
*((struct addrinfo **)rv) = sentinel.ai_next;
|
||||
return sentinel.ai_next;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static struct addrinfo *
|
||||
_dns_host_lookup(const char *name, const struct addrinfo *pai)
|
||||
{
|
||||
struct res_target q, q2;
|
||||
struct addrinfo sentinel, *ai;
|
||||
res_state res;
|
||||
|
||||
res = __res_get_state();
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(&q, 0, sizeof(q2));
|
||||
memset(&q2, 0, sizeof(q2));
|
||||
|
||||
switch (pai->ai_family) {
|
||||
case AF_UNSPEC:
|
||||
/* prefer IPv6 */
|
||||
q.name = name;
|
||||
q.qclass = C_IN;
|
||||
q.qtype = T_AAAA;
|
||||
q.next = &q2;
|
||||
q2.name = name;
|
||||
q2.qclass = C_IN;
|
||||
q2.qtype = T_A;
|
||||
break;
|
||||
case AF_INET:
|
||||
q.name = name;
|
||||
q.qclass = C_IN;
|
||||
q.qtype = T_A;
|
||||
break;
|
||||
case AF_INET6:
|
||||
q.name = name;
|
||||
q.qclass = C_IN;
|
||||
q.qtype = T_AAAA;
|
||||
break;
|
||||
default:
|
||||
h_errno = NETDB_INTERNAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ai = _dns_query(&q, pai, res, 1);
|
||||
|
||||
memset(&sentinel, 0, sizeof(sentinel));
|
||||
sentinel.ai_next = ai;
|
||||
|
||||
if (ai != NULL && res->nsort)
|
||||
aisort(&sentinel, res);
|
||||
|
||||
__res_put_state(res);
|
||||
|
||||
return sentinel.ai_next;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
_dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
|
||||
{
|
||||
struct addrinfo *ai = NULL;
|
||||
const char *name, *servname;
|
||||
const struct addrinfo *pai;
|
||||
|
||||
name = va_arg(ap, char *);
|
||||
pai = va_arg(ap, const struct addrinfo *);
|
||||
servname = va_arg(ap, char *);
|
||||
|
||||
/*
|
||||
* Try doing SRV lookup on service first.
|
||||
*/
|
||||
if (servname
|
||||
#ifdef AI_SRV
|
||||
&& (pai->ai_flags & AI_SRV)
|
||||
#endif
|
||||
&& !(pai->ai_flags & AI_NUMERICSERV)
|
||||
&& str2number(servname) == -1) {
|
||||
|
||||
#ifdef DNS_DEBUG
|
||||
printf("%s: try SRV lookup\n", __func__);
|
||||
#endif
|
||||
ai = _dns_srv_lookup(name, servname, pai);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do lookup on name.
|
||||
*/
|
||||
if (ai == NULL) {
|
||||
|
||||
#ifdef DNS_DEBUG
|
||||
printf("%s: try HOST lookup\n", __func__);
|
||||
#endif
|
||||
ai = _dns_host_lookup(name, pai);
|
||||
|
||||
if (ai == NULL) {
|
||||
switch (h_errno) {
|
||||
case HOST_NOT_FOUND:
|
||||
return NS_NOTFOUND;
|
||||
case TRY_AGAIN:
|
||||
return NS_TRYAGAIN;
|
||||
default:
|
||||
return NS_UNAVAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*((struct addrinfo **)rv) = ai;
|
||||
return NS_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1996,3 +2290,33 @@ res_querydomainN(const char *name, const char *domain,
|
||||
}
|
||||
return res_queryN(longname, target, res);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
struct addrinfo *ai, *sai;
|
||||
int i, e;
|
||||
char buf[1024];
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if ((e = getaddrinfo(argv[i], NULL, NULL, &sai)) != 0)
|
||||
warnx("%s: %s", argv[i], gai_strerror(e));
|
||||
for (ai = sai; ai; ai = ai->ai_next) {
|
||||
sockaddr_snprintf(buf, sizeof(buf), "%a", ai->ai_addr);
|
||||
printf("flags=0x%x family=%d socktype=%d protocol=%d "
|
||||
"addrlen=%zu addr=%s canonname=%s next=%p\n",
|
||||
ai->ai_flags,
|
||||
ai->ai_family,
|
||||
ai->ai_socktype,
|
||||
ai->ai_protocol,
|
||||
(size_t)ai->ai_addrlen,
|
||||
buf,
|
||||
ai->ai_canonname,
|
||||
ai->ai_next);
|
||||
}
|
||||
if (sai)
|
||||
freeaddrinfo(sai);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user