コード例 #1
0
ファイル: DNS.cpp プロジェクト: joegen/oss_core
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;
}
コード例 #2
0
static void test_res_fake_a_query_case_insensitive(void **state)
{
    int rv;
    struct __res_state dnsstate;
    unsigned char answer[ANSIZE];
    char addr[INET_ADDRSTRLEN];
    ns_msg handle;
    ns_rr rr;   /* expanded resource record */

    (void) state; /* unused */

    memset(&dnsstate, 0, sizeof(struct __res_state));
    rv = res_ninit(&dnsstate);
    assert_int_equal(rv, 0);

    rv = res_nquery(&dnsstate, "CWRAP.ORG", ns_c_in, ns_t_a,
                    answer, sizeof(answer));
    assert_in_range(rv, 1, 100);

    ns_initparse(answer, sizeof(answer), &handle);
    /* The query must finish w/o an error, have one answer and the answer
     * must be a parseable RR of type A and have the address that our
     * fake hosts file contains. Case does not matter.
     */
    assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
    assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
    assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
    assert_int_equal(ns_rr_type(rr), ns_t_a);
    assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr),
                              addr, sizeof(addr)));
    assert_string_equal(addr, "127.0.0.21");

    res_nclose(&dnsstate);
}
コード例 #3
0
ファイル: qhostinfo_unix.cpp プロジェクト: fluxer/katie
QString QHostInfo::localDomainName()
{
#if !defined(QT_NO_RESOLV) && defined(res_ninit)
    // using thread-safe version
    res_state state = static_cast<res_state>(malloc(sizeof(res_state)));
    Q_CHECK_PTR(state);
    memset(state, 0, sizeof(res_state));
    res_ninit(state);
    QString domainName = QUrl::fromAce(state->defdname);
    if (domainName.isEmpty())
        domainName = QUrl::fromAce(state->dnsrch[0]);
    res_nclose(state);
    free(state);

    return domainName;
#elif !defined(QT_NO_RESOLV)
    // using thread-unsafe version

#if defined(QT_NO_GETADDRINFO)
    // We have to call res_init to be sure that _res was initialized
    // So, for systems without getaddrinfo (which is thread-safe), we lock the mutex too
    QMutexLocker locker(::getHostByNameMutex());
#endif
    res_init();
    QString domainName = QUrl::fromAce(local_res->defdname);
    if (domainName.isEmpty())
        domainName = QUrl::fromAce(local_res->dnsrch[0]);
    return domainName;
#else

    // nothing worked, try doing it by ourselves:
    QFile resolvconf;
#if defined(_PATH_RESCONF)
    resolvconf.setFileName(QFile::decodeName(_PATH_RESCONF));
#else
    resolvconf.setFileName(QLatin1String("/etc/resolv.conf"));
#endif
    if (!resolvconf.open(QIODevice::ReadOnly))
        return QString();       // failure

    QString domainName;
    while (!resolvconf.atEnd()) {
        QByteArray line = resolvconf.readLine().trimmed();
        if (line.startsWith("domain "))
            return QUrl::fromAce(line.mid(sizeof "domain " - 1).trimmed());

        // in case there's no "domain" line, fall back to the first "search" entry
        if (domainName.isEmpty() && line.startsWith("search ")) {
            QByteArray searchDomain = line.mid(sizeof "search " - 1).trimmed();
            int pos = searchDomain.indexOf(' ');
            if (pos != -1)
                searchDomain.truncate(pos);
            domainName = QUrl::fromAce(searchDomain);
        }
    }

    // return the fallen-back-to searched domain
    return domainName;
#endif // QT_NO_RESOLV
}
コード例 #4
0
ファイル: res_init.c プロジェクト: alexandermerritt/dragonfly
void
res_ndestroy(res_state statp) {
	res_nclose(statp);
	if (statp->_u._ext.ext != NULL)
		free(statp->_u._ext.ext);
	statp->options &= ~RES_INIT;
	statp->_u._ext.ext = NULL;
}
コード例 #5
0
ファイル: res_init.c プロジェクト: 10114395/android-5.0.0_r5
void
res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt)
{
	int i, nserv;
	size_t size;

	/* close open servers */
	res_nclose(statp);

	/* cause rtt times to be forgotten */
	statp->_u._ext.nscount = 0;

	nserv = 0;
	for (i = 0; i < cnt && nserv < MAXNS; i++) {
		switch (set->sin.sin_family) {
		case AF_INET:
			size = sizeof(set->sin);
			if (statp->_u._ext.ext)
				memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
					&set->sin, size);
			if (size <= sizeof(statp->nsaddr_list[nserv]))
				memcpy(&statp->nsaddr_list[nserv],
					&set->sin, size);
			else
				statp->nsaddr_list[nserv].sin_family = 0;
			nserv++;
			break;

#ifdef HAS_INET6_STRUCTS
		case AF_INET6:
			size = sizeof(set->sin6);
			if (statp->_u._ext.ext)
				memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
					&set->sin6, size);
			if (size <= sizeof(statp->nsaddr_list[nserv]))
				memcpy(&statp->nsaddr_list[nserv],
					&set->sin6, size);
			else
				statp->nsaddr_list[nserv].sin_family = 0;
			nserv++;
			break;
#endif

		default:
			break;
		}
		set++;
	}
	statp->nscount = nserv;

}
コード例 #6
0
ファイル: dnsresolv.c プロジェクト: mrmt/enma
void
DnsResolver_free(DnsResolver *self)
{
    assert(NULL != self);
    res_nclose(&self->resolver);
    /*
     * glibc-2.4.0 以降ならば
     * res_nclose(&self->resolver);
     * とすることで libresolv でも対応可能.
     * glibc-2.3.x にも res_nclose() は存在するが,
     * マルチスレッド環境下ではメモリリークを引き起こす.
     */
    free(self);
}   // end function : DnsResolver_free
コード例 #7
0
ファイル: hesiod.c プロジェクト: andreiw/polaris
/*
 * This function deallocates the hesiod_p
 */
void
hesiod_end(void *context) {
	struct hesiod_p *ctx = (struct hesiod_p *) context;
	int save_errno = errno;

	if (ctx->res)
		res_nclose(ctx->res);
	if (ctx->RHS)
		free(ctx->RHS);
	if (ctx->LHS)
		free(ctx->LHS);
	if (ctx->res && ctx->free_res)
		(*ctx->free_res)(ctx->res);
	free(ctx);
	errno = save_errno;
}
コード例 #8
0
ファイル: ext_std_network-posix.cpp プロジェクト: ezoic/hhvm
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);
}
コード例 #9
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);
}
コード例 #10
0
void
net_data_minimize(struct net_data *net_data) {
	res_nclose(net_data->res);
}
コード例 #11
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;
}
コード例 #12
0
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;
}
コード例 #13
0
ファイル: SipSrvLookup.cpp プロジェクト: LordGaav/sipxecs
// Perform a DNS query and parse the results.  Follows CNAME records.
void SipSrvLookup::res_query_and_parse(const char* in_name,
                                       int type,
                                       res_response* in_response,
                                       const char*& out_name,
                                       res_response*& out_response
   )
{
   OsSysLog::add(FAC_SIP, PRI_DEBUG,
                 "SipSrvLookup::res_query_and_parse in_name = '%s', "
                 "type = %d (%s)",
                 in_name,type,
                 type == T_CNAME ? "CNAME" :
                 type == T_SRV ? "SRV" :
                 type == T_A ? "A" :
                 type == T_NAPTR ? "NAPTR" :
                 "unknown");

   // The number of CNAMEs we have followed.
   int cname_count = 0;
   // The response currently being examined.
   res_response* response = in_response;
   // The name currently being examined.
   const char* name = in_name;
   // TRUE if 'response' was a lookup for 'name' and 'type'.
   UtlBoolean response_for_this_name = FALSE;
   // Buffer into which to read DNS replies.
   char answer[DNS_RESPONSE_SIZE];
   union u_rdata* p;

   // Loop until we find a reason to exit.  Each turn around the loop does
   // another DNS lookup.
   while (1)
   {
      // While response != NULL and there is a CNAME record for name
      // in response.
      while (response != NULL &&
             (p = look_for(response, name, T_CNAME)) != NULL)
      {
         cname_count++;
         if (cname_count > SipSrvLookup::getOption(SipSrvLookup::OptionCodeCNAMELimit))
         {
            break;
         }
         // If necessary, free the current 'name'.
         if (name != in_name)
         {
            free((void*) name);
         }
         // Copy the canonical name from the CNAME record into 'name', so
         // we can still use it after freeing 'response'.
         name = strdup(p->string);
         // Remember that we are now looking for a name that was not the one
         // that we searched for to produce this response.  Hence, if we don't
         // find any RRs for it, that is not authoritative and we have to do
         // another DNS query.
         response_for_this_name = FALSE;
         // Go back and check whether the result name of the CNAME is listed
         // in this response.
      }
      // This response does not contain a CNAME for 'name'.  So it is either
      // a final response that gives us the RRs we are looking for, or
      // we need to do a lookup on 'name'.

      // Check whether the response was for this name, or contains records
      // of the type we are looking for.  If either, then any records we
      // are looking for are in this response, so we can return.
      if (response_for_this_name ||
          (response != NULL && look_for(response, name, type) != NULL))
      {
         break;
      }

      // We must do another lookup.
      // Start by freeing 'response' if we need to.
      if (response != in_response)
      {
         res_free(response);
      }
      response = NULL;
      // Now, 'response' will be from a query for 'name'.
      response_for_this_name = TRUE;
      // Debugging print.
      if (SipSrvLookup::getOption(SipSrvLookup::OptionCodePrintAnswers))
      {
         printf("res_nquery(\"%s\", class = %d, type = %d)\n",
                name, C_IN, type);
      }

      // Initialize the res state struct and set the timeout to
      // 3 secs and retries to 2
      struct __res_state res;
      res_ninit(&res);
      res.retrans = mTimeout;
      res.retry = mRetries;

      if (!mNameserverIP.isNull())
      {
          res.nscount = 1;
          inet_aton(mNameserverIP.data(), &res.nsaddr_list[0].sin_addr);

          if (mNameserverPort > 1)
          {
             res.nsaddr_list[0].sin_port = htons(mNameserverPort);
          }
      }

      // Use res_nquery, not res_search or res_query, so defaulting rules are not
      // applied to the domain, and so that the query is thread-safe.
      int r = res_nquery(&res, name, C_IN, type,
                         (unsigned char*) answer, sizeof (answer));
      // Done with res state struct, so cleanup.
      // Must close once and only once per res_ninit, after res_nquery.
      res_nclose(&res);

      if (r == -1)
      {
         // res_query failed, return.
         OsSysLog::add(FAC_SIP, PRI_WARNING,
                       "DNS query for name '%s', "
                       "type = %d (%s): returned error",
                       name, type,
                       type == T_CNAME ? "CNAME" :
                       type == T_SRV ? "SRV" :
                       type == T_A ? "A" :
                       type == T_NAPTR ? "NAPTR" :
                       "unknown");
         break;
      }

      response = res_parse((char*) &answer);
      if (response == NULL)
      {
         // res_parse failed, return.
         OsSysLog::add(FAC_SIP, PRI_WARNING,
                       "DNS query for name '%s', "
                       "type = %d (%s): response could not be parsed",
                       name, type,
                       type == T_CNAME ? "CNAME" :
                       type == T_SRV ? "SRV" :
                       type == T_A ? "A" :
                       type == T_NAPTR ? "NAPTR" :
                       "unknown");
         break;
      }
      // If requested for testing purposes, sort the query and print it.
      // Sort first, so we see how sorting came out.
      if (SipSrvLookup::getOption(SipSrvLookup::OptionCodeSortAnswers))
      {
         sort_answers(response);
      }
      if (SipSrvLookup::getOption(SipSrvLookup::OptionCodePrintAnswers))
      {
         res_print(response);
      }
      // Now that we have a fresh DNS query to analyze, go back and check it
      // for a CNAME for 'name' and then for records of the requested type.
   }

   // Final processing:  Copy the working name and response to the output
   // variables.
   out_name = name;
   out_response = response;
   OsSysLog::add(FAC_SIP, PRI_DEBUG,
                 "SipSrvLookup::res_query_and_parse out_name = '%s', out_response = %p",
                 out_name, out_response);

}
コード例 #14
0
ファイル: net.c プロジェクト: zabbix/zabbix
static int	dns_query(AGENT_REQUEST *request, AGENT_RESULT *result, int short_answer)
{
#if defined(HAVE_RES_QUERY) || defined(_WINDOWS)

	size_t			offset = 0;
	int			res, type, retrans, retry, use_tcp, i, ret = SYSINFO_RET_FAIL, ip_type = AF_INET;
	char			*ip, zone[MAX_STRING_LEN], buffer[MAX_STRING_LEN], *zone_str, *param,
				tmp[MAX_STRING_LEN];
	struct in_addr		inaddr;
	struct in6_addr		in6addr;
#ifndef _WINDOWS
#if defined(HAVE_RES_NINIT) && !defined(_AIX)
	/* It seems that on some AIX systems with no updates installed res_ninit() can */
	/* corrupt stack (see ZBX-14559). Use res_init() on AIX. */
	struct __res_state	res_state_local;
#else	/* thread-unsafe resolver API */
	int			saved_retrans, saved_retry, saved_nscount = 0;
	unsigned long		saved_options;
	struct sockaddr_in	saved_ns;
#	if defined(HAVE_RES_U_EXT)		/* thread-unsafe resolver API /Linux/ */
	int			save_nssocks, saved_nscount6;
#	endif
#endif

#if defined(HAVE_RES_EXT_EXT)		/* AIX */
	union res_sockaddr_union	saved_ns6;
#elif defined(HAVE_RES_U_EXT_EXT)	/* BSD */
	struct sockaddr_in6		saved_ns6;
#else
	struct sockaddr_in6		*saved_ns6;
#endif
	struct sockaddr_in6	sockaddrin6;
	struct addrinfo		hint, *hres = NULL;
#endif
	typedef struct
	{
		const char	*name;
		int		type;
	}
	resolv_querytype_t;

	static const resolv_querytype_t	qt[] =
	{
		{"ANY",		T_ANY},
		{"A",		T_A},
		{"AAAA",	T_AAAA},
		{"NS",		T_NS},
		{"MD",		T_MD},
		{"MF",		T_MF},
		{"CNAME",	T_CNAME},
		{"SOA",		T_SOA},
		{"MB",		T_MB},
		{"MG",		T_MG},
		{"MR",		T_MR},
		{"NULL",	T_NULL},
#ifndef _WINDOWS
		{"WKS",		T_WKS},
#endif
		{"PTR",		T_PTR},
		{"HINFO",	T_HINFO},
		{"MINFO",	T_MINFO},
		{"MX",		T_MX},
		{"TXT",		T_TXT},
		{"SRV",		T_SRV},
		{NULL}
	};

#ifdef _WINDOWS
	PDNS_RECORD	pQueryResults, pDnsRecord;
	wchar_t		*wzone;
	char		tmp2[MAX_STRING_LEN];
	DWORD		options;
#else
	char		*name;
	unsigned char	*msg_end, *msg_ptr, *p;
	int		num_answers, num_query, q_type, q_class, q_len, value, c, n;
	struct servent	*s;
	HEADER		*hp;
	struct protoent	*pr;
#if PACKETSZ > 1024
	unsigned char	buf[PACKETSZ];
#else
	unsigned char	buf[1024];
#endif

	typedef union
	{
		HEADER		h;
#if defined(NS_PACKETSZ)
		unsigned char	buffer[NS_PACKETSZ];
#elif defined(PACKETSZ)
		unsigned char	buffer[PACKETSZ];
#else
		unsigned char	buffer[512];
#endif
	}
	answer_t;

	answer_t	answer;
#endif	/* _WINDOWS */
	zbx_vector_str_t	answers;

	*buffer = '\0';

	if (6 < request->nparam)
	{
		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
		return SYSINFO_RET_FAIL;
	}

	ip = get_rparam(request, 0);
	zone_str = get_rparam(request, 1);

#ifndef _WINDOWS
	memset(&hint, '\0', sizeof(hint));
	hint.ai_family = PF_UNSPEC;
	hint.ai_flags = AI_NUMERICHOST;

	if (NULL != ip && '\0' != *ip && 0 == getaddrinfo(ip, NULL, &hint, &hres) && AF_INET6 == hres->ai_family)
		ip_type = hres->ai_family;

	if (NULL != hres)
		freeaddrinfo(hres);
#endif
	if (NULL == zone_str || '\0' == *zone_str)
		strscpy(zone, "zabbix.com");
	else
		strscpy(zone, zone_str);

	param = get_rparam(request, 2);

	if (NULL == param || '\0' == *param)
		type = T_SOA;
	else
	{
		for (i = 0; NULL != qt[i].name; i++)
		{
			if (0 == strcasecmp(qt[i].name, param))
			{
				type = qt[i].type;
				break;
			}
		}

		if (NULL == qt[i].name)
		{
			SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
			return SYSINFO_RET_FAIL;
		}
	}

	param = get_rparam(request, 3);

	if (NULL == param || '\0' == *param)
		retrans = 1;
	else if (SUCCEED != is_uint31(param, &retrans) || 0 == retrans)
	{
		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid fourth parameter."));
		return SYSINFO_RET_FAIL;
	}

	param = get_rparam(request, 4);

	if (NULL == param || '\0' == *param)
		retry = 2;
	else if (SUCCEED != is_uint31(param, &retry) || 0 == retry)
	{
		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid fifth parameter."));
		return SYSINFO_RET_FAIL;
	}

	param = get_rparam(request, 5);

	if (NULL == param || '\0' == *param || 0 == strcmp(param, "udp"))
		use_tcp = 0;
	else if (0 == strcmp(param, "tcp"))
		use_tcp = 1;
	else
	{
		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid sixth parameter."));
		return SYSINFO_RET_FAIL;
	}

#ifdef _WINDOWS
	options = DNS_QUERY_STANDARD | DNS_QUERY_BYPASS_CACHE;
	if (0 != use_tcp)
		options |= DNS_QUERY_USE_TCP_ONLY;

	wzone = zbx_utf8_to_unicode(zone);
	res = DnsQuery(wzone, type, options, NULL, &pQueryResults, NULL);
	zbx_free(wzone);

	if (1 == short_answer)
	{
		SET_UI64_RESULT(result, DNS_RCODE_NOERROR != res ? 0 : 1);
		ret = SYSINFO_RET_OK;
		goto clean_dns;
	}

	if (DNS_RCODE_NOERROR != res)
	{
		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot perform DNS query: [%d]", res));
		return SYSINFO_RET_FAIL;
	}

	pDnsRecord = pQueryResults;
	zbx_vector_str_create(&answers);

	while (NULL != pDnsRecord)
	{
		if (DnsSectionAnswer != pDnsRecord->Flags.S.Section)
		{
			pDnsRecord = pDnsRecord->pNext;
			continue;
		}

		if (NULL == pDnsRecord->pName)
			goto clean;

		offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%-20s",
				zbx_unicode_to_utf8_static(pDnsRecord->pName, tmp, sizeof(tmp)));
		offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %-8s",
				decode_type(pDnsRecord->wType));

		switch (pDnsRecord->wType)
		{
			case T_A:
				inaddr.s_addr = pDnsRecord->Data.A.IpAddress;
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
						inet_ntoa(inaddr));
				break;
			case T_AAAA:
				memcpy(&in6addr.s6_addr, &(pDnsRecord->Data.AAAA.Ip6Address), sizeof(in6addr.s6_addr));
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
						zbx_inet_ntop(AF_INET6, &in6addr, tmp, sizeof(tmp)));
				break;
			case T_NS:
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
						zbx_unicode_to_utf8_static(pDnsRecord->Data.NS.pNameHost, tmp, sizeof(tmp)));
				break;
			case T_MD:
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
						zbx_unicode_to_utf8_static(pDnsRecord->Data.MD.pNameHost, tmp, sizeof(tmp)));
				break;
			case T_MF:
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
						zbx_unicode_to_utf8_static(pDnsRecord->Data.MF.pNameHost, tmp, sizeof(tmp)));
				break;
			case T_CNAME:
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
						zbx_unicode_to_utf8_static(pDnsRecord->Data.CNAME.pNameHost, tmp, sizeof(tmp)));
				break;
			case T_SOA:
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s %s %lu %lu %lu %lu %lu",
						zbx_unicode_to_utf8_static(pDnsRecord->Data.SOA.pNamePrimaryServer, tmp, sizeof(tmp)),
						zbx_unicode_to_utf8_static(pDnsRecord->Data.SOA.pNameAdministrator, tmp2, sizeof(tmp2)),
						pDnsRecord->Data.SOA.dwSerialNo,
						pDnsRecord->Data.SOA.dwRefresh,
						pDnsRecord->Data.SOA.dwRetry,
						pDnsRecord->Data.SOA.dwExpire,
						pDnsRecord->Data.SOA.dwDefaultTtl);
				break;
			case T_MB:
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
						zbx_unicode_to_utf8_static(pDnsRecord->Data.MB.pNameHost, tmp, sizeof(tmp)));
				break;
			case T_MG:
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
						zbx_unicode_to_utf8_static(pDnsRecord->Data.MG.pNameHost, tmp, sizeof(tmp)));
				break;
			case T_MR:
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
						zbx_unicode_to_utf8_static(pDnsRecord->Data.MR.pNameHost, tmp, sizeof(tmp)));
				break;
			case T_NULL:
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " len:%lu",
						pDnsRecord->Data.Null.dwByteCount);
				break;
			case T_PTR:
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
						zbx_unicode_to_utf8_static(pDnsRecord->Data.PTR.pNameHost, tmp, sizeof(tmp)));
				break;
			case T_HINFO:
				for (i = 0; i < (int)(pDnsRecord->Data.HINFO.dwStringCount); i++)
					offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " \"%s\"",
							zbx_unicode_to_utf8_static(pDnsRecord->Data.HINFO.pStringArray[i], tmp, sizeof(tmp)));
				break;
			case T_MINFO:
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s %s",
						zbx_unicode_to_utf8_static(pDnsRecord->Data.MINFO.pNameMailbox, tmp, sizeof(tmp)),
						zbx_unicode_to_utf8_static(pDnsRecord->Data.MINFO.pNameErrorsMailbox, tmp2, sizeof(tmp2)));
				break;
			case T_MX:
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %hu %s",
						pDnsRecord->Data.MX.wPreference,
						zbx_unicode_to_utf8_static(pDnsRecord->Data.MX.pNameExchange, tmp, sizeof(tmp)));
				break;
			case T_TXT:
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " \"");

				for (i = 0; i < (int)(pDnsRecord->Data.TXT.dwStringCount); i++)
					offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%s ",
							zbx_unicode_to_utf8_static(pDnsRecord->Data.TXT.pStringArray[i], tmp, sizeof(tmp)));

				if (0 < i)
					offset -= 1;	/* remove the trailing space */

				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "\"");

				break;
			case T_SRV:
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %hu %hu %hu %s",
						pDnsRecord->Data.SRV.wPriority,
						pDnsRecord->Data.SRV.wWeight,
						pDnsRecord->Data.SRV.wPort,
						zbx_unicode_to_utf8_static(pDnsRecord->Data.SRV.pNameTarget, tmp, sizeof(tmp)));
				break;
			default:
				break;
		}

		zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "\n");

		pDnsRecord = pDnsRecord->pNext;
		zbx_vector_str_append(&answers, zbx_strdup(NULL, buffer));
		offset = 0;
		*buffer = '\0';
	}
#else	/* not _WINDOWS */
#if defined(HAVE_RES_NINIT) && !defined(_AIX)
	memset(&res_state_local, 0, sizeof(res_state_local));
	if (-1 == res_ninit(&res_state_local))	/* initialize always, settings might have changed */
#else
	if (-1 == res_init())	/* initialize always, settings might have changed */
#endif
	{
		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot initialize DNS subsystem: %s", zbx_strerror(errno)));
		return SYSINFO_RET_FAIL;
	}

#if defined(HAVE_RES_NINIT) && !defined(_AIX)
	if (-1 == (res = res_nmkquery(&res_state_local, QUERY, zone, C_IN, type, NULL, 0, NULL, buf, sizeof(buf))))
#else
	if (-1 == (res = res_mkquery(QUERY, zone, C_IN, type, NULL, 0, NULL, buf, sizeof(buf))))
#endif
	{
		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot create DNS query: %s", zbx_strerror(errno)));
		return SYSINFO_RET_FAIL;
	}

	if (NULL != ip && '\0' != *ip && AF_INET == ip_type)
	{
		if (0 == inet_aton(ip, &inaddr))
		{
			SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid IP address."));
			return SYSINFO_RET_FAIL;
		}

#if defined(HAVE_RES_NINIT) && !defined(_AIX)
		res_state_local.nsaddr_list[0].sin_addr = inaddr;
		res_state_local.nsaddr_list[0].sin_family = AF_INET;
		res_state_local.nsaddr_list[0].sin_port = htons(ZBX_DEFAULT_DNS_PORT);
		res_state_local.nscount = 1;
#else	/* thread-unsafe resolver API */
		memcpy(&saved_ns, &(_res.nsaddr_list[0]), sizeof(struct sockaddr_in));
		saved_nscount = _res.nscount;

		_res.nsaddr_list[0].sin_addr = inaddr;
		_res.nsaddr_list[0].sin_family = AF_INET;
		_res.nsaddr_list[0].sin_port = htons(ZBX_DEFAULT_DNS_PORT);
		_res.nscount = 1;
#endif
	}
	else if (NULL != ip && '\0' != *ip && AF_INET6 == ip_type)
	{
		if (0 == inet_pton(ip_type, ip, &in6addr))
		{
			SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid IPv6 address."));
			return SYSINFO_RET_FAIL;
		}

		memset(&sockaddrin6, '\0', sizeof(sockaddrin6));
#if defined(HAVE_RES_SIN6_LEN)
		sockaddrin6.sin6_len = sizeof(sockaddrin6);
#endif
		sockaddrin6.sin6_family = AF_INET6;
		sockaddrin6.sin6_addr = in6addr;
		sockaddrin6.sin6_port = htons(ZBX_DEFAULT_DNS_PORT);
#if defined(HAVE_RES_NINIT) && !defined(_AIX) && (defined(HAVE_RES_U_EXT) || defined(HAVE_RES_U_EXT_EXT))
		memset(&res_state_local.nsaddr_list[0], '\0', sizeof(res_state_local.nsaddr_list[0]));
#		ifdef HAVE_RES_U_EXT			/* Linux */
		saved_ns6 = res_state_local._u._ext.nsaddrs[0];
		res_state_local._u._ext.nsaddrs[0] = &sockaddrin6;
		res_state_local._u._ext.nssocks[0] = -1;
		res_state_local._u._ext.nscount6 = 1;	/* CentOS */
#		elif HAVE_RES_U_EXT_EXT			/* BSD */
		if (NULL != res_state_local._u._ext.ext)
			memcpy(res_state_local._u._ext.ext, &sockaddrin6, sizeof(sockaddrin6));

		res_state_local.nsaddr_list[0].sin_port = htons(ZBX_DEFAULT_DNS_PORT);
#		endif
		res_state_local.nscount = 1;
#else
		memcpy(&saved_ns, &(_res.nsaddr_list[0]), sizeof(struct sockaddr_in));
		saved_nscount = _res.nscount;
#		if defined(HAVE_RES_U_EXT) || defined(HAVE_RES_U_EXT_EXT) || defined(HAVE_RES_EXT_EXT)
		memset(&_res.nsaddr_list[0], '\0', sizeof(_res.nsaddr_list[0]));
		_res.nscount = 1;
#		endif
#		if defined(HAVE_RES_U_EXT)		/* thread-unsafe resolver API /Linux/ */
		saved_nscount6 = _res._u._ext.nscount6;
		saved_ns6 = _res._u._ext.nsaddrs[0];
		save_nssocks = _res._u._ext.nssocks[0];
		_res._u._ext.nsaddrs[0] = &sockaddrin6;
		_res._u._ext.nssocks[0] = -1;
		_res._u._ext.nscount6 = 1;
#		elif defined(HAVE_RES_U_EXT_EXT)	/* thread-unsafe resolver API /BSD/ */
		memcpy(&saved_ns6, _res._u._ext.ext, sizeof(saved_ns6));
		_res.nsaddr_list[0].sin_port = htons(ZBX_DEFAULT_DNS_PORT);

		if (NULL != _res._u._ext.ext)
			memcpy(_res._u._ext.ext, &sockaddrin6, sizeof(sockaddrin6));
#		elif defined(HAVE_RES_EXT_EXT)		/* thread-unsafe resolver API /AIX/ */
		memcpy(&saved_ns6, &(_res._ext.ext.nsaddrs[0]), sizeof(saved_ns6));
		memcpy(&_res._ext.ext.nsaddrs[0], &sockaddrin6, sizeof(sockaddrin6));
#		endif /* #if defined(HAVE_RES_U_EXT) */
#endif /* #if defined(HAVE_RES_NINIT) && !defined(_AIX) && (defined(HAVE_RES_U_EXT) || defined(HAVE_RES_U_EXT_EXT)) */
	}

#if defined(HAVE_RES_NINIT) && !defined(_AIX) && (defined(HAVE_RES_U_EXT) || defined(HAVE_RES_U_EXT_EXT))
	if (0 != use_tcp)
		res_state_local.options |= RES_USEVC;

	res_state_local.retrans = retrans;
	res_state_local.retry = retry;

	res = res_nsend(&res_state_local, buf, res, answer.buffer, sizeof(answer.buffer));

#	ifdef HAVE_RES_U_EXT	/* Linux */
	if (NULL != ip && '\0' != *ip && AF_INET6 == ip_type)
		res_state_local._u._ext.nsaddrs[0] = saved_ns6;
#	endif
#	ifdef HAVE_RES_NDESTROY
	res_ndestroy(&res_state_local);
#	else
	res_nclose(&res_state_local);
#	endif
#else	/* thread-unsafe resolver API */
	saved_options = _res.options;
	saved_retrans = _res.retrans;
	saved_retry = _res.retry;

	if (0 != use_tcp)
		_res.options |= RES_USEVC;

	_res.retrans = retrans;
	_res.retry = retry;

	res = res_send(buf, res, answer.buffer, sizeof(answer.buffer));

	_res.options = saved_options;
	_res.retrans = saved_retrans;
	_res.retry = saved_retry;

	if (NULL != ip && '\0' != *ip)
	{
		if (AF_INET6 == ip_type)
		{
#			if defined(HAVE_RES_U_EXT)		/* Linux */
			_res._u._ext.nsaddrs[0] = saved_ns6;
			_res._u._ext.nssocks[0] = save_nssocks;
			_res._u._ext.nscount6 = saved_nscount6;
#			elif defined(HAVE_RES_U_EXT_EXT)	/* BSD */
			if (NULL != _res._u._ext.ext)
				memcpy(_res._u._ext.ext, &saved_ns6, sizeof(saved_ns6));
#			elif defined(HAVE_RES_EXT_EXT)		/* AIX */
			memcpy(&_res._ext.ext.nsaddrs[0], &saved_ns6, sizeof(saved_ns6));
#			endif
		}

		memcpy(&(_res.nsaddr_list[0]), &saved_ns, sizeof(struct sockaddr_in));
		_res.nscount = saved_nscount;
	}
#endif
	hp = (HEADER *)answer.buffer;

	if (1 == short_answer)
	{
		SET_UI64_RESULT(result, NOERROR != hp->rcode || 0 == ntohs(hp->ancount) || -1 == res ? 0 : 1);
		return SYSINFO_RET_OK;
	}

	if (NOERROR != hp->rcode || 0 == ntohs(hp->ancount) || -1 == res)
	{
		SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot perform DNS query."));
		return SYSINFO_RET_FAIL;
	}

	msg_end = answer.buffer + res;

	num_answers = ntohs(answer.h.ancount);
	num_query = ntohs(answer.h.qdcount);

	msg_ptr = answer.buffer + HFIXEDSZ;
	zbx_vector_str_create(&answers);

	/* skipping query records */
	for (; 0 < num_query && msg_ptr < msg_end; num_query--)
		msg_ptr += dn_skipname(msg_ptr, msg_end) + QFIXEDSZ;

	for (; 0 < num_answers && msg_ptr < msg_end; num_answers--)
	{
		if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr)))
		{
			SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response."));
			ret = SYSINFO_RET_FAIL;
			goto clean;
		}

		offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%-20s", name);

		GETSHORT(q_type, msg_ptr);
		GETSHORT(q_class, msg_ptr);
		msg_ptr += INT32SZ;		/* skipping TTL */
		GETSHORT(q_len, msg_ptr);
		offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %-8s", decode_type(q_type));

		switch (q_type)
		{
			case T_A:
				switch (q_class)
				{
					case C_IN:
					case C_HS:
						memcpy(&inaddr, msg_ptr, INADDRSZ);
						offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
								inet_ntoa(inaddr));
						break;
					default:
						;
				}

				msg_ptr += q_len;

				break;
			case T_AAAA:
				switch (q_class)
				{
					case C_IN:
					case C_HS:
						memcpy(&in6addr, msg_ptr, IN6ADDRSZ);
						offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s",
								inet_ntop(AF_INET6, &in6addr, tmp, sizeof(tmp)));
						break;
					default:
						;
				}

				msg_ptr += q_len;

				break;
			case T_NS:
			case T_CNAME:
			case T_MB:
			case T_MD:
			case T_MF:
			case T_MG:
			case T_MR:
			case T_PTR:
				if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr)))
				{
					SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response."));
					return SYSINFO_RET_FAIL;
				}
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name);
				break;
			case T_MX:
				GETSHORT(value, msg_ptr);	/* preference */
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value);

				if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr)))	/* exchange */
				{
					SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response."));
					return SYSINFO_RET_FAIL;
				}
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name);

				break;
			case T_SOA:
				if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr)))	/* source host */
				{
					SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response."));
					return SYSINFO_RET_FAIL;
				}
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name);

				if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr)))	/* administrator */
				{
					SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response."));
					return SYSINFO_RET_FAIL;
				}
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name);

				GETLONG(value, msg_ptr);	/* serial number */
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value);

				GETLONG(value, msg_ptr);	/* refresh time */
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value);

				GETLONG(value, msg_ptr);	/* retry time */
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value);

				GETLONG(value, msg_ptr);	/* expire time */
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value);

				GETLONG(value, msg_ptr);	/* minimum TTL */
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value);

				break;
			case T_NULL:
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " len:%d", q_len);
				msg_ptr += q_len;
				break;
			case T_WKS:
				if (INT32SZ + 1 > q_len)
				{
					SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response."));
					return SYSINFO_RET_FAIL;
				}

				p = msg_ptr + q_len;

				memcpy(&inaddr, msg_ptr, INADDRSZ);
				msg_ptr += INT32SZ;

				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", inet_ntoa(inaddr));

				if (NULL != (pr = getprotobynumber(*msg_ptr)))
					offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", pr->p_name);
				else
					offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", (int)*msg_ptr);

				msg_ptr++;
				n = 0;

				while (msg_ptr < p)
				{
					c = *msg_ptr++;

					do
					{
						if (0 != (c & 0200))
						{
							s = getservbyport((int)htons(n), pr ? pr->p_name : NULL);

							if (NULL != s)
								offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", s->s_name);
							else
								offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " #%d", n);
						}

						c <<= 1;
					}
					while (0 != (++n & 07));
				}

				break;
			case T_HINFO:
				p = msg_ptr + q_len;
				c = *msg_ptr++;

				if (0 != c)
				{
					offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " \"%.*s\"", c, msg_ptr);
					msg_ptr += c;
				}

				if (msg_ptr < p)
				{
					c = *msg_ptr++;

					if (0 != c)
					{
						offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " \"%.*s\"", c, msg_ptr);
						msg_ptr += c;
					}
				}

				break;
			case T_MINFO:
				if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr)))	/* mailbox responsible for mailing lists */
				{
					SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response."));
					return SYSINFO_RET_FAIL;
				}
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name);

				if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr)))	/* mailbox for error messages */
				{
					SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response."));
					return SYSINFO_RET_FAIL;
				}
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name);

				break;
			case T_TXT:
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " \"");
				p = msg_ptr + q_len;

				while (msg_ptr < p)
				{
					for (c = *msg_ptr++; 0 < c && msg_ptr < p; c--)
						offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%c", *msg_ptr++);
				}

				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "\"");

				break;
			case T_SRV:
				GETSHORT(value, msg_ptr);       /* priority */
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value);

				GETSHORT(value, msg_ptr);       /* weight */
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value);

				GETSHORT(value, msg_ptr);       /* port */
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value);

				if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr)))	/* target */
				{
					SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response."));
					return SYSINFO_RET_FAIL;
				}
				offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name);

				break;
			default:
				msg_ptr += q_len;
				break;
		}

		zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "\n");

		zbx_vector_str_append(&answers, zbx_strdup(NULL, buffer));
		offset = 0;
		*buffer = '\0';
	}
#endif	/* _WINDOWS */

	zbx_vector_str_sort(&answers, ZBX_DEFAULT_STR_COMPARE_FUNC);

	for (i = 0; i < answers.values_num; i++)
		offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%s", answers.values[i]);

	if (0 != offset)
		buffer[--offset] = '\0';

	SET_TEXT_RESULT(result, zbx_strdup(NULL, buffer));
	ret = SYSINFO_RET_OK;

clean:
	zbx_vector_str_clear_ext(&answers, zbx_str_free);
	zbx_vector_str_destroy(&answers);
#ifdef _WINDOWS
clean_dns:
	if (DNS_RCODE_NOERROR == res)
		DnsRecordListFree(pQueryResults, DnsFreeRecordList);
#endif

	return ret;

#else	/* both HAVE_RES_QUERY and _WINDOWS not defined */

	return SYSINFO_RET_FAIL;

#endif	/* defined(HAVE_RES_QUERY) || defined(_WINDOWS) */
}
コード例 #15
0
ファイル: lwnet-dns.c プロジェクト: FarazShaikh/LikewiseSMB2
DWORD
LWNetDnsQueryWithBuffer(
    IN PCSTR pszQuestion,
    IN BOOLEAN bReInit,
    IN BOOLEAN bUseTcp,
    OUT PVOID pBuffer,
    IN DWORD dwBufferSize,
    OUT PDWORD pdwResponseSize
    )
{
    DWORD dwError = 0;
    PDNS_RESPONSE_HEADER pHeader = (PDNS_RESPONSE_HEADER)pBuffer;
    int responseSize =  0;
    BOOLEAN bInLock = FALSE;
#if HAVE_DECL_RES_NINIT
    union
    {
        struct __res_state res;
#ifdef __LWI_AIX__
        // struct __res_state was enlarged from 720 in AIX 5.2 to 824 in AIX
        // 5.3. This means calling res_ninit on AIX 5.3 on a structure compiled
        // on AIX 5.2 will result in a buffer overflow. Furthermore, even on
        // AIX 5.3, res_ninit seems to expect 1596 bytes in the structure (1491
        // on AIX 5.2). As a workaround, this padding will ensure enough space
        // is allocated on the stack.
        char buffer[2048];
#endif
    } resLocal = { {0} };
    res_state res = &resLocal.res;
#else
    struct __res_state *res = &_res;
#endif

    LWNET_LOCK_RESOLVER_API(bInLock);

#if HAVE_DECL_RES_NINIT
    if (res_ninit(res) != 0)
#else
    if (res_init() != 0)
#endif
    {
        dwError = ERROR_NOT_FOUND;
        BAIL_ON_LWNET_ERROR(dwError);
    }
    
    if (dwBufferSize < CT_MIN(sizeof(DNS_RESPONSE_HEADER), MAX_DNS_UDP_BUFFER))
    {
        dwError = ERROR_INVALID_PARAMETER;
        BAIL_ON_LWNET_ERROR(dwError);
    }

    // TODO: Add lock on calling resolver due to global options, which may or
    // may not be safe depending on the system.
    if (bUseTcp)
    {
        res->options |= RES_USEVC;
    }
    else
    {
        res->options &= ~(RES_USEVC);
    }

    /* Assertion: pResolverContext != NULL && pResolverContext->bLocked == TRUE */
#if HAVE_DECL_RES_NINIT
    responseSize = res_nquery(res, pszQuestion, ns_c_in, ns_t_srv, (PBYTE) pBuffer, dwBufferSize);
#else
    responseSize = res_query(pszQuestion, ns_c_in, ns_t_srv, (PBYTE) pBuffer, dwBufferSize);
#endif
    if (responseSize < 0)
    {
        LWNET_LOG_VERBOSE("DNS lookup for '%s' failed with errno %d, h_errno = %d", pszQuestion, errno, h_errno);
        dwError = DNS_ERROR_BAD_PACKET;
        BAIL_ON_LWNET_ERROR(dwError);
    }
    if (responseSize < CT_FIELD_OFFSET(DNS_RESPONSE_HEADER, data))
    {
        dwError = DNS_ERROR_BAD_PACKET;
        BAIL_ON_LWNET_ERROR(dwError);
    }
    if (responseSize > dwBufferSize)
    {
        dwError = DNS_ERROR_BAD_PACKET;
        BAIL_ON_LWNET_ERROR(dwError);
    }

    LWNetDnsFixHeaderForEndianness(pHeader);

    if (!LWNetDnsIsValidResponse(pHeader))
    {
        dwError = DNS_ERROR_BAD_PACKET;
        BAIL_ON_LWNET_ERROR(dwError);
    }

error:

#if HAVE_DECL_RES_NINIT
    res_nclose(res);
#else
    /* Indicate that we are done with the resolver, except on HPUX which
       does not implement the res_close function. */
#ifndef __LWI_HP_UX__
    res_close();
#endif
#endif

    LWNET_UNLOCK_RESOLVER_API(bInLock);

    if (dwError)
    {
        responseSize = 0;
    }
    *pdwResponseSize = responseSize;
    return dwError;
}
コード例 #16
0
ファイル: NetworkUtils.cpp プロジェクト: brunchboy/ola
bool NameServers(vector<IPV4Address> *name_servers) {
#if HAVE_DECL_RES_NINIT
  struct __res_state res;
  memset(&res, 0, sizeof(struct __res_state));

  // Init the resolver info each time so it's always current for the RDM
  // responders in case we've set it via RDM too
  if (res_ninit(&res) != 0) {
    OLA_WARN << "Error getting nameservers via res_ninit";
    return false;
  }

  for (int32_t i = 0; i < res.nscount; i++) {
    IPV4Address addr = IPV4Address(res.nsaddr_list[i].sin_addr.s_addr);
    OLA_DEBUG << "Found Nameserver " << i << ": " << addr;
    name_servers->push_back(addr);
  }

  res_nclose(&res);
#elif defined(_WIN32)
  ULONG size = sizeof(FIXED_INFO);
  PFIXED_INFO fixed_info = NULL;
  while (1) {
    fixed_info = reinterpret_cast<PFIXED_INFO>(new uint8_t[size]);
    DWORD result = GetNetworkParams(fixed_info, &size);
    if (result == ERROR_SUCCESS) {
      break;
    }

    if (result != ERROR_BUFFER_OVERFLOW) {
      OLA_WARN << "GetNetworkParams failed with: " << GetLastError();
      return false;
    }

    delete[] fixed_info;
  }

  IP_ADDR_STRING* addr = &(fixed_info->DnsServerList);
  for (; addr; addr = addr->Next) {
    IPV4Address ipv4addr = IPV4Address(inet_addr(addr->IpAddress.String));
    OLA_DEBUG << "Found nameserver: " << ipv4addr;
    name_servers->push_back(ipv4addr);
  }

  delete[] fixed_info;
#else
  // Init the resolver info each time so it's always current for the RDM
  // responders in case we've set it via RDM too
  if (res_init() != 0) {
    OLA_WARN << "Error getting nameservers via res_init";
    return false;
  }

  for (int32_t i = 0; i < _res.nscount; i++) {
    IPV4Address addr = IPV4Address(_res.nsaddr_list[i].sin_addr.s_addr);
    OLA_DEBUG << "Found Nameserver " << i << ": " << addr;
    name_servers->push_back(addr);
  }
#endif

  return true;
}