DNS_STATUS DnsQuery_A(const char * service, unsigned short requestType, unsigned long options, void *, DNS_RECORD * results, void *) { if (results == 0) return -1; *results = 0; struct __res_state statbuf; res_ninit(&statbuf); union { HEADER hdr; unsigned char buf[PACKETSZ]; } reply; int replyLen = res_nsearch(&statbuf, service, C_IN, requestType, (unsigned char *)&reply, sizeof(reply)); if (replyLen < 1) return -1; unsigned char * replyStart = reply.buf; unsigned char * replyEnd = reply.buf + replyLen; unsigned char * cp = reply.buf + sizeof(HEADER); // ignore questions in response uint16_t i; for (i = 0; i < ntohs(reply.hdr.qdcount); i++) { char qName[MAXDNAME]; if (!GetDN(replyStart, replyEnd, cp, qName)) return -1; cp += QFIXEDSZ; } if (!ProcessDNSRecords( replyStart, replyEnd, cp, ntohs(reply.hdr.ancount), ntohs(reply.hdr.nscount), ntohs(reply.hdr.arcount), results)) { DnsRecordListFree(*results, 0); res_nclose(&statbuf); return -1; } res_nclose(&statbuf); return 0; }
bool HHVM_FUNCTION(checkdnsrr, const String& host, const String& type /* = null_string */) { int ntype; if (!validate_dns_arguments(host, type, ntype)) { return false; } unsigned char ans[MAXPACKET]; struct __res_state *res; res = ResolverInit::s_res.get()->getResolver(); if (res == NULL) { return false; } int i = res_nsearch(res, host.data(), C_IN, ntype, ans, sizeof(ans)); res_nclose(res); php_dns_free_res(res); return (i >= 0); }
bool HHVM_FUNCTION(checkdnsrr, const String& host, const String& type /* = null_string */) { IOStatusHelper io("dns_check_record", host.data()); const char *stype; if (type.empty()) { stype = "MX"; } else { stype = type.data(); } if (host.empty()) { throw_invalid_argument("host: [empty]"); } int ntype; if (!strcasecmp("A", stype)) ntype = DNS_T_A; else if (!strcasecmp("NS", stype)) ntype = DNS_T_NS; else if (!strcasecmp("MX", stype)) ntype = DNS_T_MX; else if (!strcasecmp("PTR", stype)) ntype = DNS_T_PTR; else if (!strcasecmp("ANY", stype)) ntype = DNS_T_ANY; else if (!strcasecmp("SOA", stype)) ntype = DNS_T_SOA; else if (!strcasecmp("TXT", stype)) ntype = DNS_T_TXT; else if (!strcasecmp("CNAME", stype)) ntype = DNS_T_CNAME; else if (!strcasecmp("AAAA", stype)) ntype = DNS_T_AAAA; else if (!strcasecmp("SRV", stype)) ntype = DNS_T_SRV; else if (!strcasecmp("NAPTR", stype)) ntype = DNS_T_NAPTR; else if (!strcasecmp("A6", stype)) ntype = DNS_T_A6; else { throw_invalid_argument("type: %s", stype); return false; } unsigned char ans[MAXPACKET]; struct __res_state *res; res = ResolverInit::s_res.get()->getResolver(); if (res == NULL) { return false; } int i = res_nsearch(res, host.data(), C_IN, ntype, ans, sizeof(ans)); res_nclose(res); php_dns_free_res(res); return (i >= 0); }
bool HHVM_FUNCTION(getmxrr, const String& hostname, VRefParam mxhostsRef, VRefParam weightsRef /* = null */) { IOStatusHelper io("dns_get_mx", hostname.data()); int count, qdc; unsigned short type, weight; unsigned char ans[MAXPACKET]; char buf[MAXHOSTNAMELEN]; unsigned char *cp, *end; Array mxhosts; Array weights; SCOPE_EXIT { mxhostsRef = mxhosts; weightsRef = weights; }; /* Go! */ struct __res_state *res; res = ResolverInit::s_res.get()->getResolver(); if (res == NULL) { return false; } int i = res_nsearch(res, hostname.data(), C_IN, DNS_T_MX, (unsigned char*)&ans, sizeof(ans)); if (i < 0) { res_nclose(res); php_dns_free_res(res); return false; } if (i > (int)sizeof(ans)) { i = sizeof(ans); } HEADER *hp = (HEADER *)&ans; cp = (unsigned char *)&ans + HFIXEDSZ; end = (unsigned char *)&ans +i; for (qdc = ntohs((unsigned short)hp->qdcount); qdc--; cp += i + QFIXEDSZ) { if ((i = dn_skipname(cp, end)) < 0 ) { res_nclose(res); php_dns_free_res(res); return false; } } count = ntohs((unsigned short)hp->ancount); while (--count >= 0 && cp < end) { if ((i = dn_skipname(cp, end)) < 0 ) { res_nclose(res); php_dns_free_res(res); return false; } cp += i; GETSHORT(type, cp); cp += INT16SZ + INT32SZ; GETSHORT(i, cp); if (type != DNS_T_MX) { cp += i; continue; } GETSHORT(weight, cp); if ((i = dn_expand(ans, end, cp, buf, sizeof(buf)-1)) < 0) { res_nclose(res); php_dns_free_res(res); return false; } cp += i; mxhosts.append(String(buf, CopyString)); weights.append(weight); } res_nclose(res); php_dns_free_res(res); return true; }
Variant HHVM_FUNCTION(dns_get_record, const String& hostname, int type /*= -1*/, VRefParam authnsRef /* = null */, VRefParam addtlRef /* = null */) { IOStatusHelper io("dns_get_record", hostname.data(), type); if (type < 0) type = PHP_DNS_ALL; if (type & ~PHP_DNS_ALL && type != PHP_DNS_ANY) { raise_warning("Type '%d' not supported", type); return false; } unsigned char *cp = NULL, *end = NULL; int qd, an, ns = 0, ar = 0; querybuf answer; /* - We emulate an or'ed type mask by querying type by type. * (Steps 0 - NUMTYPES-1 ) * If additional info is wanted we check again with DNS_T_ANY * (step NUMTYPES / NUMTYPES+1 ) * store_results is used to skip storing the results retrieved in step * NUMTYPES+1 when results were already fetched. * - In case of PHP_DNS_ANY we use the directly fetch DNS_T_ANY. * (step NUMTYPES+1 ) */ Array ret; bool first_query = true; bool store_results = true; for (int t = (type == PHP_DNS_ANY ? (PHP_DNS_NUM_TYPES + 1) : 0); t < PHP_DNS_NUM_TYPES + 2 || first_query; t++) { first_query = false; int type_to_fetch; switch (t) { case 0: type_to_fetch = type & PHP_DNS_A ? DNS_T_A : 0; break; case 1: type_to_fetch = type & PHP_DNS_NS ? DNS_T_NS : 0; break; case 2: type_to_fetch = type & PHP_DNS_CNAME ? DNS_T_CNAME : 0; break; case 3: type_to_fetch = type & PHP_DNS_SOA ? DNS_T_SOA : 0; break; case 4: type_to_fetch = type & PHP_DNS_PTR ? DNS_T_PTR : 0; break; case 5: type_to_fetch = type & PHP_DNS_HINFO ? DNS_T_HINFO : 0; break; case 6: type_to_fetch = type & PHP_DNS_MX ? DNS_T_MX : 0; break; case 7: type_to_fetch = type & PHP_DNS_TXT ? DNS_T_TXT : 0; break; case 8: type_to_fetch = type & PHP_DNS_AAAA ? DNS_T_AAAA : 0; break; case 9: type_to_fetch = type & PHP_DNS_SRV ? DNS_T_SRV : 0; break; case 10: type_to_fetch = type & PHP_DNS_NAPTR ? DNS_T_NAPTR : 0; break; case 11: type_to_fetch = type & PHP_DNS_A6 ? DNS_T_A6 : 0; break; case PHP_DNS_NUM_TYPES: store_results = false; continue; default: case (PHP_DNS_NUM_TYPES + 1): type_to_fetch = DNS_T_ANY; break; } if (!type_to_fetch) continue; struct __res_state *res; res = ResolverInit::s_res.get()->getResolver(); if (res == NULL) { return false; } int n = res_nsearch(res, hostname.data(), C_IN, type_to_fetch, answer.qb2, sizeof answer); if (n < 0) { res_nclose(res); php_dns_free_res(res); continue; } HEADER *hp; cp = answer.qb2 + HFIXEDSZ; end = answer.qb2 + n; hp = (HEADER *)&answer; qd = ntohs(hp->qdcount); an = ntohs(hp->ancount); ns = ntohs(hp->nscount); ar = ntohs(hp->arcount); /* Skip QD entries, they're only used by dn_expand later on */ while (qd-- > 0) { n = dn_skipname(cp, end); if (n < 0) { raise_warning("Unable to parse DNS data received"); res_nclose(res); php_dns_free_res(res); return false; } cp += n + QFIXEDSZ; } /* YAY! Our real answers! */ while (an-- && cp && cp < end) { Array retval; cp = php_parserr(cp, end, &answer, type_to_fetch, store_results, retval); if (!retval.empty() && store_results) { ret.append(retval); } } res_nclose(res); php_dns_free_res(res); } Array authns; Array addtl; /* List of Authoritative Name Servers */ while (ns-- > 0 && cp && cp < end) { Array retval; cp = php_parserr(cp, end, &answer, DNS_T_ANY, true, retval); if (!retval.empty()) { authns.append(retval); } } /* Additional records associated with authoritative name servers */ while (ar-- > 0 && cp && cp < end) { Array retval; cp = php_parserr(cp, end, &answer, DNS_T_ANY, true, retval); if (!retval.empty()) { addtl.append(retval); } } authnsRef = authns; addtlRef = addtl; return ret; }
/* * Simplified version of srv_query() for domain auto-discovery. */ int srv_getdom(res_state state, const char *svc_name, char **rrname) { union { HEADER hdr; uchar_t buf[NS_MAXMSG]; } msg; int len, qdcount, ancount; uchar_t *ptr, *eom; char namebuf[NS_MAXDNAME]; /* query necessary resource records */ *rrname = NULL; if (DBG(DNS, 1)) { logger(LOG_DEBUG, "Looking for SRV RRs '%s.*'", svc_name); } len = res_nsearch(state, svc_name, C_IN, T_SRV, msg.buf, sizeof (msg.buf)); if (len < 0) { if (DBG(DNS, 0)) { logger(LOG_DEBUG, "DNS search for '%s' failed (%s)", svc_name, hstrerror(state->res_h_errno)); } return (-1); } if (len > sizeof (msg.buf)) { logger(LOG_WARNING, "DNS query %ib message doesn't fit into %ib buffer", len, sizeof (msg.buf)); len = sizeof (msg.buf); } /* parse the reply header */ ptr = msg.buf + sizeof (msg.hdr); eom = msg.buf + len; qdcount = ntohs(msg.hdr.qdcount); ancount = ntohs(msg.hdr.ancount); /* skip the question section */ len = ns_skiprr(ptr, eom, ns_s_qd, qdcount); if (len < 0) { logger(LOG_ERR, "DNS query invalid message format"); return (-1); } ptr += len; /* parse the answer section */ if (ancount < 1) { logger(LOG_ERR, "DNS query - no answers"); return (-1); } len = dn_expand(msg.buf, eom, ptr, namebuf, sizeof (namebuf)); if (len < 0) { logger(LOG_ERR, "DNS query invalid message format"); return (-1); } *rrname = strdup(namebuf); if (*rrname == NULL) { logger(LOG_ERR, "Out of memory"); return (-1); } return (0); }
/* * Query or search the SRV RRs for a given name. * * If dname == NULL then search (as in res_nsearch(3RESOLV), honoring any * search list/option), else query (as in res_nquery(3RESOLV)). * * The output TTL will be the one of the SRV RR with the lowest TTL. */ ad_disc_cds_t * srv_query(res_state state, const char *svc_name, const char *dname, ad_disc_ds_t *prefer) { ad_disc_cds_t *cds_res = NULL; uchar_t *msg = NULL; int len, scnt, maxcnt; msg = malloc(NS_MAXMSG); if (msg == NULL) { logger(LOG_ERR, "Out of memory"); return (NULL); } /* query necessary resource records */ /* Search, querydomain or query */ if (dname == NULL) { dname = "*"; if (DBG(DNS, 1)) { logger(LOG_DEBUG, "Looking for SRV RRs '%s.*'", svc_name); } len = res_nsearch(state, svc_name, C_IN, T_SRV, msg, NS_MAXMSG); if (len < 0) { if (DBG(DNS, 0)) { logger(LOG_DEBUG, "DNS search for '%s' failed (%s)", svc_name, hstrerror(state->res_h_errno)); } goto errout; } } else { /* dname != NULL */ if (DBG(DNS, 1)) { logger(LOG_DEBUG, "Looking for SRV RRs '%s.%s' ", svc_name, dname); } len = res_nquerydomain(state, svc_name, dname, C_IN, T_SRV, msg, NS_MAXMSG); if (len < 0) { if (DBG(DNS, 0)) { logger(LOG_DEBUG, "DNS: %s.%s: %s", svc_name, dname, hstrerror(state->res_h_errno)); } goto errout; } } if (len > NS_MAXMSG) { logger(LOG_WARNING, "DNS query %ib message doesn't fit into %ib buffer", len, NS_MAXMSG); len = NS_MAXMSG; } /* parse the reply header */ cds_res = srv_parse(msg, len, &scnt, &maxcnt); if (cds_res == NULL) goto errout; if (prefer != NULL) add_preferred(cds_res, prefer, &scnt, maxcnt); get_addresses(cds_res, scnt); /* sort list of candidates */ if (scnt > 1) qsort(cds_res, scnt, sizeof (*cds_res), (int (*)(const void *, const void *))srvcmp); free(msg); return (cds_res); errout: free(msg); return (NULL); }
/* * krb5int_dns_init() * * Initialize an opaque handle. Do name lookup and initial parsing of * reply, skipping question section. Prepare to iterate over answer * section. Returns -1 on error, 0 on success. */ int krb5int_dns_init(struct krb5int_dns_state **dsp, char *host, int nclass, int ntype) { #if USE_RES_NINIT 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 USE_RES_NINIT memset(&statbuf, 0, sizeof(statbuf)); ret = res_ninit(&statbuf); #else ret = res_init(); #endif if (ret < 0) return -1; do { p = (ds->ansp == NULL) ? malloc(nextincr) : realloc(ds->ansp, nextincr); if (p == NULL) { ret = -1; goto errout; } ds->ansp = p; ds->ansmax = nextincr; #if USE_RES_NINIT 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 ((size_t) len > maxincr) { ret = -1; goto errout; } while (nextincr < (size_t) 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 USE_RES_NINIT res_ndestroy(&statbuf); #endif if (ret < 0) { if (ds->ansp != NULL) { free(ds->ansp); ds->ansp = NULL; } } return ret; }