bool Discovery::checkDomain() const { // If a domain has a SOA record, don't traverse any higher. // Returns true if no SOA can be found (domain is "ok" to use) // Stick to old resolver interface for portability reasons. union { HEADER header; unsigned char buf[ PACKETSZ ]; } response; int len = res_query( m_hostname.local8Bit(), C_IN, T_SOA, response.buf, sizeof( response.buf ) ); if ( len <= int( sizeof( response.header ) ) || ntohs( response.header.ancount ) != 1 ) return true; unsigned char* pos = response.buf + sizeof( response.header ); unsigned char* end = response.buf + len; // skip query section pos += dn_skipname( pos, end ) + QFIXEDSZ; if ( pos >= end ) return true; // skip answer domain pos += dn_skipname( pos, end ); short type; GETSHORT( type, pos ); return type != T_SOA; }
int ns_skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) { const u_char *optr = ptr; for ((void) NULL; count > 0; count--) { int b, rdlength; b = dn_skipname(ptr, eom); if (b < 0) { RETERR(EMSGSIZE); } ptr += b /*Name*/ + NS_INT16SZ /*Type*/ + NS_INT16SZ /*Class*/; if (section != ns_s_qd) { if (ptr + NS_INT32SZ + NS_INT16SZ > eom) { RETERR(EMSGSIZE); } ptr += NS_INT32SZ /*TTL*/; NS_GET16(rdlength, ptr); ptr += rdlength /*RData*/; } } if (ptr > eom) { RETERR(EMSGSIZE); } return (ptr - optr); }
isc_result_t ns_skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count, int *rc) { const u_char *optr = ptr; for ((void)NULL; count > 0; count--) { int b, rdlength; b = dn_skipname(ptr, eom); if (b < 0) return ISC_R_INCOMPLETE; ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/; if (section != ns_s_qd) { if (ptr + NS_INT32SZ + NS_INT16SZ > eom) return ISC_R_INCOMPLETE; ptr += NS_INT32SZ/*TTL*/; rdlength = getUShort(ptr); ptr += 2; ptr += rdlength/*RData*/; } } if (ptr > eom) return ISC_R_INCOMPLETE; if (rc) *rc = ptr - optr; return ISC_R_SUCCESS; }
static int parse_answer(querybuf_t *ans, int len, struct in_addr *addr) { char buf[MAXPACKET]; HEADER *ahp; u_char *cp, *eoa; int type, n; ahp = &ans->hdr; eoa = ans->buf + len; cp = ans->buf + sizeof(HEADER); while (ahp->qdcount > 0) { ahp->qdcount--; cp += dn_skipname(cp, eoa) + QFIXEDSZ; } while (ahp->ancount > 0 && cp < eoa) { ahp->ancount--; if ((n = dn_expand(ans->buf, eoa, cp, buf, sizeof(buf))) < 0) break; cp += n; type = _getshort(cp); cp += 8; n = _getshort(cp); cp += 2; if (type == T_CNAME) { cp += n; continue; } memcpy(addr, cp, n); return 0; } h_errno = TRY_AGAIN; return -1; }
dnsparse::dnsparse (const u_char *buf, size_t len, bool answer) : buf (buf), eom (buf + len), anp (NULL), error (0), hdr (len > sizeof (HEADER) ? (HEADER *) buf : NULL), ancount (hdr ? ntohs (hdr->ancount) : 0), nscount (hdr ? ntohs (hdr->nscount) : 0), arcount (hdr ? ntohs (hdr->arcount) : 0) { if (!hdr) error = ARERR_BADRESP; else if (hdr->rcode) error = hdr->rcode; else if ((!hdr->qr && answer) || (hdr->qr && !answer)) error = ARERR_BADRESP; else if (!ntohs (hdr->qdcount)) error = ARERR_BADRESP; #if 0 else if (hdr->tc) error = ARERR_BADRESP; #endif else { const u_char *cp = getqp (); for (int i = 0, l = ntohs (hdr->qdcount); i < l; i++) { int n = dn_skipname (cp, eom); cp += n + 4; if (n < 0 || cp > eom) { error = ARERR_BADRESP; return; } } anp = cp; } }
static int skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) { const u_char *optr = ptr; for ((void)NULL; count > 0; count--) { int b, rdlength; b = dn_skipname(ptr, eom); if (b < 0) goto emsgsize; ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/; if (section != ns_s_qd) { if (ptr + NS_INT32SZ > eom) goto emsgsize; ptr += NS_INT32SZ/*TTL*/; if (ptr + NS_INT16SZ > eom) goto emsgsize; NS_GET16(rdlength, ptr); ptr += rdlength/*RData*/; } } if (ptr > eom) goto emsgsize; return ((int)(ptr - optr)); emsgsize: errno = EMSGSIZE; return (-1); }
/* Modified version of req_action */ static enum req_action req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp, u_char *msg) { int dlen, alen, n, type, class, count; char anbuf[512], *data, *fname; /* * Skip domain name, get class, and type. */ if ((n = dn_skipname(*cpp, eom)) < 0) { printf("FORMERR IQuery packet name problem\n"); hp->rcode = FORMERR; return (Finish); } *cpp += n; GETSHORT(type, *cpp); GETSHORT(class, *cpp); *cpp += INT32SZ; /* ttl */ GETSHORT(dlen, *cpp); *cpp += dlen; if (*cpp != eom) { printf("FORMERR IQuery message length off\n"); hp->rcode = FORMERR; return (Finish); } /* * not all inverse queries are handled. * this is a meaningless switch statement to preserve original program's structure */ switch (type) { case T_A: if (something == 0) return (Refuse); break; default: return (Refuse); } printf("req: IQuery class %d type %d\n", class, type); fname = (char *)msg + HFIXEDSZ; alen = (char *)*cpp - fname; printf("Copying %d bytes from fname to anbuf which can store %d bytes\n", alen, sizeof(anbuf)); /*BAD*/ memcpy(anbuf, fname, alen); data = anbuf + alen - dlen; *cpp = (u_char *)fname; *buflenp -= HFIXEDSZ; count = 0; /* ..... do some other stuff */ return (Finish); }
static int dblchk(str *domain, str *dbltxt) { str dblstr; char *dbl = getenv("DBLLOOKUP"); int l, i; unsigned char ansbuf[512]; if(!dbl || domain->len == 0) return 0; if(session_getnum("sump",0)) return 0; /* no point */ str_init(&dblstr); str_copy(&dblstr, domain); str_catc(&dblstr, '.'); str_cats(&dblstr, dbl); l = res_query(dblstr.s, C_IN, T_TXT, ansbuf, sizeof(ansbuf)); if(l > 0 && ((HEADER *)ansbuf)->ancount != 0) { /* something in the answer */ unsigned char *recbuf = ansbuf+NS_HFIXEDSZ; /* skip over questions, why am I still writing stuff * like this? */ for(i = ns_get16(ansbuf+4); i != 0; --i) recbuf += dn_skipname(recbuf, ansbuf+l)+4; for(i = ns_get16(ansbuf+6); i != 0; --i) { recbuf += dn_skipname(recbuf, ansbuf+l); if(ns_get16(recbuf) != T_TXT) { /* CNAME or something */ recbuf += 10 + ns_get16(recbuf+8); continue; } /* it's a TXT record, wow */ str_init(dbltxt); str_copyb(dbltxt, (char*)recbuf+11, recbuf[10]); str_free(&dblstr); return 1; } } /* didn't find anything */ str_free(&dblstr); return 0; }
int php_getmxrr(char *hostname, char *mx_list, char *weight_list) { #ifdef PCC_MINGW return 0; #else char *mx_list_ptr = (char *)(mx_list + sprintf(mx_list, "")); char *weight_list_ptr = (char *)(weight_list + sprintf(weight_list, "")); unsigned char answer[MAXPACKET]; unsigned char expand_buffer[MAXHOSTNAMELEN]; int ans_len = res_search(hostname, C_IN, T_MX, answer, sizeof(answer)); HEADER *header_ptr = (HEADER *)&answer; unsigned char *body_ptr = (unsigned char *)&answer + NS_HFIXEDSZ; unsigned char *eom_ptr = (unsigned char *)&answer + sizeof(answer); int n, ancount, qdcount, type, weight; for (qdcount = ntohs((unsigned short)header_ptr->qdcount); qdcount--; body_ptr += (n + NS_QFIXEDSZ)) if ((n = dn_skipname(body_ptr, eom_ptr)) < 0) return -1; ancount = ntohs((unsigned short)header_ptr->ancount); while (--ancount >= 0 && body_ptr < eom_ptr) { if ((n = dn_skipname(body_ptr, eom_ptr)) < 0) return -1; body_ptr += n; NS_GET16(type, body_ptr); body_ptr += (NS_INT16SZ + NS_INT32SZ); NS_GET16(n, body_ptr); if (type != T_MX) { body_ptr += n; continue; } NS_GET16(weight, body_ptr); if ((n = dn_expand(answer, eom_ptr, body_ptr, expand_buffer, sizeof(expand_buffer) - 1)) < 0) return -1; body_ptr += n; mx_list_ptr += sprintf(mx_list_ptr - 1, " %s ", expand_buffer); weight_list_ptr += sprintf(weight_list_ptr - 1, " %d ", weight); } return 0; #endif /* PCC_MINGW */ }
u_char * ns_find_tsig(u_char *msg, u_char *eom) { HEADER *hp = (HEADER *)msg; int n, type; u_char *cp = msg, *start; isc_result_t status; if (msg == NULL || eom == NULL || msg > eom) return (NULL); if (cp + HFIXEDSZ >= eom) return (NULL); if (hp->arcount == 0) return (NULL); cp += HFIXEDSZ; status = ns_skiprr(cp, eom, ns_s_qd, ntohs(hp->qdcount), &n); if (status != ISC_R_SUCCESS) return (NULL); cp += n; status = ns_skiprr(cp, eom, ns_s_an, ntohs(hp->ancount), &n); if (status != ISC_R_SUCCESS) return (NULL); cp += n; status = ns_skiprr(cp, eom, ns_s_ns, ntohs(hp->nscount), &n); if (status != ISC_R_SUCCESS) return (NULL); cp += n; status = ns_skiprr(cp, eom, ns_s_ar, ntohs(hp->arcount) - 1, &n); if (status != ISC_R_SUCCESS) return (NULL); cp += n; start = cp; n = dn_skipname(cp, eom); if (n < 0) return (NULL); cp += n; if (cp + INT16SZ >= eom) return (NULL); GETSHORT(type, cp); if (type != ns_t_tsig) return (NULL); return (start); }
/* * krb5int_dns_nextans() - get next answer record * * Sets pp to NULL if no more records. */ 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); /* Also skip 4 bytes of TTL */ 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; /* Solaris Kerberos - resync */ #if 0 if (rdlen > INT_MAX) return -1; #endif if (nclass == ds->nclass && ntype == ds->ntype) { *pp = p; *lenp = rdlen; ds->ptr = p + rdlen; return 0; } p += rdlen; } return 0; out: return -1; }
bool dnsparse::skipnrecs (const u_char **cpp, u_int nrec) { const u_char *cp = *cpp; while (nrec-- > 0) { int n = dn_skipname (cp, eom); cp += n; if (n < 0 || cp + 10 > eom) return false; cp += 8; u_int16_t rdlen; GETSHORT (rdlen, cp); if (rdlen > eom - cp) return false; cp += rdlen; } *cpp = cp; return true; }
/* * initparse * * Skip header and question section of reply. Set a pointer to the * beginning of the answer section, and prepare to iterate over * answer records. */ 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 ((size_t) 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); /* * Skip query records. */ 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; }
static int dns_ns_skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) { const u_char *optr = ptr; while (count-- > 0) { int b, rdlength; b = dn_skipname(ptr, eom); if (b < 0) RETERR(EMSGSIZE); ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/; if (section != ns_s_qd) { if (ptr + NS_INT32SZ + NS_INT16SZ > eom) RETERR(EMSGSIZE); ptr += NS_INT32SZ/*TTL*/; DNS_NS_GET16(rdlength, ptr); ptr += rdlength/*RData*/; } } if (ptr > eom) RETERR(EMSGSIZE); return (ptr - optr); }
static int dns_query(const char *cmd, const char *param, unsigned flags, AGENT_RESULT *result, int short_answer) { #if defined(HAVE_RES_QUERY) || defined(_WINDOWS) size_t offset = 0; int res, type, retrans, retry, i, ret = SYSINFO_RET_FAIL; char ip[MAX_STRING_LEN], zone[MAX_STRING_LEN], tmp[MAX_STRING_LEN], buffer[MAX_STRING_LEN]; struct in_addr inaddr; #ifndef _WINDOWS int saved_nscount, saved_retrans, saved_retry; struct sockaddr_in saved_ns; #endif typedef struct { char *name; int type; } resolv_querytype_t; static const resolv_querytype_t qt[] = { {"ANY", T_ANY}, {"A", T_A}, {"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; LPTSTR wzone; char tmp2[MAX_STRING_LEN]; #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 */ *buffer = '\0'; if (5 < num_param(param)) return SYSINFO_RET_FAIL; if (0 != get_param(param, 1, ip, sizeof(ip))) *ip = '\0'; if (0 != get_param(param, 2, zone, sizeof(zone)) || '\0' == *zone) strscpy(zone, "zabbix.com"); if (0 != get_param(param, 3, tmp, sizeof(tmp)) || '\0' == *tmp) type = T_SOA; else { for (i = 0; NULL != qt[i].name; i++) { #ifdef _WINDOWS if (0 == lstrcmpiA(qt[i].name, tmp)) #else if (0 == strcasecmp(qt[i].name, tmp)) #endif { type = qt[i].type; break; } } if (NULL == qt[i].name) return SYSINFO_RET_FAIL; } if (0 != get_param(param, 4, tmp, sizeof(tmp)) || '\0' == *tmp) retrans = 1; else retrans = atoi(tmp); if (0 != get_param(param, 5, tmp, sizeof(tmp)) || '\0' == *tmp) retry = 2; else retry = atoi(tmp); #ifdef _WINDOWS wzone = zbx_utf8_to_unicode(zone); res = DnsQuery(wzone, type, DNS_QUERY_STANDARD, 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; } if (DNS_RCODE_NOERROR != res) return SYSINFO_RET_FAIL; pDnsRecord = pQueryResults; 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_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; } offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "\n"); pDnsRecord = pDnsRecord->pNext; } #else /* not _WINDOWS */ if (-1 == res_init()) /* initialize always, settings might have changed */ return SYSINFO_RET_FAIL; if (-1 == (res = res_mkquery(QUERY, zone, C_IN, type, NULL, 0, NULL, buf, sizeof(buf)))) return SYSINFO_RET_FAIL; if ('\0' != *ip) { if (0 == inet_aton(ip, &inaddr)) return SYSINFO_RET_FAIL; 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; } saved_retrans = _res.retrans; saved_retry = _res.retry; _res.retrans = retrans; _res.retry = retry; res = res_send(buf, res, answer.buffer, sizeof(answer.buffer)); _res.retrans = saved_retrans; _res.retry = saved_retry; if ('\0' != *ip) { memcpy(&(_res.nsaddr_list[0]), &saved_ns, sizeof(struct sockaddr_in)); _res.nscount = saved_nscount; } 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) 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; /* 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))) return SYSINFO_RET_FAIL; 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_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))) 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 */ 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 */ 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 */ 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) 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 */ 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 */ 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 */ return SYSINFO_RET_FAIL; offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name); break; default: msg_ptr += q_len; break; } offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "\n"); } #endif /* _WINDOWS */ if (0 != offset) buffer[--offset] = '\0'; SET_TEXT_RESULT(result, zbx_strdup(NULL, buffer)); ret = SYSINFO_RET_OK; #ifdef _WINDOWS clean: 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) */ }
int getsrv (const char *name,struct srventry **list) { int srvcount=0; u16 count; int i, rc; *list = NULL; #ifdef USE_ADNS { adns_state state; adns_answer *answer = NULL; rc = adns_init (&state, adns_if_noerrprint, NULL); if (rc) { log_error ("error initializing adns: %s\n", strerror (errno)); return -1; } rc = adns_synchronous (state, name, adns_r_srv, adns_qf_quoteok_query, &answer); if (rc) { log_error ("DNS query failed: %s\n", strerror (errno)); adns_finish (state); return -1; } if (answer->status != adns_s_ok || answer->type != adns_r_srv || !answer->nrrs) { /* log_error ("DNS query returned an error or no records: %s (%s)\n", */ /* adns_strerror (answer->status), */ /* adns_errabbrev (answer->status)); */ adns_free (answer); adns_finish (state); return 0; } for (count = 0; count < answer->nrrs; count++) { struct srventry *srv = NULL; struct srventry *newlist; if (strlen (answer->rrs.srvha[count].ha.host) >= MAXDNAME) { log_info ("hostname in SRV record too long - skipped\n"); continue; } newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry)); if (!newlist) goto fail; *list = newlist; memset (&(*list)[srvcount], 0, sizeof(struct srventry)); srv = &(*list)[srvcount]; srvcount++; srv->priority = answer->rrs.srvha[count].priority; srv->weight = answer->rrs.srvha[count].weight; srv->port = answer->rrs.srvha[count].port; strcpy (srv->target, answer->rrs.srvha[count].ha.host); } adns_free (answer); adns_finish (state); } #else /*!USE_ADNS*/ { unsigned char answer[2048]; HEADER *header = (HEADER *)answer; unsigned char *pt, *emsg; int r; u16 dlen; r = res_query (name, C_IN, T_SRV, answer, sizeof answer); if (r < sizeof (HEADER) || r > sizeof answer) return -1; if (header->rcode != NOERROR || !(count=ntohs (header->ancount))) return 0; /* Error or no record found. */ emsg = &answer[r]; pt = &answer[sizeof(HEADER)]; /* Skip over the query */ rc = dn_skipname (pt, emsg); if (rc == -1) goto fail; pt += rc + QFIXEDSZ; while (count-- > 0 && pt < emsg) { struct srventry *srv=NULL; u16 type,class; struct srventry *newlist; newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry)); if (!newlist) goto fail; *list = newlist; memset(&(*list)[srvcount],0,sizeof(struct srventry)); srv=&(*list)[srvcount]; srvcount++; rc = dn_skipname(pt,emsg); /* the name we just queried for */ if (rc == -1) goto fail; pt+=rc; /* Truncated message? */ if((emsg-pt)<16) goto fail; type=*pt++ << 8; type|=*pt++; /* We asked for SRV and got something else !? */ if(type!=T_SRV) goto fail; class=*pt++ << 8; class|=*pt++; /* We asked for IN and got something else !? */ if(class!=C_IN) goto fail; pt+=4; /* ttl */ dlen=*pt++ << 8; dlen|=*pt++; srv->priority=*pt++ << 8; srv->priority|=*pt++; srv->weight=*pt++ << 8; srv->weight|=*pt++; srv->port=*pt++ << 8; srv->port|=*pt++; /* Get the name. 2782 doesn't allow name compression, but dn_expand still works to pull the name out of the packet. */ rc = dn_expand(answer,emsg,pt,srv->target,MAXDNAME); if (rc == 1 && srv->target[0] == 0) /* "." */ { xfree(*list); *list = NULL; return 0; } if (rc == -1) goto fail; pt += rc; /* Corrupt packet? */ if (dlen != rc+6) goto fail; } } #endif /*!USE_ADNS*/ /* Now we have an array of all the srv records. */ /* Order by priority */ qsort(*list,srvcount,sizeof(struct srventry),priosort); /* For each priority, move the zero-weighted items first. */ for (i=0; i < srvcount; i++) { int j; for (j=i;j < srvcount && (*list)[i].priority == (*list)[j].priority; j++) { if((*list)[j].weight==0) { /* Swap j with i */ if(j!=i) { struct srventry temp; memcpy (&temp,&(*list)[j],sizeof(struct srventry)); memcpy (&(*list)[j],&(*list)[i],sizeof(struct srventry)); memcpy (&(*list)[i],&temp,sizeof(struct srventry)); } break; } } } /* Run the RFC-2782 weighting algorithm. We don't need very high quality randomness for this, so regular libc srand/rand is sufficient. Fixme: It is a bit questionaly to reinitalize srand - better use a gnupg fucntion for this. */ srand(time(NULL)*getpid()); for (i=0; i < srvcount; i++) { int j; float prio_count=0,chose; for (j=i; j < srvcount && (*list)[i].priority == (*list)[j].priority; j++) { prio_count+=(*list)[j].weight; (*list)[j].run_count=prio_count; } chose=prio_count*rand()/RAND_MAX; for (j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++) { if (chose<=(*list)[j].run_count) { /* Swap j with i */ if(j!=i) { struct srventry temp; memcpy(&temp,&(*list)[j],sizeof(struct srventry)); memcpy(&(*list)[j],&(*list)[i],sizeof(struct srventry)); memcpy(&(*list)[i],&temp,sizeof(struct srventry)); } break; } } } return srvcount; fail: xfree(*list); *list=NULL; return -1; }
/* ns_verify * Parameters: * statp res stuff * msg received message * msglen length of message * key tsig key used for verifying. * querysig (response), the signature in the query * querysiglen (response), the length of the signature in the query * sig (query), a buffer to hold the signature * siglen (query), input - length of signature buffer * output - length of signature * * Errors: * - bad input (-1) * - invalid dns message (NS_TSIG_ERROR_FORMERR) * - TSIG is not present (NS_TSIG_ERROR_NO_TSIG) * - key doesn't match (-ns_r_badkey) * - TSIG verification fails with BADKEY (-ns_r_badkey) * - TSIG verification fails with BADSIG (-ns_r_badsig) * - TSIG verification fails with BADTIME (-ns_r_badtime) * - TSIG verification succeeds, error set to BAKEY (ns_r_badkey) * - TSIG verification succeeds, error set to BADSIG (ns_r_badsig) * - TSIG verification succeeds, error set to BADTIME (ns_r_badtime) */ isc_result_t ns_verify(u_char *msg, unsigned *msglen, void *k, const u_char *querysig, unsigned querysiglen, u_char *sig, unsigned *siglen, time_t *timesigned, int nostrip) { HEADER *hp = (HEADER *)msg; DST_KEY *key = (DST_KEY *)k; u_char *cp = msg, *eom; char name[MAXDNAME], alg[MAXDNAME]; u_char *recstart, *rdatastart; u_char *sigstart, *otherstart; unsigned n; int error; u_int16_t type, length; u_int16_t fudge, sigfieldlen, id, otherfieldlen; dst_init(); if (msg == NULL || msglen == NULL) return ISC_R_INVALIDARG; eom = msg + *msglen; recstart = ns_find_tsig(msg, eom); if (recstart == NULL) return ISC_R_NO_TSIG; cp = recstart; /* Read the key name. */ n = dn_expand(msg, eom, cp, name, MAXDNAME); if (n < 0) return ISC_R_FORMERR; cp += n; /* Read the type. */ BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ); GETSHORT(type, cp); if (type != ns_t_tsig) return ISC_R_NO_TSIG; /* Skip the class and TTL, save the length. */ cp += INT16SZ + INT32SZ; GETSHORT(length, cp); if (eom - cp != length) return ISC_R_FORMERR; /* Read the algorithm name. */ rdatastart = cp; n = dn_expand(msg, eom, cp, alg, MAXDNAME); if (n < 0) return ISC_R_FORMERR; if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1) return ISC_R_INVALIDKEY; cp += n; /* Read the time signed and fudge. */ BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); cp += INT16SZ; GETLONG((*timesigned), cp); GETSHORT(fudge, cp); /* Read the signature. */ BOUNDS_CHECK(cp, INT16SZ); GETSHORT(sigfieldlen, cp); BOUNDS_CHECK(cp, sigfieldlen); sigstart = cp; cp += sigfieldlen; /* Read the original id and error. */ BOUNDS_CHECK(cp, 2*INT16SZ); GETSHORT(id, cp); GETSHORT(error, cp); /* Parse the other data. */ BOUNDS_CHECK(cp, INT16SZ); GETSHORT(otherfieldlen, cp); BOUNDS_CHECK(cp, otherfieldlen); otherstart = cp; cp += otherfieldlen; if (cp != eom) return ISC_R_FORMERR; /* Verify that the key used is OK. */ if (key != NULL) { if (key->dk_alg != KEY_HMAC_MD5) return ISC_R_INVALIDKEY; if (error != ns_r_badsig && error != ns_r_badkey) { if (ns_samename(key->dk_key_name, name) != 1) return ISC_R_INVALIDKEY; } } hp->arcount = htons(ntohs(hp->arcount) - 1); /* * Do the verification. */ if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { void *ctx; u_char buf[MAXDNAME]; /* Digest the query signature, if this is a response. */ dst_verify_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0); if (querysiglen > 0 && querysig != NULL) { u_int16_t len_n = htons(querysiglen); dst_verify_data(SIG_MODE_UPDATE, key, &ctx, (u_char *)&len_n, INT16SZ, NULL, 0); dst_verify_data(SIG_MODE_UPDATE, key, &ctx, querysig, querysiglen, NULL, 0); } /* Digest the message. */ dst_verify_data(SIG_MODE_UPDATE, key, &ctx, msg, (unsigned)(recstart - msg), NULL, 0); /* Digest the key name. */ n = ns_name_ntol(recstart, buf, sizeof(buf)); dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); /* Digest the class and TTL. */ dst_verify_data(SIG_MODE_UPDATE, key, &ctx, recstart + dn_skipname(recstart, eom) + INT16SZ, INT16SZ + INT32SZ, NULL, 0); /* Digest the algorithm. */ n = ns_name_ntol(rdatastart, buf, sizeof(buf)); dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); /* Digest the time signed and fudge. */ dst_verify_data(SIG_MODE_UPDATE, key, &ctx, rdatastart + dn_skipname(rdatastart, eom), INT16SZ + INT32SZ + INT16SZ, NULL, 0); /* Digest the error and other data. */ dst_verify_data(SIG_MODE_UPDATE, key, &ctx, otherstart - INT16SZ - INT16SZ, (unsigned)otherfieldlen + INT16SZ + INT16SZ, NULL, 0); n = dst_verify_data(SIG_MODE_FINAL, key, &ctx, NULL, 0, sigstart, sigfieldlen); if (n < 0) return ISC_R_BADSIG; if (sig != NULL && siglen != NULL) { if (*siglen < sigfieldlen) return ISC_R_NOSPACE; memcpy(sig, sigstart, sigfieldlen); *siglen = sigfieldlen; } } else { if (sigfieldlen > 0) return ISC_R_FORMERR; if (sig != NULL && siglen != NULL) *siglen = 0; } /* Reset the counter, since we still need to check for badtime. */ hp->arcount = htons(ntohs(hp->arcount) + 1); /* Verify the time. */ if (abs((*timesigned) - time(NULL)) > fudge) return ISC_R_BADTIME; if (nostrip == 0) { *msglen = recstart - msg; hp->arcount = htons(ntohs(hp->arcount) - 1); } if (error != NOERROR) return ns_rcode_to_isc (error); return ISC_R_SUCCESS; }
/* Setup a client socket for the named service over the given protocol under * the given domain name. */ static int insrv_lookup (int (*mksox) (int,const struct sockaddr *,socklen_t), char *service, char *proto, char *domain, char *cnxhost, size_t cnxhlen, int *cnxport) { // 1. convert service/proto to svcnm // 2. construct SRV query for _service._proto.domain // 3. try connecting to all answers in turn // 4. if no SRV records exist, lookup A record to connect to on stdport // 5. return connection socket or error code iobuf query, names; name svcnm; int error=0; int ctr; int rnd; int sox=0; HEADER *nameshdr; unsigned char *here, *srv[MAXNUM_SRV], *ip; int num_srv=0; // Storage for fallback SRV list, constructed when DNS gives no SRV unsigned char fallbacksrv [2*(MAXCDNAME+SRV_FIXEDSZ+MAXCDNAME)]; srv_flags &= ~SRV_GOT_MASK; srv_flags |= SRV_GOT_SRV; strcpy (svcnm, "_"); strcat (svcnm, service); strcat (svcnm, "._"); strcat (svcnm, proto); // Note that SRV records are only defined for class IN if (domain) { names.len=res_querydomain (svcnm, domain, C_IN, T_SRV, names.buf, PACKETSZ); } else { names.len=res_query (svcnm, C_IN, T_SRV, names.buf, PACKETSZ); } if (names.len < 0) { error = -ENOENT; goto fallback; } nameshdr=(HEADER *) names.buf; here=names.buf + HFIXEDSZ; rnd=nameshdr->id; // Heck, gimme one reason why not! if ((names.len < HFIXEDSZ) || nameshdr->tc) { error = -EMSGSIZE; } switch (nameshdr->rcode) { case 1: error = -EFAULT; goto fallback; case 2: error = -EAGAIN; goto fallback; case 3: error = -ENOENT; goto fallback; case 4: error = -ENOSYS; goto fallback; case 5: error = -EPERM; goto fallback; default: break; } if (ntohs (nameshdr->ancount) == 0) { error = -ENOENT; goto fallback; } if (ntohs (nameshdr->ancount) > MAXNUM_SRV) { error = -ERANGE; goto fallback; } for (ctr=ntohs (nameshdr->qdcount); ctr>0; ctr--) { int strlen=dn_skipname (here, names.buf+names.len); here += strlen + QFIXEDSZ; } for (ctr=ntohs (nameshdr->ancount); ctr>0; ctr--) { int strlen=dn_skipname (here, names.buf+names.len); here += strlen; srv [num_srv++] = here; here += SRV_FIXEDSZ; here += dn_skipname (here, names.buf+names.len); } // In case an error occurred, there are no SRV records. // Fallback strategy now is: construct two. One with the domain name, // the other with the /standard/ service name prefixed. // Note: Assuming a domain without the service name prefixed! fallback: if (error) { struct servent *servent = getservbyname (service, proto); srv_flags &= ~SRV_GOT_MASK; srv_flags |= SRV_GOT_A; num_srv = 2; if (!servent) { return error; // First error returned } srv [0] = here = fallbacksrv; // Only few record fields are really needed: *(unsigned short *)(here + SRV_COST) = htons (0); *(unsigned short *)(here + SRV_WEIGHT) = htons (0); *(unsigned short *)(here + SRV_PORT) = servent->s_port; here += SRV_FIXEDSZ; if (domain) { here += dn_comp (domain, here, MAXCDNAME, NULL, NULL); } // Forget about the name whose SRV IN this is, no need for it srv [1] = here; // Only few record fields are really needed: *(unsigned short *)(here + SRV_COST) = htons (1); *(unsigned short *)(here + SRV_WEIGHT) = htons (0); *(unsigned short *)(here + SRV_PORT) = servent->s_port; here += SRV_FIXEDSZ; here += dn_comp (servent->s_name, here, MAXCDNAME, NULL, NULL); here--; // Go back to overwrite final zero byte if (domain) { here += dn_comp (domain, here, MAXCDNAME, NULL, NULL); } rnd = 1; } // End of fallback construction, making sure that variables are defined // srv[] points to the SRV RR, num_srv counts the number of entries. // Every SRV RR has at least cost, weight, port and servername set. #ifdef DEBUG for (ctr=0; ctr<num_srv; ctr++) { name srvname; if (ns_name_ntop (srv [ctr]+SRV_SERVER, srvname, MAXDNAME) < 0) { return -errno; } printf ("Considering SRV server %d %d %d\t%s\n", ns_get16 (srv [ctr]+SRV_COST), ns_get16 (srv [ctr]+SRV_WEIGHT), ns_get16 (srv [ctr]+SRV_PORT), srvname ); } #endif // Overwrite weight with rnd-spread version to divide load over weights for (ctr=0; ctr<num_srv; ctr++) { *(unsigned short *)(srv [ctr]+SRV_WEIGHT) = rnd % (1+ns_get16 (srv [ctr]+SRV_WEIGHT)); } qsort (srv, num_srv, sizeof (*srv), srvcmp); for (ctr=0; ctr<num_srv; ctr++) { name srvname; struct hostent *host; // Open a socket to connect with int sox = socket (PF_INET, (*proto!='u')? SOCK_STREAM: SOCK_DGRAM, 0); if (sox < 0) { return -errno; } if (ns_name_ntop (srv [ctr]+SRV_SERVER, srvname, MAXDNAME) < 0) { return -errno; } #ifdef DEBUG printf ("Trying SRV server %d %d\t%s\n", ns_get16 (srv [ctr]+SRV_COST), *(unsigned short *)(srv [ctr]+SRV_WEIGHT), srvname ); #endif if ((host=gethostbyname (srvname)) && (host->h_addrtype == AF_INET)) { char **ip=host->h_addr_list; while (*ip) { char *ipnr=*ip; struct sockaddr_in sin; memset (&sin, 0, sizeof (sin)); sin.sin_family = AF_INET; memcpy (&sin.sin_addr, ipnr, sizeof (sin.sin_addr)); sin.sin_port = *(unsigned short *) (srv [ctr]+SRV_PORT); #ifdef DEBUG fprintf (stderr, "\tbind_connect (%d, 0x%08lx, %d)\t", sox, ntohl(*(unsigned long *)ipnr), ntohs (sin.sin_port)); #endif #ifdef DEBUG if (mksox == connect) { printf ("mksox == connect\n"); } if (mksox == bind) { printf ("mksox == bind\n"); } { int i; printf ("SIN ="); for (i=0; i<sizeof (sin); i++) printf (" %02x", (int) (((unsigned char *) &sin) [i])); printf ("\n"); } #endif if (mksox (sox, (struct sockaddr *) &sin, sizeof (sin)) == 0) { #ifdef DEBUG fprintf (stderr, "Connected or bound to %s:%d\n", srvname, ntohs (sin.sin_port)); #endif if (cnxhost) { if (strlen (cnxhost) > cnxhlen-1) { *cnxhost = '\0'; } else { strncpy (cnxhost,srvname,cnxhlen); } } if (cnxport) { *cnxport = ntohs (sin.sin_port); } return sox; } else { if (!error) { error = -errno; } } ip++; } } #ifdef DEBUG printf ("Closing socket %d\n", sox); #endif close (sox); } if (!error) { error = -ENOENT; } return error; }
CAMLprim value mlresolv_query(value vdname, value vclass, value vtype) { union { HEADER hdr; /* defined in resolv.h */ u_char buf[PACKETSZ]; /* defined in arpa/nameser.h */ } response; int rc; u_char *cp, *tcp; u_char *eom; char r_name[MAXDNAME+1]; u_short r_class; u_short r_type; u_int32_t r_ttl; u_short r_len; int ancount, qdcount; value vres = Val_emptylist; if(vtype == caml_hash_variant("PTR")) { int a, b, c, d; a = b = c = d = 0; sscanf(String_val(vdname), "%u.%u.%u.%u", &a, &b, &c, &d); sprintf(r_name, "%u.%u.%u.%u.in-addr.arpa", d, c, b, a); rc = res_query(r_name, mlvariant_to_c(rr_class, vclass), mlvariant_to_c(rr_type, vtype), (u_char*)&response, sizeof(response)); } else rc = res_query(String_val(vdname), mlvariant_to_c(rr_class, vclass), mlvariant_to_c(rr_type, vtype), (u_char*)&response, sizeof(response)); if (rc < 0) { switch (h_errno) { case NETDB_INTERNAL: mlresolv_error(errno); case HOST_NOT_FOUND: /* Authoritative Answer Host not found */ raise_constant(*mlresolv_host_not_found_exn); case TRY_AGAIN: /* Non-Authoritative Host not found, or SERVERFAIL */ raise_constant(*mlresolv_try_again_exn); case NO_RECOVERY: raise_constant(*mlresolv_no_recovery_exn); case NO_DATA: /* Valid name, no data record of requested type */ raise_constant(*mlresolv_no_data_exn); case NETDB_SUCCESS: /* no problem */ defaykt: failwith("res_query: unknown error"); } } cp = (u_char *)&response.buf + sizeof(HEADER); eom = (u_char *)&response.buf + rc; ancount = ntohs(response.hdr.ancount) + ntohs(response.hdr.nscount); qdcount = ntohs(response.hdr.qdcount); for (; (qdcount > 0) && (cp < eom); qdcount--) { rc = dn_skipname(cp, eom) + QFIXEDSZ; if(rc < 0) failwith("dn_skipname failed"); cp += rc; } for (; (ancount > 0) && (cp < eom); ancount--) { value vrdata, vfields = Val_unit; rc = dn_expand(response.buf, eom, cp, (void*)r_name, MAXDNAME); if(rc < 0) failwith("dn_expand1 failed"); cp += rc; NS_GET16(r_type, cp); NS_GET16(r_class, cp); NS_GET32(r_ttl, cp); NS_GET16(r_len, cp); if(cp + r_len > eom) /* is this check necessary? */ r_len = eom - cp; tcp = cp; switch(r_type) { case ns_t_a: /* if(r_class == ns_c_in || r_class == ns_c_hs) { */ if(INADDRSZ > r_len) vfields = copy_string(""); else { struct in_addr inaddr; char *address; bcopy(tcp, (char *)&inaddr, INADDRSZ); address = (char *)inet_ntoa(inaddr); vfields = copy_string(address); } break; case ns_t_cname: case ns_t_ns: case ns_t_mb: case ns_t_md: case ns_t_mf: case ns_t_mg: case ns_t_mr: case ns_t_ptr: case ns_t_nsap_ptr: { char r_name[MAXDNAME+1]; rc = dn_expand(response.buf, eom, cp, (void *) r_name, MAXDNAME); if(rc < 0) vfields = copy_string(""); else vfields = copy_string(r_name); break; } case ns_t_null: /* max up to 65535 */ vfields = caml_alloc_string(r_len); memmove(String_val(vfields), cp, r_len); break; case ns_t_txt: { int txtlen, rdata_len = r_len; value newcons, txt; vfields = Val_emptylist; while(tcp < eom && *tcp <= rdata_len) { txtlen = *tcp++; txt = caml_alloc_string(txtlen); memmove(String_val(txt), tcp, txtlen); tcp += txtlen; rdata_len -= txtlen+1; newcons = alloc_small(2, 0); Field(newcons, 0) = txt; Field(newcons, 1) = vfields; vfields = newcons; } break; } case ns_t_srv: if(INT16SZ * 3 <= r_len) { char r_name[MAXDNAME+1]; int prio, weight, port; NS_GET16(prio, tcp); NS_GET16(weight, tcp); NS_GET16(port, tcp); rc = dn_expand(response.buf, eom, tcp, (void *) r_name, MAXDNAME); vfields = alloc_small(4, 0); Field(vfields, 0) = Val_int(prio); Field(vfields, 1) = Val_int(weight); Field(vfields, 2) = Val_int(port); if(rc < 0) Field(vfields, 3) = copy_string(""); else Field(vfields, 3) = copy_string(r_name); } break; case ns_t_mx: case ns_t_rt: case ns_t_afsdb: if(INT16SZ <= r_len) { char r_name[MAXDNAME+1]; int prio; NS_GET16(prio, tcp); rc = dn_expand(response.buf, eom, tcp, (void *) r_name, MAXDNAME); vfields = alloc_small(2, 0); Field(vfields, 0) = Val_int(prio); if(rc < 0) Field(vfields, 1) = copy_string(""); else Field(vfields, 1) = copy_string(r_name); } break; case ns_t_soa: { char mname[MAXDNAME+1]; char rname[MAXDNAME+1]; u_int serial, minimum; int refresh, retry, expire; if((rc = dn_expand(response.buf, eom, tcp, (void *)mname, MAXDNAME)) < 0) break; tcp += rc; if((rc = dn_expand(response.buf, eom, tcp, (void *)rname, MAXDNAME)) < 0) break; tcp += rc; if (tcp - cp + INT32SZ * 5 > r_len) break; NS_GET32(serial, tcp); NS_GET32(refresh, tcp); NS_GET32(retry, tcp); NS_GET32(expire, tcp); NS_GET32(minimum, tcp); vfields = alloc_small(7, 0); Field(vfields, 0) = copy_string(mname); Field(vfields, 1) = copy_string(rname); Field(vfields, 2) = Val_int(serial); Field(vfields, 3) = Val_int(refresh); Field(vfields, 4) = Val_int(retry); Field(vfields, 5) = Val_int(expire); Field(vfields, 6) = Val_int(minimum); } break; case ns_t_minfo: { char rmailbx[MAXDNAME+1]; char emailbx[MAXDNAME+1]; if((rc = dn_expand(response.buf, eom, tcp, rmailbx, MAXDNAME)) < 0) break; tcp += rc; if((rc = dn_expand(response.buf, eom, tcp, emailbx, MAXDNAME)) < 0) break; vfields = alloc_small(2, 0); Field(vfields, 0) = copy_string(rmailbx); Field(vfields, 1) = copy_string(emailbx); } break; /* two strings */ case ns_t_hinfo: case ns_t_isdn: /* <ISDN-address> <sa> */ case ns_t_nsap: if(r_len > 0 && *tcp < r_len) { value str1; value str2; rc = *tcp++; if(r_type == ns_t_nsap) { int result = 0; for(; rc; rc--, tcp++) result += result * 10 + (*tcp - 0x38); str1 = Val_int(result); } else { str1 = caml_alloc_string(rc); memmove(String_val(str1), tcp, rc); tcp += rc; } if(rc + 1 > r_len && *tcp + rc + 2 >= r_len) { rc = *tcp++; str2 = caml_alloc_string(rc); memmove(String_val(str2), tcp, rc); } else str2 = copy_string(""); vfields = caml_alloc_small(2, 0); Field(vfields, 0) = str1; Field(vfields, 1) = str2; } break; case ns_t_wks: if(INADDRSZ + 1 <= r_len) { struct in_addr inaddr; char* address; u_short protocol; value bitmap; bcopy(tcp, (char *) &inaddr, INADDRSZ); address = (char*) inet_ntoa(inaddr); tcp += INADDRSZ; protocol = *tcp++; /* getprotobynumber(*cp) */ /* n = 0; while (cp < eom) { c = *cp++; do { if (c & 0200) { int port; port = htons((u_short)n); if (protocol != NULL) service = getservbyport(port, protocol->p_name); else service = NULL; if (service != NULL) doprintf((" %s", service->s_name)); else doprintf((" %s", dtoa(n))); } c <<= 1; } while (++n & 07); } doprintf((" )")); */ bitmap = caml_alloc_string(r_len - INADDRSZ - 1); memmove(String_val(bitmap), tcp, eom - tcp); vfields = alloc_small(4, 0); Field(vfields, 0) = copy_string(address); Field(vfields, 1) = Val_int(protocol); Field(vfields, 2) = bitmap; } break; case ns_t_rp: /* <mbox-dname> <txt-dname> */ { char rname1[MAXDNAME+1]; char rname2[MAXDNAME+1]; rc = dn_expand(response.buf, eom, tcp, rname1, MAXDNAME); if(rc < 0) break; tcp += rc; rc = dn_expand(response.buf, eom, tcp, rname2, MAXDNAME); if(rc < 0) break; vfields = alloc_small(2, 0); Field(vfields, 0) = copy_string(rname1); Field(vfields, 1) = copy_string(rname2); } break; case ns_t_x25: /* <PSDN-address> */ if(r_len > 0 && *tcp >= r_len) { rc = *tcp++; vfields = caml_alloc_string(rc); memmove(String_val(vfields), tcp, rc); } else vfields = copy_string(""); break; case ns_t_px: if(r_len > INT16SZ) { int pref; char rname1[MAXDNAME]; char rname2[MAXDNAME]; NS_GET16(pref, tcp); rc = dn_expand(response.buf, eom, tcp, rname1, MAXDNAME); if(rc < 0) break; tcp += rc; rc = dn_expand(response.buf, eom, tcp, rname2, MAXDNAME); if(rc < 0) break; tcp += rc; vfields = alloc_small(2, 0); Field(vfields, 0) = copy_string(rname1); Field(vfields, 1) = copy_string(rname2); } break; case ns_t_gpos: if(r_len > 0 && *tcp <= r_len) { float f1, f2, f3; char *tmp; rc = *tcp++; tmp = (char *) malloc(rc + 1); bcopy(tcp, tmp, rc); tmp[rc] = '\0'; f1 = atof(tmp); tcp += rc; if(tcp < eom && tcp + *tcp <= eom) { if(*tcp > rc) tmp = realloc(tmp, *tcp); rc = *tcp++; bcopy(tcp, tmp, rc); tmp[rc] = '\0'; f2 = atof(tmp); tcp += rc; } else f2 = 0.0; if(tcp < eom && tcp + *tcp <= eom) { if(*tcp > rc) tmp = realloc(tmp, *tcp); rc = *tcp++; bcopy(tcp, tmp, rc); tmp[rc] = '\0'; f3 = atof(tmp); tcp += rc; } else f3 = 0.0; free(tmp); vfields = alloc_small(3, 0); Field(vfields, 0) = copy_double((double)f1); Field(vfields, 1) = copy_double((double)f2); Field(vfields, 2) = copy_double((double)f3); } break; case ns_t_loc: failwith("LOC not implemented"); /* if(r_len > 0 && *tcp != 0) failwith("Invalid version in LOC RDATA"); if(r_len > 0) { rc = INT n = INT32SZ + 3*INT32SZ; if (check_size(rname, type, cp, msg, eor, n) < 0) break; c = _getlong(cp); cp += INT32SZ; n = _getlong(cp); doprintf(("\t%s ", pr_spherical(n, "N", "S"))); cp += INT32SZ; n = _getlong(cp); doprintf((" %s ", pr_spherical(n, "E", "W"))); cp += INT32SZ; n = _getlong(cp); doprintf((" %sm ", pr_vertical(n, "", "-"))); cp += INT32SZ; doprintf((" %sm", pr_precision((c >> 16) & 0xff))); doprintf((" %sm", pr_precision((c >> 8) & 0xff))); doprintf((" %sm", pr_precision((c >> 0) & 0xff))); break; */ /* case T_UID: case T_GID: if(INT32SZ <= r_len) NS_GET32(rc, cp); if (dlen == INT32SZ) { n = _getlong(cp); doprintf(("\t%s", dtoa(n))); cp += INT32SZ; } break; case T_UINFO: doprintf(("\t\"%s\"", stoa(cp, dlen, TRUE))); cp += dlen; break; case T_UNSPEC: cp += dlen; break; case T_AAAA: if (dlen == IPNGSIZE) { doprintf(("\t%s", ipng_ntoa(cp))); cp += IPNGSIZE; } break; case T_SIG: if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0) break; n = _getshort(cp); if (n >= T_FIRST && n <= T_LAST) doprintf(("\t%s", pr_type(n))); else doprintf(("\t%s", dtoa(n))); cp += INT16SZ; if (check_size(rname, type, cp, msg, eor, 1) < 0) break; n = *cp++; doprintf((" %s", dtoa(n))); if (check_size(rname, type, cp, msg, eor, 1) < 0) break; n = *cp++; doprintf((" %s", dtoa(n))); n = 3*INT32SZ + INT16SZ; if (check_size(rname, type, cp, msg, eor, n) < 0) break; doprintf((" (")); n = _getlong(cp); doprintf(("\n\t\t\t%s", dtoa(n))); doprintf(("\t\t;original ttl")); cp += INT32SZ; n = _getlong(cp); doprintf(("\n\t\t\t%s", pr_date(n))); doprintf(("\t;signature expiration")); cp += INT32SZ; n = _getlong(cp); doprintf(("\n\t\t\t%s", pr_date(n))); doprintf(("\t;signature inception")); cp += INT32SZ; n = _getshort(cp); doprintf(("\n\t\t\t%s", dtoa(n))); doprintf(("\t\t;key tag")); cp += INT16SZ; n = expand_name(rname, type, cp, msg, eom, dname); if (n < 0) break; doprintf(("\n\t\t\t%s", pr_name(dname))); cp += n; if (cp < eor) { register char *buf; register int size; n = eor - cp; buf = base_ntoa(cp, n); size = strlength(buf); cp += n; while ((n = (size > 64) ? 64 : size) > 0) { doprintf(("\n\t%s", stoa((u_char *)buf, n, FALSE))); buf += n; size -= n; } } doprintf(("\n\t\t\t)")); break; case T_KEY: if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0) break; n = _getshort(cp); doprintf(("\t0x%s", xtoa(n))); cp += INT16SZ; if (check_size(rname, type, cp, msg, eor, 1) < 0) break; n = *cp++; doprintf((" %s", dtoa(n))); if (check_size(rname, type, cp, msg, eor, 1) < 0) break; n = *cp++; doprintf((" %s", dtoa(n))); if (cp < eor) { register char *buf; register int size; n = eor - cp; buf = base_ntoa(cp, n); size = strlength(buf); cp += n; doprintf((" (")); while ((n = (size > 64) ? 64 : size) > 0) { doprintf(("\n\t%s", stoa((u_char *)buf, n, FALSE))); buf += n; size -= n; } doprintf(("\n\t\t\t)")); } break; case T_NXT: n = expand_name(rname, type, cp, msg, eom, dname); if (n < 0) break; doprintf(("\t%s", pr_name(dname))); cp += n; n = 0; while (cp < eor) { c = *cp++; do { if (c & 0200) { if (n >= T_FIRST && n <= T_LAST) doprintf((" %s", pr_type(n))); else doprintf((" %s", dtoa(n))); } c <<= 1; } while (++n & 07); } break; case T_NAPTR: if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0) break; n = _getshort(cp); doprintf(("\t%s", dtoa(n))); cp += INT16SZ; if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0) break; n = _getshort(cp); doprintf((" %s", dtoa(n))); cp += INT16SZ; if (check_size(rname, type, cp, msg, eor, 1) < 0) break; n = *cp++; doprintf((" \"%s\"", stoa(cp, n, TRUE))); cp += n; if (check_size(rname, type, cp, msg, eor, 1) < 0) break; n = *cp++; doprintf((" \"%s\"", stoa(cp, n, TRUE))); cp += n; if (check_size(rname, type, cp, msg, eor, 1) < 0) break; n = *cp++; doprintf((" \"%s\"", stoa(cp, n, TRUE))); cp += n; n = expand_name(rname, type, cp, msg, eom, dname); if (n < 0) break; doprintf((" %s", pr_name(dname))); cp += n; break; case T_KX: if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0) break; n = _getshort(cp); doprintf(("\t%s", dtoa(n))); cp += INT16SZ; n = expand_name(rname, type, cp, msg, eom, dname); if (n < 0) break; doprintf((" %s", pr_name(dname))); cp += n; break; case T_CERT: if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0) break; n = _getshort(cp); doprintf(("\t%s", dtoa(n))); cp += INT16SZ; if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0) break; n = _getshort(cp); doprintf((" %s", dtoa(n))); cp += INT16SZ; if (check_size(rname, type, cp, msg, eor, 1) < 0) break; n = *cp++; doprintf((" %s", dtoa(n))); if (cp < eor) { register char *buf; register int size; n = eor - cp; buf = base_ntoa(cp, n); size = strlength(buf); cp += n; doprintf((" (")); while ((n = (size > 64) ? 64 : size) > 0) { doprintf(("\n\t%s", stoa((u_char *)buf, n, FALSE))); buf += n; size -= n; } doprintf(("\n\t\t\t)")); } break; case T_EID: failwith("EID not implemented"); break; case T_NIMLOC: failwith("NIMLOC not implemented"); break; case T_ATMA: failwith("ATMA not implemented"); */ default: failwith("unknown RDATA type"); } if(vfields != Val_unit) { value vrecord, vrdata, newcons; Begin_root(vres); vrecord = alloc_small(5, 0); Field(vrecord, 0) = copy_string(r_name); Field(vrecord, 1) = c_to_mlvariant(rr_type, r_type); Field(vrecord, 2) = c_to_mlvariant(rr_class, r_class); Field(vrecord, 3) = Val_int(r_ttl); vrdata = alloc_small(2, 0); Field(vrdata, 0) = c_to_mlvariant(rr_type, r_type); Field(vrdata, 1) = vfields; Field(vrecord, 4) = vrdata; newcons = alloc_small(2, 0); Field(newcons, 0) = vrecord; Field(newcons, 1) = vres; vres = newcons; End_roots(); vrdata = Val_unit; } cp += r_len; } return vres; }
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; }
static int printZone(ns_type xfr, const char *zone, const struct sockaddr_in *sin, ns_tsig_key *key) { static u_char *answer = NULL; static int answerLen = 0; querybuf buf; int msglen, amtToRead, numRead, result, sockFD, len; int count, type, rlen, done, n; int numAnswers, numRecords, soacnt; u_char *cp, tmp[NS_INT16SZ]; char dname[2][NS_MAXDNAME]; enum { NO_ERRORS, ERR_READING_LEN, ERR_READING_MSG, ERR_PRINTING } error; pid_t zpid = -1; u_char *newmsg; int newmsglen; ns_tcp_tsig_state tsig_state; int tsig_ret, tsig_required, tsig_present; switch (xfr) { case ns_t_axfr: case ns_t_zxfr: break; default: fprintf(stderr, ";; %s - transfer type not supported\n", p_type(xfr)); return (ERROR); } /* * Create a query packet for the requested zone name. */ msglen = res_nmkquery(&res, ns_o_query, zone, queryClass, ns_t_axfr, NULL, 0, 0, buf.qb2, sizeof buf); if (msglen < 0) { if (res.options & RES_DEBUG) fprintf(stderr, ";; res_nmkquery failed\n"); return (ERROR); } /* * Sign the message if a key was sent */ if (key == NULL) { newmsg = (u_char *)&buf; newmsglen = msglen; } else { DST_KEY *dstkey; int bufsize, siglen; u_char sig[64]; int ret; /* ns_sign() also calls dst_init(), but there is no harm * doing it twice */ dst_init(); bufsize = msglen + 1024; newmsg = (u_char *) malloc(bufsize); if (newmsg == NULL) { errno = ENOMEM; return (-1); } memcpy(newmsg, (u_char *)&buf, msglen); newmsglen = msglen; if (strcmp(key->alg, NS_TSIG_ALG_HMAC_MD5) != 0) dstkey = NULL; else dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5, NS_KEY_TYPE_AUTH_ONLY, NS_KEY_PROT_ANY, key->data, key->len); if (dstkey == NULL) { errno = EINVAL; if (key) free(newmsg); return (-1); } siglen = sizeof(sig); /* newmsglen++; */ ret = ns_sign(newmsg, &newmsglen, bufsize, NOERROR, dstkey, NULL, 0, sig, &siglen, 0); if (ret < 0) { if (key) free (newmsg); if (ret == NS_TSIG_ERROR_NO_SPACE) errno = EMSGSIZE; else if (ret == -1) errno = EINVAL; return (ret); } ns_verify_tcp_init(dstkey, sig, siglen, &tsig_state); } /* * Set up a virtual circuit to the server. */ if ((sockFD = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) { int e = errno; perror(";; socket"); return (e); } switch (sin->sin_family) { case AF_INET: if (bind(sockFD, (struct sockaddr *)&myaddress, sizeof myaddress) < 0){ int e = errno; fprintf(stderr, ";; bind(%s port %u): %s\n", inet_ntoa(myaddress.sin_addr), ntohs(myaddress.sin_port), strerror(e)); (void) close(sockFD); sockFD = -1; return (e); } if (connect(sockFD, (const struct sockaddr *)sin, sizeof *sin) < 0) { int e = errno; perror(";; connect"); (void) close(sockFD); sockFD = -1; return (e); } break; case AF_INET6: if (bind(sockFD, (struct sockaddr *)&myaddress6, sizeof myaddress6) < 0){ int e = errno; char buf[80]; fprintf(stderr, ";; bind(%s port %u): %s\n", inet_ntop(AF_INET6, &myaddress6.sin6_addr, buf, sizeof(buf)), ntohs(myaddress6.sin6_port), strerror(e)); (void) close(sockFD); sockFD = -1; return (e); } if (connect(sockFD, (const struct sockaddr *)sin, sizeof(struct sockaddr_in6)) < 0) { int e = errno; perror(";; connect"); (void) close(sockFD); sockFD = -1; return (e); } break; } /* * Send length & message for zone transfer */ ns_put16(newmsglen, tmp); if (write(sockFD, (char *)tmp, NS_INT16SZ) != NS_INT16SZ || write(sockFD, (char *)newmsg, newmsglen) != newmsglen) { int e = errno; if (key) free (newmsg); perror(";; write"); (void) close(sockFD); sockFD = -1; return (e); } else if (key) free (newmsg); /* * If we're compressing, push a gzip into the pipeline. */ if (xfr == ns_t_zxfr) { enum { rd = 0, wr = 1 }; int z[2]; if (pipe(z) < 0) { int e = errno; perror(";; pipe"); (void) close(sockFD); sockFD = -1; return (e); } zpid = vfork(); if (zpid < 0) { int e = errno; perror(";; fork"); (void) close(sockFD); sockFD = -1; return (e); } else if (zpid == 0) { /* Child. */ (void) close(z[rd]); (void) dup2(sockFD, STDIN_FILENO); (void) close(sockFD); (void) dup2(z[wr], STDOUT_FILENO); (void) close(z[wr]); execlp("gzip", "gzip", "-d", "-v", NULL); perror(";; child: execlp(gunzip)"); _exit(1); } /* Parent. */ (void) close(z[wr]); (void) dup2(z[rd], sockFD); (void) close(z[rd]); } result = 0; numAnswers = 0; numRecords = 0; soacnt = 0; error = NO_ERRORS; numRead = 0; dname[0][0] = '\0'; for (done = 0; !done; (void)NULL) { /* * Read the length of the response. */ cp = tmp; amtToRead = INT16SZ; while (amtToRead > 0 && (numRead = read(sockFD, cp, amtToRead)) > 0) { cp += numRead; amtToRead -= numRead; } if (numRead <= 0) { error = ERR_READING_LEN; break; } len = ns_get16(tmp); if (len == 0) break; /* nothing left to read */ /* * The server sent too much data to fit the existing buffer -- * allocate a new one. */ if (len > answerLen) { if (answerLen != 0) free(answer); answerLen = len; answer = (u_char *)malloc(answerLen); } /* * Read the response. */ amtToRead = len; cp = answer; while (amtToRead > 0 && (numRead = read(sockFD, cp, amtToRead)) > 0) { cp += numRead; amtToRead -= numRead; } if (numRead <= 0) { error = ERR_READING_MSG; break; } result = print_axfr(stdout, answer, len); if (result != 0) { error = ERR_PRINTING; break; } numRecords += htons(((HEADER *)answer)->ancount); numAnswers++; /* Header. */ cp = answer + HFIXEDSZ; /* Question. */ for (count = ntohs(((HEADER *)answer)->qdcount); count > 0; count--) { n = dn_skipname(cp, answer + len); if (n < 0) { error = ERR_PRINTING; done++; break; } cp += n + QFIXEDSZ; if (cp > answer + len) { error = ERR_PRINTING; done++; break; } } /* Answer. */ for (count = ntohs(((HEADER *)answer)->ancount); count > 0 && !done; count--) { n = dn_expand(answer, answer + len, cp, dname[soacnt], sizeof dname[0]); if (n < 0) { error = ERR_PRINTING; done++; break; } cp += n; if (cp + 3 * INT16SZ + INT32SZ > answer + len) { error = ERR_PRINTING; done++; break; } GETSHORT(type, cp); cp += INT16SZ; cp += INT32SZ; /* ttl */ GETSHORT(rlen, cp); cp += rlen; if (cp > answer + len) { error = ERR_PRINTING; done++; break; } if (type == T_SOA && soacnt++ && ns_samename(dname[0], dname[1]) == 1) { done++; break; } } /* * Verify the TSIG */ if (key) { if (ns_find_tsig(answer, answer + len) != NULL) tsig_present = 1; else tsig_present = 0; if (numAnswers == 1 || soacnt > 1) tsig_required = 1; else tsig_required = 0; tsig_ret = ns_verify_tcp(answer, &len, &tsig_state, tsig_required); if (tsig_ret == 0) { if (tsig_present) printf("; TSIG ok\n"); } else printf("; TSIG invalid\n"); } } printf(";; Received %d answer%s (%d record%s).\n", numAnswers, (numAnswers != 1) ? "s" : "", numRecords, (numRecords != 1) ? "s" : ""); (void) close(sockFD); sockFD = -1; /* * If we were uncompressing, reap the uncompressor. */ if (xfr == ns_t_zxfr) { pid_t pid; int status = 0; pid = wait(&status); if (pid < 0) { int e = errno; perror(";; wait"); return (e); } if (pid != zpid) { fprintf(stderr, ";; wrong pid (%lu != %lu)\n", (u_long)pid, (u_long)zpid); return (ERROR); } printf(";; pid %lu: exit %d, signal %d, core %c\n", (u_long)pid, WEXITSTATUS(status), WIFSIGNALED(status) ? WTERMSIG(status) : 0, WCOREDUMP(status) ? 't' : 'f'); } switch (error) { case NO_ERRORS: return (0); case ERR_READING_LEN: return (EMSGSIZE); case ERR_PRINTING: return (result); case ERR_READING_MSG: return (EMSGSIZE); default: return (EFAULT); } }
DNS::HostMap DNS::resolve( const std::string& service, const std::string& proto, const std::string& domain, const LogSink& logInstance ) { buffer srvbuf; bool error = false; const std::string dname = "_" + service + "._" + proto; if( !domain.empty() ) srvbuf.len = res_querydomain( dname.c_str(), const_cast<char*>( domain.c_str() ), C_IN, T_SRV, srvbuf.buf, NS_PACKETSZ ); else srvbuf.len = res_query( dname.c_str(), C_IN, T_SRV, srvbuf.buf, NS_PACKETSZ ); if( srvbuf.len < 0 ) return defaultHostMap( domain, logInstance ); HEADER* hdr = (HEADER*)srvbuf.buf; unsigned char* here = srvbuf.buf + NS_HFIXEDSZ; if( ( hdr->tc ) || ( srvbuf.len < NS_HFIXEDSZ ) ) error = true; if( hdr->rcode >= 1 && hdr->rcode <= 5 ) error = true; if( ntohs( hdr->ancount ) == 0 ) error = true; if( ntohs( hdr->ancount ) > NS_PACKETSZ ) error = true; int cnt; for( cnt = ntohs( hdr->qdcount ); cnt>0; --cnt ) { int strlen = dn_skipname( here, srvbuf.buf + srvbuf.len ); here += strlen + NS_QFIXEDSZ; } unsigned char* srv[NS_PACKETSZ]; int srvnum = 0; for( cnt = ntohs( hdr->ancount ); cnt>0; --cnt ) { int strlen = dn_skipname( here, srvbuf.buf + srvbuf.len ); here += strlen; srv[srvnum++] = here; here += SRV_FIXEDSZ; here += dn_skipname( here, srvbuf.buf + srvbuf.len ); } if( error ) { return defaultHostMap( domain, logInstance ); } // (q)sort here HostMap servers; for( cnt=0; cnt<srvnum; ++cnt ) { name srvname; if( ns_name_ntop( srv[cnt] + SRV_SERVER, (char*)srvname, NS_MAXDNAME ) < 0 ) printf( "handle this error!\n" ); servers[(char*)srvname] = ns_get16( srv[cnt] + SRV_PORT ); } return servers; }
int gethinfo(register char *hostname, register char *cpu, register int cpulen, register char *os, register int oslen) { #ifdef HAVE_DN_SKIPNAME register querybuf *qb; register u_char *cp, *eom; register char *bp; register int n; register HEADER *hp; register int type, class, buflen, ancount, qdcount; querybuf qbuf; qb = &qbuf; n = res_query(hostname, C_IN, T_HINFO, qb->buf, sizeof(qb->buf)); if (n < 0) return (0); eom = qb->buf + n; /* * find first satisfactory answer */ hp = &qb->hdr; ancount = ntohs(hp->ancount); qdcount = ntohs(hp->qdcount); bp = hostbuf; buflen = sizeof(hostbuf); cp = qb->buf + sizeof(HEADER); if (qdcount) { cp += dn_skipname(cp, eom) + QFIXEDSZ; while (--qdcount > 0) cp += dn_skipname(cp, eom) + QFIXEDSZ; } while (--ancount >= 0 && cp < eom) { if ((n = dn_expand((u_char *)qb->buf, (u_char *)eom, (u_char *)cp, (u_char *)bp, buflen)) < 0) break; cp += n; type = _getshort(cp); cp += sizeof(u_short); class = _getshort(cp); cp += sizeof(u_short) + sizeof(u_int32_t); n = _getshort(cp); cp += sizeof(u_short); if (type == T_HINFO) { /* Unpack */ n = *cp++; if (n > cpulen - 1) return (0); BCOPY(cp, cpu, n); cp += n; cpu[n] = '\0'; n = *cp++; if (n > oslen - 1) return (0); BCOPY(cp, os, n); os[n] = '\0'; return (1); } /* Skip unexpected junk */ cp += n; } #endif return (0); }
static int dnsSD_Request(HSP *sp, char *dname, uint16_t rtype, HSPDnsCB callback, HSPSFlowSettings *settings) { u_char buf[PACKETSZ]; // We could have a config option to set the DNS servers that we will ask. If so // they should be written into this array of sockaddrs... // myDebug(1,"_res_nsaddr=%p", &_res.nsaddr); myDebug(1,"=== res_search(%s, C_IN, %u) ===", dname, rtype); int anslen = res_search(dname, C_IN, rtype, buf, PACKETSZ); if(anslen == -1) { if(errno == 0 && (h_errno == HOST_NOT_FOUND || h_errno == NO_DATA)) { // although res_search returned -1, the request did actually get an answer, // it's just that there was no SRV record configured, or the response was // not authoritative. Interpret this the same way as answer_count==0. myDebug(1,"res_search(%s, C_IN, %u) came up blank (h_errno=%d)", dname, rtype, h_errno); return 0; } else { myLog(LOG_ERR,"res_search(%s, C_IN, %u) failed : %s (h_errno=%d)", dname, rtype, strerror(errno), h_errno); return -1; } } if(anslen < sizeof(HEADER)) { myLog(LOG_ERR,"res_search(%s) returned %d (too short)", dname, anslen); return -1; } HEADER *ans = (HEADER *)buf; if(ans->rcode != NOERROR) { myLog(LOG_ERR,"res_search(%s) returned response code %d", dname, ans->rcode); return -1; } uint32_t answer_count = (ntohs(ans->ancount)); if(answer_count == 0) { myLog(LOG_INFO,"res_search(%s) returned no answer", dname); return 0; } myDebug(1, "dnsSD: answer_count = %d", answer_count); u_char *p = buf + sizeof(HEADER); u_char *endp = buf + anslen; // consume query int query_name_len = dn_skipname(p, endp); if(query_name_len == -1) { myLog(LOG_ERR,"dn_skipname() <query> failed"); return -1; } myDebug(1, "dnsSD: (compressed) query_name_len = %d", query_name_len); p += (query_name_len); p += QFIXEDSZ; // collect array of results for(int entry = 0; entry < answer_count; entry++) { myDebug(1, "dnsSD: entry %d, bytes_left=%d", entry, (endp - p)); // consume name (again) query_name_len = dn_skipname(p, endp); if(query_name_len == -1) { myLog(LOG_ERR,"dn_skipname() <ans> failed"); return -1; } p += (query_name_len); // now p should be looking at: // [type:16][class:16][ttl:32][len:16][record] if((endp - p) <= 16) { myLog(LOG_ERR,"ans %d of %d: ran off end -- only %d bytes left", entry, answer_count, (endp-p)); return -1; } uint16_t res_typ = (p[0] << 8) | p[1]; uint16_t res_cls = (p[2] << 8) | p[3]; uint32_t res_ttl = (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]; uint16_t res_len = (p[8] << 8) | p[9]; p += 10; // use another pointer to walk the payload and move p to the next answer u_char *x = p; p += res_len; uint16_t res_payload = res_len; // sanity check if(res_typ != rtype || res_cls != C_IN) { myLog(LOG_ERR,"expected t=%d,c=%d, got t=%d,c=%d", rtype, C_IN, res_typ, res_cls); return -1; } switch(rtype) { case T_SRV: { // now x should see // [priority:2][weight:2][port:2][FQDN:res_len-6] uint16_t res_pri = (x[0] << 8) | x[1]; uint16_t res_wgt = (x[2] << 8) | x[3]; uint32_t res_prt = (x[4] << 8) | x[5]; x += 6; res_payload -= 6; // still got room for an FQDN? if((endp - x) < HSP_MIN_DNAME) { myLog(LOG_ERR,"no room for target name -- only %d bytes left", (endp - x)); return -1; } char fqdn[MAXDNAME]; int ans_len = dn_expand(buf, endp, x, fqdn, MAXDNAME); if(ans_len == -1) { myLog(LOG_ERR,"dn_expand() failed"); return -1; } // cross-check if(ans_len != res_payload) { myLog(LOG_ERR,"target name len cross-check failed"); return -1; } if(ans_len < HSP_MIN_DNAME) { // just ignore this one -- e.g. might just be "." } else { // fqdn[ans_len] = '\0'; myDebug(1, "answer %d is <%s>:<%u> (wgt=%d; pri=%d; ttl=%d; ans_len=%d; res_len=%d)", entry, fqdn, res_prt, res_wgt, res_pri, res_ttl, ans_len, res_len); if(callback) { char fqdn_port[PACKETSZ]; sprintf(fqdn_port, "%s/%u", fqdn, res_prt); // use key == NULL to indicate that the value is host:port (*callback)(sp, rtype, res_ttl, NULL, 0, (u_char *)fqdn_port, strlen(fqdn_port), settings); } } } break; case T_TXT: { // now x should see // [TXT:res_len] // still got room for a text record? if((endp - x) < HSP_MIN_TXT) { myLog(LOG_ERR,"no room for text record -- only %d bytes left", (endp - x)); return -1; } if(getDebug()) { printf("dsnSD TXT Record: "); for(int i = 0; i < res_len; i++) { int ch = x[i]; if(isalnum(ch)) printf("%c", ch); else printf("{%02x}", ch); } printf("\n"); } // format is [len][<key>=<val>][len][<key>=<val>]... // so we can pull out the settings and give them directly // to the callback fn without copying u_char *txtend = x + res_len; // need at least 3 chars for a var=val setting while((txtend - x) >= 3) { int pairlen = *x++; int klen = strcspn((char *)x, "="); if(klen < 0) { myLog(LOG_ERR, "dsnSD TXT record not in var=val format: %s", x); } else { if(callback) (*callback)(sp, rtype, res_ttl, x, klen, (x+klen+1), (pairlen - klen - 1), settings); } x += pairlen; } } break; default: myLog(LOG_ERR, "unsupported query type: %u" , rtype); return -1; break; } } return answer_count; }
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; }
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) */ }
int getrrs(const char *label, int rrtype, void gotrec(unsigned int num, int type, const char *record)) { #ifdef _LINUX struct __res_state res; #endif unsigned char answer[8192]; HEADER *header = (HEADER *)answer; char buf[2048]; int ret, count; unsigned int i,j,k,rrnum = 0; unsigned char *startptr, *endptr, *ptr; uint16_t type = 0, class = 0; uint32_t ttl = 0; #ifdef _LINUX memset(&res, 0, sizeof(res)); res.options = RES_DEBUG; res_ninit(&res); #else res_init(); #endif memset(answer, 0, sizeof(answer)); #ifdef _LINUX ret = res_nquery(&res, label, C_IN, rrtype, answer, sizeof(answer)); #else ret = res_query(label, C_IN, rrtype, answer, sizeof(answer)); #endif if (ret < 0) return -1; /* Our start and end */ startptr = &answer[0]; endptr = &answer[ret]; /* Skip the header */ ptr = startptr + HFIXEDSZ; /* Skip Query part */ for (count = ntohs(header->qdcount); count--; ptr += ret + QFIXEDSZ) { if ((ret = dn_skipname(ptr, endptr)) < 0) return -1; } /* Only look at the Answer section */ count = ntohs(header->ancount); /* Go through all the Answer records */ while (ptr < endptr && count > 0) { rrnum++; memset(buf, 0, sizeof(buf)); ret = dn_expand (startptr, endptr, ptr, buf, sizeof(buf)); if (ret < 0) break; ptr += ret; if (ptr + INT16SZ + INT16SZ + INT32SZ >= endptr) break; /* Get the type */ NS_GET16(type, ptr); /* Get the class */ NS_GET16(class, ptr); /* Get the TTL */ NS_GET32(ttl, ptr); /* Get the RDLength */ NS_GET16(ret, ptr); memset(buf, 0, sizeof(buf)); switch (type) { case T_TXT: for (k = ret, j = 0; j < k && &ptr[j] < endptr; j += (i+1)) { i = ptr[j]; memcpy(buf, &ptr[j+1], i > sizeof(buf) ? sizeof(buf) : i); buf[i > sizeof(buf) ? sizeof(buf) : i] = '\0'; if (rrtype == type || rrtype == T_ANY) gotrec(rrnum, type, buf); } break; case T_A: inet_ntop(AF_INET, ptr, buf, sizeof(buf)); if (rrtype == type || rrtype == T_ANY) gotrec(rrnum, type, buf); break; case T_AAAA: inet_ntop(AF_INET6, ptr, buf, sizeof(buf)); if (rrtype == type || rrtype == T_ANY) gotrec(rrnum, type, buf); break; case T_MX: /* Get the MX preference */ NS_GET16(ttl, ptr); ret = dn_expand(startptr, endptr, ptr, buf, sizeof(buf)); if (rrtype == type || rrtype == T_ANY) gotrec(rrnum, type, buf); break; case T_NS: ret = dn_expand(startptr, endptr, ptr, buf, sizeof(buf)); if (rrtype == type || rrtype == T_ANY) gotrec(rrnum, type, buf); break; default: /* Unhandled */ break; } ptr += ret; count--; } return 0; }
int Resolver :: ar_procanswer(DNSSession* session, HEADER* hptr, u_char* buf, u_char* eob) { u_char* cp = NULL; char** alias = NULL; int xclass, type = 0, dlen, len, ans = 0, n = 0; char** adr = NULL; char ar_hostbuf[MAXDNAME]; /* Must be on stack */ unsigned int ancount = 0 , arcount = 0 , nscount = 0, qdcount = 0; int host_cnt = 0; /* * convert things to be in the right order. */ ancount = ntohs(hptr->ancount); arcount = ntohs(hptr->arcount); nscount = ntohs(hptr->nscount); qdcount = ntohs(hptr->qdcount); cp = buf + HFIXEDSZ; hent& re_he = session->getHent(); adr = re_he.h_addr_list; #ifdef DNS_DEBUG Print_query(buf, eob, 1); #endif while (*adr) { adr++; host_cnt++; } alias = re_he.h_aliases; while (*alias) { alias++; } /* * Skip over the original question. */ while (qdcount > 0) { qdcount--; cp += dn_skipname((const unsigned char*)cp, (const unsigned char*)eob) + QFIXEDSZ; } /* * process each answer sent to us. blech. */ while ((ancount > 0) && (cp < eob)) { ancount--; PR_Lock(dnslock); n = dn_expand((const unsigned char*)buf, (const unsigned char*)eob, (const unsigned char*)cp, (char*)ar_hostbuf, sizeof(ar_hostbuf)); PR_Unlock(dnslock); cp += n; if (n <= 0) return ans; ans++; /* * 'skip' past the general dns crap (ttl, xclass, etc) to get * the pointer to the right spot. Some of thse are actually * useful so its not a good idea to skip past in one big jump. */ type = (int)GetShort(cp); cp += sizeof(short); xclass = (int)GetShort(cp); cp += sizeof(short); /* ttl = */ (void)(PRUint32)GetLong(cp); cp += INT32SZ; dlen = (int)GetShort(cp); cp += sizeof(short); session->setType(type); switch(type) { case T_A : { re_he.h_addrtype = PR_AF_INET; re_he.h_length = INADDRSZ; re_he.h_addr_list[host_cnt] = (char *)malloc(INADDRSZ); memcpy(re_he.h_addr_list[host_cnt], cp, dlen); re_he.h_addr_list[++host_cnt] = NULL; cp += dlen; len = strlen(ar_hostbuf); if (!re_he.h_name) { re_he.h_name = (char *)malloc(len+1); (void)strcpy(re_he.h_name, ar_hostbuf); } break; } case T_AAAA : { char buf[1024]; re_he.h_addrtype = PR_AF_INET6; re_he.h_length = IN6ADDRSZ; re_he.h_addr_list[host_cnt] = (char *)malloc(16); memcpy(re_he.h_addr_list[host_cnt], cp, dlen); re_he.h_addr_list[++host_cnt] = NULL; cp += dlen; len = strlen(ar_hostbuf); if (!re_he.h_name) { re_he.h_name = (char *)malloc(len+1); (void)strcpy(re_he.h_name, ar_hostbuf); } break; } case T_PTR : { PR_Lock(dnslock); n = dn_expand((const unsigned char*)buf, (const unsigned char*)eob, (const unsigned char*)cp, (char*)ar_hostbuf, sizeof(ar_hostbuf)); PR_Unlock(dnslock); if (n < 0) { cp += n; continue; } cp += n; len = strlen(ar_hostbuf)+1; /* * copy the returned hostname into the host name * or alias field if there is a known hostname * already. */ if (!re_he.h_name) { re_he.h_name = (char *)malloc(len); (void)strcpy(re_he.h_name, ar_hostbuf); } else { *alias = (char*)malloc(len); if (!*alias) return -1; (void)strcpy(*alias++, ar_hostbuf); *alias = NULL; } break; } case T_CNAME : { cp += dlen; if (alias >= &(re_he.h_aliases[MAXALIASES-1])) continue; n = strlen(ar_hostbuf)+1; *alias = (char*)malloc(n); if (!*alias) return -1; (void)strcpy(*alias++, ar_hostbuf); *alias = NULL; break; } default : { break; } } } return ans; }
int getsrv(const char *name,struct srventry **list) { unsigned char answer[2048]; int r,srvcount=0; unsigned char *pt,*emsg; u16 count,dlen; HEADER *header=(HEADER *)answer; *list=NULL; r=res_query(name,C_IN,T_SRV,answer,2048); if(r<sizeof(HEADER) || r>2048) return -1; if(header->rcode==NOERROR && (count=ntohs(header->ancount))) { int i,rc; emsg=&answer[r]; pt=&answer[sizeof(HEADER)]; /* Skip over the query */ rc=dn_skipname(pt,emsg); if(rc==-1) goto fail; pt+=rc+QFIXEDSZ; while(count-->0 && pt<emsg) { struct srventry *srv=NULL; u16 type,class; srv=realloc(*list,(srvcount+1)*sizeof(struct srventry)); if(!srv) goto fail; *list=srv; memset(&(*list)[srvcount],0,sizeof(struct srventry)); srv=&(*list)[srvcount]; srvcount++; rc=dn_skipname(pt,emsg); /* the name we just queried for */ if(rc==-1) goto fail; pt+=rc; /* Truncated message? */ if((emsg-pt)<16) goto fail; type=*pt++ << 8; type|=*pt++; /* We asked for SRV and got something else !? */ if(type!=T_SRV) goto fail; class=*pt++ << 8; class|=*pt++; /* We asked for IN and got something else !? */ if(class!=C_IN) goto fail; pt+=4; /* ttl */ dlen=*pt++ << 8; dlen|=*pt++; srv->priority=*pt++ << 8; srv->priority|=*pt++; srv->weight=*pt++ << 8; srv->weight|=*pt++; srv->port=*pt++ << 8; srv->port|=*pt++; /* Get the name. 2782 doesn't allow name compression, but dn_expand still works to pull the name out of the packet. */ rc=dn_expand(answer,emsg,pt,srv->target,MAXDNAME); if(rc==1 && srv->target[0]==0) /* "." */ goto noanswer; if(rc==-1) goto fail; pt+=rc; /* Corrupt packet? */ if(dlen!=rc+6) goto fail; #if 0 printf("count=%d\n",srvcount); printf("priority=%d\n",srv->priority); printf("weight=%d\n",srv->weight); printf("port=%d\n",srv->port); printf("target=%s\n",srv->target); #endif } /* Now we have an array of all the srv records. */ /* Order by priority */ qsort(*list,srvcount,sizeof(struct srventry),priosort); /* For each priority, move the zero-weighted items first. */ for(i=0; i<srvcount; i++) { int j; for(j=i; j<srvcount && (*list)[i].priority==(*list)[j].priority; j++) { if((*list)[j].weight==0) { /* Swap j with i */ if(j!=i) { struct srventry temp; memcpy(&temp,&(*list)[j],sizeof(struct srventry)); memcpy(&(*list)[j],&(*list)[i],sizeof(struct srventry)); memcpy(&(*list)[i],&temp,sizeof(struct srventry)); } break; } } } /* Run the RFC-2782 weighting algorithm. We don't need very high quality randomness for this, so regular libc srand/rand is sufficient. */ srand(time(NULL)*getpid()); for(i=0; i<srvcount; i++) { int j; float prio_count=0,chose; for(j=i; j<srvcount && (*list)[i].priority==(*list)[j].priority; j++) { prio_count+=(*list)[j].weight; (*list)[j].run_count=prio_count; } chose=prio_count*rand()/RAND_MAX; for(j=i; j<srvcount && (*list)[i].priority==(*list)[j].priority; j++) { if(chose<=(*list)[j].run_count) { /* Swap j with i */ if(j!=i) { struct srventry temp; memcpy(&temp,&(*list)[j],sizeof(struct srventry)); memcpy(&(*list)[j],&(*list)[i],sizeof(struct srventry)); memcpy(&(*list)[i],&temp,sizeof(struct srventry)); } break; } } } }
DNS::HostMap DNS::resolve( const std::string& service, const std::string& proto, const std::string& domain, const LogSink& logInstance ) { buffer srvbuf; bool error = false; const std::string dname = "_" + service + "._" + proto; if( !domain.empty() ) srvbuf.len = res_querydomain( dname.c_str(), const_cast<char*>( domain.c_str() ), C_IN, T_SRV, srvbuf.buf, NS_PACKETSZ ); else srvbuf.len = res_query( dname.c_str(), C_IN, T_SRV, srvbuf.buf, NS_PACKETSZ ); if( srvbuf.len < 0 ) return defaultHostMap( domain, logInstance ); HEADER* hdr = (HEADER*)srvbuf.buf; unsigned char* here = srvbuf.buf + NS_HFIXEDSZ; if( srvbuf.len < NS_HFIXEDSZ ) error = true; if( hdr->rcode >= 1 && hdr->rcode <= 5 ) error = true; if( ntohs( hdr->ancount ) == 0 ) error = true; if( ntohs( hdr->ancount ) > NS_PACKETSZ ) error = true; int cnt; for( cnt = ntohs( hdr->qdcount ); cnt > 0; --cnt ) { int strlen = dn_skipname( here, srvbuf.buf + srvbuf.len ); here += strlen + NS_QFIXEDSZ; } unsigned char* srv[NS_PACKETSZ]; int srvnum = 0; for( cnt = ntohs( hdr->ancount ); cnt > 0; --cnt ) { int strlen = dn_skipname( here, srvbuf.buf + srvbuf.len ); here += strlen; srv[srvnum++] = here; here += SRV_FIXEDSZ; here += dn_skipname( here, srvbuf.buf + srvbuf.len ); } if( error ) { return defaultHostMap( domain, logInstance ); } // (q)sort here HostMap servers; for( cnt = 0; cnt < srvnum; ++cnt ) { char srvname[NS_MAXDNAME]; srvname[0] = '\0'; if( dn_expand( srvbuf.buf, srvbuf.buf + NS_PACKETSZ, srv[cnt] + SRV_SERVER, srvname, NS_MAXDNAME ) < 0 || !(*srvname) ) continue; unsigned char* c = srv[cnt] + SRV_PORT; servers.insert( std::make_pair( (char*)srvname, ntohs( c[1] << 8 | c[0] ) ) ); } if( !servers.size() ) return defaultHostMap( domain, logInstance ); return servers; }