#ifdef KRB5_DNS_LOOKUP
#include "dnsglue.h"
struct krb5int_dns_state {
int nclass;
int ntype;
void *ansp;
int anslen;
int ansmax;
#if HAVE_NS_INITPARSE
int cur_ans;
ns_msg msg;
#else
unsigned char *ptr;
unsigned short nanswers;
#endif
};
#if !HAVE_NS_INITPARSE
static int initparse(struct krb5int_dns_state *);
#endif
int
krb5int_dns_init(struct krb5int_dns_state **dsp,
char *host, int nclass, int ntype)
{
#if HAVE_RES_NSEARCH
struct __res_state statbuf;
#endif
struct krb5int_dns_state *ds;
int len, ret;
size_t nextincr, maxincr;
unsigned char *p;
*dsp = ds = malloc(sizeof(*ds));
if (ds == NULL)
return -1;
ret = -1;
ds->nclass = nclass;
ds->ntype = ntype;
ds->ansp = NULL;
ds->anslen = 0;
ds->ansmax = 0;
nextincr = 2048;
maxincr = INT_MAX;
#if HAVE_NS_INITPARSE
ds->cur_ans = 0;
#endif
#if HAVE_RES_NSEARCH
ret = res_ninit(&statbuf);
if (ret < 0)
return -1;
#endif
do {
p = (ds->ansp == NULL)
? malloc(nextincr) : realloc(ds->ansp, nextincr);
if (p == NULL && ds->ansp != NULL) {
ret = -1;
goto errout;
}
ds->ansp = p;
ds->ansmax = nextincr;
#if HAVE_RES_NSEARCH
len = res_nsearch(&statbuf, host, ds->nclass, ds->ntype,
ds->ansp, ds->ansmax);
#else
len = res_search(host, ds->nclass, ds->ntype,
ds->ansp, ds->ansmax);
#endif
if (len > maxincr) {
ret = -1;
goto errout;
}
while (nextincr < len)
nextincr *= 2;
if (len < 0 || nextincr > maxincr) {
ret = -1;
goto errout;
}
} while (len > ds->ansmax);
ds->anslen = len;
#if HAVE_NS_INITPARSE
ret = ns_initparse(ds->ansp, ds->anslen, &ds->msg);
#else
ret = initparse(ds);
#endif
if (ret < 0)
goto errout;
ret = 0;
errout:
#if HAVE_RES_NSEARCH
#if HAVE_RES_NDESTROY
res_ndestroy(&statbuf);
if (statbuf._u._ext.ext != NULL) free(statbuf._u._ext.ext);
statbuf._u._ext.ext = NULL;
#else
res_nclose(&statbuf);
#endif
#endif
if (ret < 0) {
if (ds->ansp != NULL) {
free(ds->ansp);
ds->ansp = NULL;
}
}
return ret;
}
#if HAVE_NS_INITPARSE
int
krb5int_dns_nextans(struct krb5int_dns_state *ds,
const unsigned char **pp, int *lenp)
{
int len;
ns_rr rr;
*pp = NULL;
*lenp = 0;
while (ds->cur_ans < ns_msg_count(ds->msg, ns_s_an)) {
len = ns_parserr(&ds->msg, ns_s_an, ds->cur_ans, &rr);
if (len < 0)
return -1;
ds->cur_ans++;
if (ds->nclass == ns_rr_class(rr)
&& ds->ntype == ns_rr_type(rr)) {
*pp = ns_rr_rdata(rr);
*lenp = ns_rr_rdlen(rr);
return 0;
}
}
return 0;
}
#endif
int krb5int_dns_expand(struct krb5int_dns_state *ds,
const unsigned char *p,
char *buf, int len)
{
#if HAVE_NS_NAME_UNCOMPRESS
return ns_name_uncompress(ds->ansp,
(unsigned char *)ds->ansp + ds->anslen,
p, buf, (size_t)len);
#else
return dn_expand(ds->ansp,
(unsigned char *)ds->ansp + ds->anslen,
p, buf, len);
#endif
}
void
krb5int_dns_fini(struct krb5int_dns_state *ds)
{
if (ds == NULL)
return;
if (ds->ansp != NULL)
free(ds->ansp);
free(ds);
}
#if !HAVE_NS_INITPARSE
static int
initparse(struct krb5int_dns_state *ds)
{
HEADER *hdr;
unsigned char *p;
unsigned short nqueries, nanswers;
int len;
#if !HAVE_DN_SKIPNAME
char host[MAXDNAME];
#endif
if (ds->anslen < sizeof(HEADER))
return -1;
hdr = (HEADER *)ds->ansp;
p = ds->ansp;
nqueries = ntohs((unsigned short)hdr->qdcount);
nanswers = ntohs((unsigned short)hdr->ancount);
p += sizeof(HEADER);
while (nqueries--) {
#if HAVE_DN_SKIPNAME
len = dn_skipname(p, (unsigned char *)ds->ansp + ds->anslen);
#else
len = dn_expand(ds->ansp, (unsigned char *)ds->ansp + ds->anslen,
p, host, sizeof(host));
#endif
if (len < 0 || !INCR_OK(ds->ansp, ds->anslen, p, len + 4))
return -1;
p += len + 4;
}
ds->ptr = p;
ds->nanswers = nanswers;
return 0;
}
int
krb5int_dns_nextans(struct krb5int_dns_state *ds,
const unsigned char **pp, int *lenp)
{
int len;
unsigned char *p;
unsigned short ntype, nclass, rdlen;
#if !HAVE_DN_SKIPNAME
char host[MAXDNAME];
#endif
*pp = NULL;
*lenp = 0;
p = ds->ptr;
while (ds->nanswers--) {
#if HAVE_DN_SKIPNAME
len = dn_skipname(p, (unsigned char *)ds->ansp + ds->anslen);
#else
len = dn_expand(ds->ansp, (unsigned char *)ds->ansp + ds->anslen,
p, host, sizeof(host));
#endif
if (len < 0 || !INCR_OK(ds->ansp, ds->anslen, p, len))
return -1;
p += len;
SAFE_GETUINT16(ds->ansp, ds->anslen, p, 2, ntype, out);
SAFE_GETUINT16(ds->ansp, ds->anslen, p, 6, nclass, out);
SAFE_GETUINT16(ds->ansp, ds->anslen, p, 2, rdlen, out);
if (!INCR_OK(ds->ansp, ds->anslen, p, rdlen))
return -1;
if (rdlen > INT_MAX)
return -1;
if (nclass == ds->nclass && ntype == ds->ntype) {
*pp = p;
*lenp = rdlen;
ds->ptr = p + rdlen;
return 0;
}
p += rdlen;
}
return 0;
out:
return -1;
}
#endif
#endif