static void test_res_fake_aaaa_query(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; char addr[INET6_ADDRSTRLEN]; ns_msg handle; ns_rr rr; /* expanded resource record */ (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "cwrap6.org", ns_c_in, ns_t_aaaa, answer, sizeof(answer)); assert_in_range(rv, 1, 100); ns_initparse(answer, sizeof(answer), &handle); /* The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type AAAA and have the address that our * fake hosts file contains */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_aaaa); assert_non_null(inet_ntop(AF_INET6, ns_rr_rdata(rr), addr, sizeof(addr))); assert_string_equal(addr, "2a00:1450:4013:c01::63"); }
/* * smb_getfqdomainname * * In the system is in domain mode, the dns_domain property value * is returned. Otherwise, it returns the local domain obtained via * resolver. * * Returns 0 upon success. Otherwise, returns -1. */ int smb_getfqdomainname(char *buf, size_t buflen) { struct __res_state res_state; int rc; if (buf == NULL || buflen == 0) return (-1); *buf = '\0'; if (smb_config_get_secmode() == SMB_SECMODE_DOMAIN) { rc = smb_config_getstr(SMB_CI_DOMAIN_FQDN, buf, buflen); if ((rc != SMBD_SMF_OK) || (*buf == '\0')) return (-1); } else { bzero(&res_state, sizeof (struct __res_state)); if (res_ninit(&res_state)) return (-1); if (*res_state.defdname == '\0') { res_ndestroy(&res_state); return (-1); } (void) strlcpy(buf, res_state.defdname, buflen); res_ndestroy(&res_state); rc = 0; } return (rc); }
int gethostent_r(struct hostent* hptr, char* buffer, size_t buflen, struct hostent** result, int* h_errnop) { struct hostent_data* hed; struct hostent he; res_state statp; statp = __res_state(); if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) { RES_SET_H_ERRNO(statp, NETDB_INTERNAL); *h_errnop = statp->res_h_errno; return (-1); } if ((hed = __hostent_data_init()) == NULL) { RES_SET_H_ERRNO(statp, NETDB_INTERNAL); *h_errnop = statp->res_h_errno; return (-1); } if (gethostent_p(&he, hed, statp->options & RES_USE_INET6, statp) != 0) { return (-1); } if (__copy_hostent(&he, hptr, buffer, buflen) != 0) { return (-1); } *result = hptr; return (0); }
struct net_data * net_data_create(const char *conf_file) { struct net_data *net_data; net_data = memget(sizeof (struct net_data)); if (net_data == NULL) return (NULL); memset(net_data, 0, sizeof (struct net_data)); if ((net_data->irs = irs_gen_acc("", conf_file)) == NULL) { memput(net_data, sizeof (struct net_data)); return (NULL); } #ifndef DO_PTHREADS (*net_data->irs->res_set)(net_data->irs, &_res, NULL); #endif net_data->res = (*net_data->irs->res_get)(net_data->irs); if (net_data->res == NULL) { (*net_data->irs->close)(net_data->irs); memput(net_data, sizeof (struct net_data)); return (NULL); } if ((net_data->res->options & RES_INIT) == 0U && res_ninit(net_data->res) == -1) { (*net_data->irs->close)(net_data->irs); memput(net_data, sizeof (struct net_data)); return (NULL); } return (net_data); }
static void test_res_fake_a_query_case_insensitive(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; char addr[INET_ADDRSTRLEN]; ns_msg handle; ns_rr rr; /* expanded resource record */ (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "CWRAP.ORG", ns_c_in, ns_t_a, answer, sizeof(answer)); assert_in_range(rv, 1, 100); ns_initparse(answer, sizeof(answer), &handle); /* The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type A and have the address that our * fake hosts file contains. Case does not matter. */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_a); assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, sizeof(addr))); assert_string_equal(addr, "127.0.0.21"); res_nclose(&dnsstate); }
QString QHostInfo::localDomainName() { #if !defined(QT_NO_RESOLV) && defined(res_ninit) // using thread-safe version res_state state = static_cast<res_state>(malloc(sizeof(res_state))); Q_CHECK_PTR(state); memset(state, 0, sizeof(res_state)); res_ninit(state); QString domainName = QUrl::fromAce(state->defdname); if (domainName.isEmpty()) domainName = QUrl::fromAce(state->dnsrch[0]); res_nclose(state); free(state); return domainName; #elif !defined(QT_NO_RESOLV) // using thread-unsafe version #if defined(QT_NO_GETADDRINFO) // We have to call res_init to be sure that _res was initialized // So, for systems without getaddrinfo (which is thread-safe), we lock the mutex too QMutexLocker locker(::getHostByNameMutex()); #endif res_init(); QString domainName = QUrl::fromAce(local_res->defdname); if (domainName.isEmpty()) domainName = QUrl::fromAce(local_res->dnsrch[0]); return domainName; #else // nothing worked, try doing it by ourselves: QFile resolvconf; #if defined(_PATH_RESCONF) resolvconf.setFileName(QFile::decodeName(_PATH_RESCONF)); #else resolvconf.setFileName(QLatin1String("/etc/resolv.conf")); #endif if (!resolvconf.open(QIODevice::ReadOnly)) return QString(); // failure QString domainName; while (!resolvconf.atEnd()) { QByteArray line = resolvconf.readLine().trimmed(); if (line.startsWith("domain ")) return QUrl::fromAce(line.mid(sizeof "domain " - 1).trimmed()); // in case there's no "domain" line, fall back to the first "search" entry if (domainName.isEmpty() && line.startsWith("search ")) { QByteArray searchDomain = line.mid(sizeof "search " - 1).trimmed(); int pos = searchDomain.indexOf(' '); if (pos != -1) searchDomain.truncate(pos); domainName = QUrl::fromAce(searchDomain); } } // return the fallen-back-to searched domain return domainName; #endif // QT_NO_RESOLV }
static JSBool Dns_query(JSContext *cx, unsigned argc, jsval *vp) { char *domain; int32_t type; struct __res_state rs; unsigned char rsp[NS_PACKETSZ]; int rlen; ns_msg hdl; JSObject *robj, *sobj; int i; if (argc < 2) return JS_RetErrno(cx, EINVAL); if (res_ninit(&rs)) return JS_RetError(cx, "res_ninit: %s", hstrerror(h_errno)); if (!JS_ValueToInt32(cx, JS_ARGV(cx, vp)[1], &type)) return JS_RetErrno(cx, EINVAL); if (!(domain = JS_EncodeStringValue(cx, JS_ARGV(cx, vp)[0]))) return JS_RetErrno(cx, EINVAL); rlen = res_nquery(&rs, domain, ns_c_in, type, rsp, sizeof(rsp)); JS_free(cx, domain); if (rlen < 0) { JS_SET_RVAL(cx, vp, INT_TO_JSVAL(h_errno)); return JS_TRUE; } if (ns_initparse(rsp, rlen, &hdl)) return JS_RetError(cx, "ns_initparse: %s", strerror(errno)); robj = JS_NewObject(cx, NULL, NULL, NULL); if (!robj) return JS_RetErrno(cx, ENOMEM); JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(robj)); for (i = 0; i < ARRAY_SIZE(smap); i++) { sobj = JS_NewArrayObject(cx, 0, NULL); if (!sobj) { JS_SET_RVAL(cx, vp, JSVAL_NULL); return JS_RetErrno(cx, ENOMEM); } if (!JS_DefineProperty(cx, robj, smap[i].prop, OBJECT_TO_JSVAL(sobj), NULL, NULL, JSPROP_ENUMERATE)) { JS_SET_RVAL(cx, vp, JSVAL_NULL); return JS_RetErrno(cx, ENOMEM); } if (!parse_section(cx, sobj, &hdl, smap[i].sect)) { JS_SET_RVAL(cx, vp, JSVAL_NULL); return JS_FALSE; } } return JS_TRUE; }
//-------------------------------------------------------------------------------------------------- le_result_t pa_mdc_GetDNSAddresses ( uint32_t profileIndex, ///< [IN] The profile to use le_mdmDefs_IpVersion_t ipVersion, ///< [IN] IP Version char* dns1AddrStr, ///< [OUT] The primary DNS IP address in dotted format size_t dns1AddrStrSize, ///< [IN] The size in bytes of the dns1AddrStr buffer char* dns2AddrStr, ///< [OUT] The secondary DNS IP address in dotted format size_t dns2AddrStrSize ///< [IN] The size in bytes of the dns2AddrStr buffer ) { struct sockaddr_in addr; struct __res_state res; le_mdc_ConState_t sessionState; le_result_t result; result = pa_mdc_GetSessionState(profileIndex, &sessionState); if ( (result != LE_OK) || (sessionState != LE_MDC_CONNECTED) ) { return LE_FAULT; } memset(dns1AddrStr,0,dns1AddrStrSize); memset(dns2AddrStr,0,dns1AddrStrSize); res.options &= ~ (RES_INIT); if (res_ninit(&res)==-1) { return LE_FAULT; } if (res.nscount > 0) { addr = res.nsaddr_list[0]; if ( dns1AddrStrSize < INET_ADDRSTRLEN) { return LE_OVERFLOW; } // now get it back and save it if ( inet_ntop(AF_INET, &(addr.sin_addr), dns1AddrStr, INET_ADDRSTRLEN) == NULL) { return LE_FAULT; } } if (res.nscount > 1) { addr = res.nsaddr_list[1]; if ( dns2AddrStrSize < INET_ADDRSTRLEN) { return LE_OVERFLOW; } // now get it back and save it if ( inet_ntop(AF_INET, &(addr.sin_addr), dns2AddrStr, INET_ADDRSTRLEN) == NULL) { return LE_FAULT; } } return LE_OK; }
static int worker(int qfd, int afd) { { int r = res_ninit(statp); if (r != 0) { syslog(LOG_ERR, "cannot initialize resolver"); return HES_RES_INIT; } #ifndef OLD_RESOLVER statp->options |= RES_ROTATE; #endif statp->options |= RES_DEBUG; } for (;; ) { struct adns_query q; struct adns_answer a; enum helper_exit_status r = read_pipe(qfd, (unsigned char *)&q, sizeof(q), sizeof(q)); if (r != HES_CONTINUE) return r; /* some kind of exit */ if (q.qmagic != ADNS_Q_MAGIC) { syslog(LOG_ERR, "error in input from master: bad magic"); return HES_BAD_MAGIC; } a.amagic = ADNS_A_MAGIC; a.serial = q.serial; a.result = res_nquery(statp, q.name_buf, ns_c_in, q.type, a.ans, sizeof(a.ans)); a.h_errno_val = h_errno; a.len = offsetof(struct adns_answer, ans) + (a.result < 0 ? 0 : a.result); if (((q.debugging & IMPAIR_DELAY_ADNS_KEY_ANSWER) && q.type == ns_t_key) || ((q.debugging & IMPAIR_DELAY_ADNS_TXT_ANSWER) && q.type == ns_t_txt)) sleep(30); /* delay the answer */ /* write answer, possibly a bit at a time */ r = write_pipe(afd, (const unsigned char *)&a); if (r != HES_CONTINUE) return r; /* some kind of exit */ } }
PRBool Reset() { // reset no more than once per second if (PR_IntervalToSeconds(PR_IntervalNow() - mLastReset) < 1) return PR_FALSE; LOG(("calling res_ninit\n")); mLastReset = PR_IntervalNow(); return (res_ninit(&_res) == 0); }
DNS_STATUS DnsQuery_A(const char * service, unsigned short requestType, unsigned long options, void *, DNS_RECORD * results, void *) { if (results == 0) return -1; *results = 0; struct __res_state statbuf; res_ninit(&statbuf); union { HEADER hdr; unsigned char buf[PACKETSZ]; } reply; int replyLen = res_nsearch(&statbuf, service, C_IN, requestType, (unsigned char *)&reply, sizeof(reply)); if (replyLen < 1) return -1; unsigned char * replyStart = reply.buf; unsigned char * replyEnd = reply.buf + replyLen; unsigned char * cp = reply.buf + sizeof(HEADER); // ignore questions in response uint16_t i; for (i = 0; i < ntohs(reply.hdr.qdcount); i++) { char qName[MAXDNAME]; if (!GetDN(replyStart, replyEnd, cp, qName)) return -1; cp += QFIXEDSZ; } if (!ProcessDNSRecords( replyStart, replyEnd, cp, ntohs(reply.hdr.ancount), ntohs(reply.hdr.nscount), ntohs(reply.hdr.arcount), results)) { DnsRecordListFree(*results, 0); res_nclose(&statbuf); return -1; } res_nclose(&statbuf); return 0; }
static void test_res_fake_srv_query(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; ns_msg handle; ns_rr rr; /* expanded resource record */ const uint8_t *rrdata; int prio; int weight; int port; char hostname[MAXDNAME]; (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "_ldap._tcp.cwrap.org", ns_c_in, ns_t_srv, answer, sizeof(answer)); assert_in_range(rv, 1, 100); ns_initparse(answer, sizeof(answer), &handle); /* * The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type SRV and have the priority, weight, * port and hostname as in the fake hosts file */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_srv); rrdata = ns_rr_rdata(rr); NS_GET16(prio, rrdata); NS_GET16(weight, rrdata); NS_GET16(port, rrdata); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, hostname, MAXDNAME); assert_int_not_equal(rv, -1); assert_int_equal(prio, 1); assert_int_equal(weight, 5); assert_int_equal(port, 389); assert_string_equal(hostname, "ldap.cwrap.org"); }
int DeviceBindingService::GetDNS(_tds__GetDNS *tds__GetDNS, _tds__GetDNSResponse *tds__GetDNSResponse) { std::cout << __FUNCTION__ << std::endl; tds__GetDNSResponse->DNSInformation = soap_new_tt__DNSInformation(soap); struct __res_state state; res_ninit(&state); for (int i=0; i < state.nscount; i++) { tt__IPAddress* address = soap_new_tt__IPAddress(soap); address->Type = tt__IPType__IPv4; address->IPv4Address = soap_new_std__string(soap); address->IPv4Address->assign(inet_ntoa(state.nsaddr_list[i].sin_addr)); tds__GetDNSResponse->DNSInformation->DNSManual.push_back(address); } return SOAP_OK; }
DnsResolver * DnsResolver_new(void) { DnsResolver *self = (DnsResolver *) malloc(sizeof(DnsResolver)); if (NULL == self) { return NULL; } // end if memset(self, 0, sizeof(DnsResolver)); if (NETDB_SUCCESS != res_ninit(&self->resolver)) { goto cleanup; } // end if self->resolv_errno = 0; self->resolv_h_errno = NETDB_SUCCESS; return self; cleanup: DnsResolver_free(self); return NULL; } // end function : DnsResolver_init
/* * Force a reinitialization when the domain is changed. */ static void res_re_init() { static char localdomain[] = "LOCALDOMAIN"; u_long pfcode = res.pfcode, options = res.options; unsigned ndots = res.ndots; int retrans = res.retrans, retry = res.retry; char *buf; /* * This is ugly but putenv() is more portable than setenv(). */ buf = malloc((sizeof localdomain) + strlen(res.defdname) +10/*fuzz*/); sprintf(buf, "%s=%s", localdomain, res.defdname); putenv(buf); /* keeps the argument, so we won't free it */ res_ninit(&res); res.pfcode = pfcode; res.options = options; res.ndots = ndots; res.retrans = retrans; res.retry = retry; }
/* * Tries to find a matching DNS domain for the given NetBIOS domain * name by checking the first label of system's configured DNS domains. * If a match is found, it'll be returned in the passed buffer. */ static boolean_t smb_ddiscover_domain_match(char *nb_domain, char *buf, uint32_t len) { struct __res_state res_state; int i; char *entry, *p; char first_label[MAXHOSTNAMELEN]; boolean_t found; if (!nb_domain || !buf) return (B_FALSE); *buf = '\0'; bzero(&res_state, sizeof (struct __res_state)); if (res_ninit(&res_state)) return (B_FALSE); found = B_FALSE; entry = res_state.defdname; for (i = 0; entry != NULL; i++) { (void) strlcpy(first_label, entry, MAXHOSTNAMELEN); if ((p = strchr(first_label, '.')) != NULL) { *p = '\0'; if (strlen(first_label) > 15) first_label[15] = '\0'; } if (smb_strcasecmp(nb_domain, first_label, 0) == 0) { found = B_TRUE; (void) strlcpy(buf, entry, len); break; } entry = res_state.dnsrch[i]; } res_ndestroy(&res_state); return (found); }
static void test_res_fake_aaaa_query_notfound(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; ns_msg handle; (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "nosuchentry.org", ns_c_in, ns_t_aaaa, answer, sizeof(answer)); assert_in_range(rv, 1, 100); ns_initparse(answer, sizeof(answer), &handle); /* The query must finish w/o an error and have no answer */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 0); }
static gboolean restart_resolve (void) { static GTimeVal last_reload = { 0, 0 }; static GStaticMutex mutex = G_STATIC_MUTEX_INIT; GTimeVal now; gboolean ret; g_static_mutex_lock (&mutex); g_get_current_time (&now); if ((now.tv_sec - last_reload.tv_sec) > RELOAD_TIMEVAL) { last_reload.tv_sec = now.tv_sec; ret = (res_ninit (&_res) == 0); } else { ret = FALSE; } g_static_mutex_unlock (&mutex); return ret; }
int smb_get_nameservers(smb_inaddr_t *ips, int sz) { union res_sockaddr_union set[MAXNS]; int i, cnt; struct __res_state res_state; char ipstr[INET6_ADDRSTRLEN]; if (ips == NULL) return (0); bzero(&res_state, sizeof (struct __res_state)); if (res_ninit(&res_state) < 0) return (0); cnt = res_getservers(&res_state, set, MAXNS); for (i = 0; i < cnt; i++) { if (i >= sz) break; ips[i].a_family = AF_INET; bcopy(&set[i].sin.sin_addr, &ips[i].a_ipv4, NS_INADDRSZ); if (inet_ntop(AF_INET, &ips[i].a_ipv4, ipstr, INET_ADDRSTRLEN)) { syslog(LOG_DEBUG, "Found %s name server\n", ipstr); continue; } ips[i].a_family = AF_INET6; bcopy(&set[i].sin.sin_addr, &ips[i].a_ipv6, NS_IN6ADDRSZ); if (inet_ntop(AF_INET6, &ips[i].a_ipv6, ipstr, INET6_ADDRSTRLEN)) { syslog(LOG_DEBUG, "Found %s name server\n", ipstr); } } res_ndestroy(&res_state); return (i); }
NS_IMETHODIMP nsAuthGSSAPI::GetNextToken(const void *inToken, PRUint32 inTokenLen, void **outToken, PRUint32 *outTokenLen) { OM_uint32 major_status, minor_status; OM_uint32 req_flags = 0; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; gss_buffer_t in_token_ptr = GSS_C_NO_BUFFER; gss_name_t server; nsCAutoString userbuf; nsresult rv; LOG(("entering nsAuthGSSAPI::GetNextToken()\n")); if (!gssLibrary) return NS_ERROR_NOT_INITIALIZED; // If they've called us again after we're complete, reset to start afresh. if (mComplete) Reset(); if (mServiceFlags & REQ_DELEGATE) req_flags |= GSS_C_DELEG_FLAG; if (mServiceFlags & REQ_MUTUAL_AUTH) req_flags |= GSS_C_MUTUAL_FLAG; input_token.value = (void *)mServiceName.get(); input_token.length = mServiceName.Length() + 1; #if defined(HAVE_RES_NINIT) res_ninit(&_res); #endif major_status = gss_import_name_ptr(&minor_status, &input_token, &gss_c_nt_hostbased_service, &server); input_token.value = NULL; input_token.length = 0; if (GSS_ERROR(major_status)) { LogGssError(major_status, minor_status, "gss_import_name() failed"); return NS_ERROR_FAILURE; } if (inToken) { input_token.length = inTokenLen; input_token.value = (void *) inToken; in_token_ptr = &input_token; } else if (mCtx != GSS_C_NO_CONTEXT) { // If there is no input token, then we are starting a new // authentication sequence. If we have already initialized our // security context, then we're in trouble because it means that the // first sequence failed. We need to bail or else we might end up in // an infinite loop. LOG(("Cannot restart authentication sequence!")); return NS_ERROR_UNEXPECTED; } #if defined(XP_MACOSX) // Suppress Kerberos prompts to get credentials. See bug 240643. // We can only use Mac OS X specific kerb functions if we are using // the native lib KLBoolean found; bool doingMailTask = mServiceName.Find("imap@") || mServiceName.Find("pop@") || mServiceName.Find("smtp@") || mServiceName.Find("ldap@"); if (!doingMailTask && (gssNativeImp && (KLCacheHasValidTickets_ptr(NULL, kerberosVersion_V5, &found, NULL, NULL) != klNoErr || !found))) { major_status = GSS_S_FAILURE; minor_status = 0; } else #endif /* XP_MACOSX */ major_status = gss_init_sec_context_ptr(&minor_status, GSS_C_NO_CREDENTIAL, &mCtx, server, mMechOID, req_flags, GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS, in_token_ptr, nsnull, &output_token, nsnull, nsnull); if (GSS_ERROR(major_status)) { LogGssError(major_status, minor_status, "gss_init_sec_context() failed"); Reset(); rv = NS_ERROR_FAILURE; goto end; } if (major_status == GSS_S_COMPLETE) { // Mark ourselves as being complete, so that if we're called again // we know to start afresh. mComplete = PR_TRUE; } else if (major_status == GSS_S_CONTINUE_NEEDED) { // // The important thing is that we do NOT reset the // context here because it will be needed on the // next call. // } *outTokenLen = output_token.length; if (output_token.length != 0) *outToken = nsMemory::Clone(output_token.value, output_token.length); else *outToken = NULL; gss_release_buffer_ptr(&minor_status, &output_token); if (major_status == GSS_S_COMPLETE) rv = NS_SUCCESS_AUTH_FINISHED; else rv = NS_OK; end: gss_release_name_ptr(&minor_status, &server); LOG((" leaving nsAuthGSSAPI::GetNextToken [rv=%x]", rv)); return rv; }
/* * This function is called to initialize a hesiod_p. */ int hesiod_init(void **context) { struct hesiod_p *ctx; char *cp; ctx = malloc(sizeof(struct hesiod_p)); if (ctx == 0) { errno = ENOMEM; return (-1); } #ifdef ORIGINAL_ISC_CODE ctx->LHS = NULL; ctx->RHS = NULL; ctx->res = NULL; #else memset(ctx, 0, sizeof (*ctx)); #endif /* ORIGINAL_ISC_CODE */ if (parse_config_file(ctx, _PATH_HESIOD_CONF) < 0) { #ifdef DEF_RHS /* * Use compiled in defaults. */ ctx->LHS = malloc(strlen(DEF_LHS)+1); ctx->RHS = malloc(strlen(DEF_RHS)+1); if (ctx->LHS == 0 || ctx->RHS == 0) { errno = ENOMEM; goto cleanup; } #ifdef HAVE_STRLCPY strlcpy(ctx->LHS, DEF_LHS, strlen(DEF_LHS) + 1); strlcpy(ctx->RHS, DEF_RHS, strlen(DEF_RHS) + 1); #else strcpy(ctx->LHS, DEF_LHS); strcpy(ctx->RHS, DEF_RHS); #endif #else goto cleanup; #endif } /* * The default RHS can be overridden by an environment * variable. */ if ((cp = getenv("HES_DOMAIN")) != NULL) { size_t RHSlen = strlen(cp) + 2; if (ctx->RHS) free(ctx->RHS); ctx->RHS = malloc(RHSlen); if (!ctx->RHS) { errno = ENOMEM; goto cleanup; } if (cp[0] == '.') { #ifdef HAVE_STRLCPY strlcpy(ctx->RHS, cp, RHSlen); #else strcpy(ctx->RHS, cp); #endif } else { #ifdef HAVE_STRLCPY strlcpy(ctx->RHS, ".", RHSlen); #else strcpy(ctx->RHS, "."); #endif #ifdef HAVE_STRLCAT strlcat(ctx->RHS, cp, RHSlen); #else strcat(ctx->RHS, cp); #endif } } /* * If there is no default hesiod realm set, we return an * error. */ if (!ctx->RHS) { errno = ENOEXEC; goto cleanup; } #if 0 if (res_ninit(ctx->res) < 0) goto cleanup; #endif *context = ctx; return (0); cleanup: hesiod_end(ctx); return (-1); }
static jdns_dnsparams_t *dnsparams_get_unixsys() { int n; jdns_dnsparams_t *params; #ifdef JDNS_MODERN_RES_API struct __res_state res; memset(&res, 0, sizeof(struct __res_state)); n = res_ninit(&res); #define RESVAR res #else n = my_res_init(); #define RESVAR _res #endif params = jdns_dnsparams_new(); // error initializing? if(n == -1) return params; #ifdef USE_INDEP_EXT for(n = 0; n < MAXNS && n < RESVAR.nscount; ++n) { struct sockaddr_in *sa = (struct sockaddr_in*)&(_res_ext.nsaddr_list[n]); jdns_address_t *addr = jdns_address_new(); if (sa->sin_family = AF_INET6) { struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; jdns_address_set_ipv6(addr, sa6->sin6_addr.s6_addr); } else { jdns_address_set_ipv4(addr, ntohl(sa->sin_addr.s_addr)); } jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT); jdns_address_delete(addr); } #else // nameservers - ipv6 #ifdef __GLIBC__ for(n = 0; n < MAXNS; ++n) #else for(n = 0; n < MAXNS && n < RESVAR._u._ext.nscount; ++n) #endif { jdns_address_t *addr; struct sockaddr_in6 *sa6; #ifdef USE_EXTEXT // seems _ext.ext can be null in some cases... if(RESVAR._u._ext.ext == NULL) break; sa6 = ((struct sockaddr_in6 *)RESVAR._u._ext.ext) + n; #else sa6 = RESVAR._u._ext.nsaddrs[n]; #endif if(sa6 == NULL) continue; addr = jdns_address_new(); jdns_address_set_ipv6(addr, sa6->sin6_addr.s6_addr); jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT); jdns_address_delete(addr); } // nameservers - ipv4 #ifdef __GLIBC__ int ns4count = RESVAR.nscount - RESVAR._u._ext.nscount6; for(n = 0; n < MAXNS && n < ns4count; ++n) #else for(n = 0; n < MAXNS && n < RESVAR.nscount; ++n) #endif { jdns_address_t *addr = jdns_address_new(); jdns_address_set_ipv4(addr, ntohl(RESVAR.nsaddr_list[n].sin_addr.s_addr)); jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT); jdns_address_delete(addr); } #endif // domain name if(strlen(RESVAR.defdname) > 0) { jdns_string_t *str; jdns_string_t *p; str = jdns_string_new(); jdns_string_set_cstr(str, RESVAR.defdname); p = string_tolower(str); jdns_string_delete(str); str = p; jdns_dnsparams_append_domain(params, str); jdns_string_delete(str); } // search list #ifdef MAXDFLSRCH for(n = 0; n < MAXDFLSRCH && RESVAR.dnsrch[n]; ++n) { if(strlen(RESVAR.dnsrch[n]) > 0) { jdns_string_t *str; jdns_string_t *p; str = jdns_string_new(); jdns_string_set_cstr(str, RESVAR.dnsrch[n]); p = string_tolower(str); jdns_string_delete(str); str = p; // don't add dups if(!dnsparams_have_domain(params, str)) jdns_dnsparams_append_domain(params, str); jdns_string_delete(str); } } #endif return params; }
static _res_thread* _res_thread_get(void) { _res_thread* rt; pthread_once( &_res_once, _res_init_key ); rt = pthread_getspecific( _res_key ); if (rt != NULL) { /* We already have one thread-specific DNS state object. * Check the serial value for any changes to net.* properties */ D("%s: Called for tid=%d rt=%p rt->pi=%p rt->serial=%d", __FUNCTION__, gettid(), rt, rt->_pi, rt->_serial); if (rt->_pi == NULL) { /* The property wasn't created when _res_thread_get() was * called the last time. This should only happen very * early during the boot sequence. First, let's try to see if it * is here now. */ rt->_pi = (struct prop_info*) __system_property_find("net.change"); if (rt->_pi == NULL) { /* Still nothing, return current state */ D("%s: exiting for tid=%d rt=%d since system property not found", __FUNCTION__, gettid(), rt); return rt; } } if (rt->_serial == rt->_pi->serial) { /* Nothing changed, so return the current state */ D("%s: tid=%d rt=%p nothing changed, returning", __FUNCTION__, gettid(), rt); return rt; } /* Update the recorded serial number, and go reset the state */ rt->_serial = rt->_pi->serial; goto RESET_STATE; } /* It is the first time this function is called in this thread, * we need to create a new thread-specific DNS resolver state. */ rt = _res_thread_alloc(); if (rt == NULL) { return NULL; } pthread_setspecific( _res_key, rt ); D("%s: tid=%d Created new DNS state rt=%p", __FUNCTION__, gettid(), rt); RESET_STATE: /* Reset the state, note that res_ninit() can now properly reset * an existing state without leaking memory. */ D("%s: tid=%d, rt=%p, resetting DNS state (options RES_INIT=%d)", __FUNCTION__, gettid(), rt, (rt->_nres->options & RES_INIT) != 0); if ( res_ninit( rt->_nres ) < 0 ) { /* This should not happen */ D("%s: tid=%d rt=%p, woot, res_ninit() returned < 0", __FUNCTION__, gettid(), rt); _res_thread_free(rt); pthread_setspecific( _res_key, NULL ); return NULL; } return rt; }
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 main(int argc, char **argv) { struct hostent_test_data td, td_addr, td_snap; char *snapshot_file, *hostlist_file; res_state statp; int rv; int c; if (argc < 2) usage(); snapshot_file = NULL; hostlist_file = NULL; while ((c = getopt(argc, argv, "nad2iod46mAcMs:f:")) != -1) switch (c) { case '4': af_type = AF_INET; break; case '6': af_type = AF_INET6; break; case 'M': af_type = AF_INET6; use_ipv6_mapping = 1; ipnode_flags |= AI_V4MAPPED_CFG; break; case 'm': af_type = AF_INET6; use_ipv6_mapping = 1; ipnode_flags |= AI_V4MAPPED; break; case 'c': ipnode_flags |= AI_ADDRCONFIG; break; case 'A': ipnode_flags |= AI_ALL; break; case 'o': use_ipnode_functions = 1; break; case 'd': debug = 1; break; case 'n': method = TEST_GETHOSTBYNAME2; break; case 'a': method = TEST_GETHOSTBYADDR; break; case '2': method = TEST_GETHOSTBYNAME2_GETADDRINFO; break; case 'i': method = TEST_GETHOSTBYADDR_GETNAMEINFO; break; case 's': snapshot_file = strdup(optarg); break; case 'f': hostlist_file = strdup(optarg); break; default: usage(); } if (use_ipnode_functions == 0) { statp = __res_state(); if ((statp == NULL) || ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1)) { if (debug) printf("error: can't init res_state\n"); free(snapshot_file); free(hostlist_file); return (-1); } if (use_ipv6_mapping == 0) statp->options &= ~RES_USE_INET6; else statp->options |= RES_USE_INET6; } TEST_DATA_INIT(hostent, &td, clone_hostent, free_hostent); TEST_DATA_INIT(hostent, &td_addr, clone_hostent, free_hostent); TEST_DATA_INIT(hostent, &td_snap, clone_hostent, free_hostent); if (hostlist_file == NULL) usage(); if (access(hostlist_file, R_OK) != 0) { if (debug) printf("can't access the hostlist file %s\n", hostlist_file); usage(); } if (debug) printf("building host lists from %s\n", hostlist_file); rv = TEST_SNAPSHOT_FILE_READ(hostent, hostlist_file, &td, hostent_read_hostlist_func); if (rv != 0) goto fin; if (snapshot_file != NULL) { if (access(snapshot_file, W_OK | R_OK) != 0) { if (errno == ENOENT) { if (method != TEST_GETHOSTBYADDR) method = TEST_BUILD_SNAPSHOT; else method = TEST_BUILD_ADDR_SNAPSHOT; } else { if (debug) printf("can't access the snapshot file %s\n", snapshot_file); rv = -1; goto fin; } } else { rv = TEST_SNAPSHOT_FILE_READ(hostent, snapshot_file, &td_snap, hostent_read_snapshot_func); if (rv != 0) { if (debug) printf("error reading snapshot file\n"); goto fin; } } } switch (method) { case TEST_GETHOSTBYNAME2: if (snapshot_file != NULL) rv = DO_2PASS_TEST(hostent, &td, &td_snap, compare_hostent, NULL); break; case TEST_GETHOSTBYADDR: rv = DO_1PASS_TEST(hostent, &td, hostent_test_gethostbyaddr, (void *)&td_addr); if (snapshot_file != NULL) rv = DO_2PASS_TEST(hostent, &td_addr, &td_snap, compare_hostent, NULL); break; case TEST_GETHOSTBYNAME2_GETADDRINFO: rv = DO_1PASS_TEST(hostent, &td, hostent_test_getaddrinfo_eq, NULL); break; case TEST_GETHOSTBYADDR_GETNAMEINFO: rv = DO_1PASS_TEST(hostent, &td, hostent_test_getnameinfo_eq, NULL); break; case TEST_BUILD_SNAPSHOT: if (snapshot_file != NULL) { rv = TEST_SNAPSHOT_FILE_WRITE(hostent, snapshot_file, &td, sdump_hostent); } break; case TEST_BUILD_ADDR_SNAPSHOT: if (snapshot_file != NULL) { rv = DO_1PASS_TEST(hostent, &td, hostent_test_gethostbyaddr, (void *)&td_addr); rv = TEST_SNAPSHOT_FILE_WRITE(hostent, snapshot_file, &td_addr, sdump_hostent); } break; default: rv = 0; break; }; fin: TEST_DATA_DESTROY(hostent, &td_snap); TEST_DATA_DESTROY(hostent, &td_addr); TEST_DATA_DESTROY(hostent, &td); free(hostlist_file); free(snapshot_file); return (rv); }
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; }
// Perform a DNS query and parse the results. Follows CNAME records. void SipSrvLookup::res_query_and_parse(const char* in_name, int type, res_response* in_response, const char*& out_name, res_response*& out_response ) { OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipSrvLookup::res_query_and_parse in_name = '%s', " "type = %d (%s)", in_name,type, type == T_CNAME ? "CNAME" : type == T_SRV ? "SRV" : type == T_A ? "A" : type == T_NAPTR ? "NAPTR" : "unknown"); // The number of CNAMEs we have followed. int cname_count = 0; // The response currently being examined. res_response* response = in_response; // The name currently being examined. const char* name = in_name; // TRUE if 'response' was a lookup for 'name' and 'type'. UtlBoolean response_for_this_name = FALSE; // Buffer into which to read DNS replies. char answer[DNS_RESPONSE_SIZE]; union u_rdata* p; // Loop until we find a reason to exit. Each turn around the loop does // another DNS lookup. while (1) { // While response != NULL and there is a CNAME record for name // in response. while (response != NULL && (p = look_for(response, name, T_CNAME)) != NULL) { cname_count++; if (cname_count > SipSrvLookup::getOption(SipSrvLookup::OptionCodeCNAMELimit)) { break; } // If necessary, free the current 'name'. if (name != in_name) { free((void*) name); } // Copy the canonical name from the CNAME record into 'name', so // we can still use it after freeing 'response'. name = strdup(p->string); // Remember that we are now looking for a name that was not the one // that we searched for to produce this response. Hence, if we don't // find any RRs for it, that is not authoritative and we have to do // another DNS query. response_for_this_name = FALSE; // Go back and check whether the result name of the CNAME is listed // in this response. } // This response does not contain a CNAME for 'name'. So it is either // a final response that gives us the RRs we are looking for, or // we need to do a lookup on 'name'. // Check whether the response was for this name, or contains records // of the type we are looking for. If either, then any records we // are looking for are in this response, so we can return. if (response_for_this_name || (response != NULL && look_for(response, name, type) != NULL)) { break; } // We must do another lookup. // Start by freeing 'response' if we need to. if (response != in_response) { res_free(response); } response = NULL; // Now, 'response' will be from a query for 'name'. response_for_this_name = TRUE; // Debugging print. if (SipSrvLookup::getOption(SipSrvLookup::OptionCodePrintAnswers)) { printf("res_nquery(\"%s\", class = %d, type = %d)\n", name, C_IN, type); } // Initialize the res state struct and set the timeout to // 3 secs and retries to 2 struct __res_state res; res_ninit(&res); res.retrans = mTimeout; res.retry = mRetries; if (!mNameserverIP.isNull()) { res.nscount = 1; inet_aton(mNameserverIP.data(), &res.nsaddr_list[0].sin_addr); if (mNameserverPort > 1) { res.nsaddr_list[0].sin_port = htons(mNameserverPort); } } // Use res_nquery, not res_search or res_query, so defaulting rules are not // applied to the domain, and so that the query is thread-safe. int r = res_nquery(&res, name, C_IN, type, (unsigned char*) answer, sizeof (answer)); // Done with res state struct, so cleanup. // Must close once and only once per res_ninit, after res_nquery. res_nclose(&res); if (r == -1) { // res_query failed, return. OsSysLog::add(FAC_SIP, PRI_WARNING, "DNS query for name '%s', " "type = %d (%s): returned error", name, type, type == T_CNAME ? "CNAME" : type == T_SRV ? "SRV" : type == T_A ? "A" : type == T_NAPTR ? "NAPTR" : "unknown"); break; } response = res_parse((char*) &answer); if (response == NULL) { // res_parse failed, return. OsSysLog::add(FAC_SIP, PRI_WARNING, "DNS query for name '%s', " "type = %d (%s): response could not be parsed", name, type, type == T_CNAME ? "CNAME" : type == T_SRV ? "SRV" : type == T_A ? "A" : type == T_NAPTR ? "NAPTR" : "unknown"); break; } // If requested for testing purposes, sort the query and print it. // Sort first, so we see how sorting came out. if (SipSrvLookup::getOption(SipSrvLookup::OptionCodeSortAnswers)) { sort_answers(response); } if (SipSrvLookup::getOption(SipSrvLookup::OptionCodePrintAnswers)) { res_print(response); } // Now that we have a fresh DNS query to analyze, go back and check it // for a CNAME for 'name' and then for records of the requested type. } // Final processing: Copy the working name and response to the output // variables. out_name = name; out_response = response; OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipSrvLookup::res_query_and_parse out_name = '%s', out_response = %p", out_name, out_response); }
int main(int argc, char **argv) { short port = htons(NAMESERVER_PORT); short lport; /* Wierd stuff for SPARC alignment, hurts nothing else. */ union { HEADER header_; u_char packet_[PACKETSZ]; } packet_; #define header (packet_.header_) #define packet (packet_.packet_) union { HEADER u; u_char b[NS_MAXMSG]; } answer; int n; char doping[90]; char pingstr[50]; char *afile; char *addrc, *addrend, *addrbegin; time_t exectime; struct timeval tv1, tv2, start_time, end_time, query_time; char *srv; int anyflag = 0; int sticky = 0; int tmp; int qtypeSet; ns_type xfr = ns_t_invalid; int bytes_out, bytes_in; char cmd[512]; char domain[MAXDNAME]; char msg[120], **vtmp; char *args[DIG_MAXARGS]; char **ax; int once = 1, dofile = 0; /* batch -vs- interactive control */ char fileq[384]; int fp; int wait=0, delay; int envset=0, envsave=0; struct __res_state res_x, res_t; int r; struct in6_addr in6; ns_tsig_key key; char *keyfile = NULL, *keyname = NULL; const char *pingfmt = NULL; UNUSED(argc); res_ninit(&res); res.pfcode = PRF_DEF; qtypeSet = 0; memset(domain, 0, sizeof domain); gethostname(myhostname, (sizeof myhostname)); #ifdef HAVE_SA_LEN myaddress.sin_len = sizeof(struct sockaddr_in); #endif myaddress.sin_family = AF_INET; myaddress.sin_addr.s_addr = INADDR_ANY; myaddress.sin_port = 0; /*INPORT_ANY*/; #ifdef HAVE_SA_LEN myaddress6.sin6_len = sizeof(struct sockaddr_in6); #endif myaddress6.sin6_family = AF_INET6; myaddress6.sin6_addr = in6addr_any; myaddress6.sin6_port = 0; /*INPORT_ANY*/; res_x = res; /* * If LOCALDEF in environment, should point to file * containing local favourite defaults. Also look for file * DiG.env (i.e. SAVEENV) in local directory. */ if ((((afile = (char *) getenv("LOCALDEF")) != (char *) NULL) && ((fp = open(afile, O_RDONLY)) > 0)) || ((fp = open(SAVEENV, O_RDONLY)) > 0)) { read(fp, (char *)&res_x, (sizeof res_x)); close(fp); res = res_x; } /* * Check for batch-mode DiG; also pre-scan for 'help'. */ vtmp = argv; ax = args; while (*vtmp != NULL) { if (strcmp(*vtmp, "-h") == 0 || strcmp(*vtmp, "-help") == 0 || strcmp(*vtmp, "-usage") == 0 || strcmp(*vtmp, "help") == 0) { Usage(); exit(0); } if (strcmp(*vtmp, "-f") == 0) { dofile++; once=0; if ((qfp = fopen(*++vtmp, "r")) == NULL) { fflush(stdout); perror("file open"); fflush(stderr); exit(10); } } else { if (ax - args == DIG_MAXARGS) { fprintf(stderr, "dig: too many arguments\n"); exit(10); } *ax++ = *vtmp; } vtmp++; } gettimeofday(&tv1, NULL); /* * Main section: once if cmd-line query * while !EOF if batch mode */ *fileq = '\0'; while ((dofile && fgets(fileq, sizeof fileq, qfp) != NULL) || (!dofile && once--)) { if (*fileq == '\n' || *fileq == '#' || *fileq==';') { printf("%s", fileq); /* echo but otherwise ignore */ continue; /* blank lines and comments */ } /* * "Sticky" requests that before current parsing args * return to current "working" environment (X******). */ if (sticky) { printf(";; (using sticky settings)\n"); res = res_x; } /* * Concat cmd-line and file args. */ stackarg(fileq, ax); /* defaults */ queryType = ns_t_ns; queryClass = ns_c_in; xfr = ns_t_invalid; *pingstr = 0; srv = NULL; sprintf(cmd, "\n; <<>> DiG %s (libbind %d) <<>> ", VSTRING, __RES); argv = args; /* argc = ax - args; */ /* * More cmd-line options than anyone should ever have to * deal with .... */ while (*(++argv) != NULL && **argv != '\0') { if (strlen(cmd) + strlen(*argv) + 2 > sizeof (cmd)) { fprintf(stderr, "Argument too large for input buffer\n"); exit(1); } strcat(cmd, *argv); strcat(cmd, " "); if (**argv == '@') { srv = (*argv+1); continue; } if (**argv == '%') continue; if (**argv == '+') { setopt(*argv+1); continue; } if (**argv == '=') { ixfr_serial = strtoul(*argv+1, NULL, 0); continue; } if (strncmp(*argv, "-nost", 5) == 0) { sticky = 0; continue; } else if (strncmp(*argv, "-st", 3) == 0) { sticky++; continue; } else if (strncmp(*argv, "-envsa", 6) == 0) { envsave++; continue; } else if (strncmp(*argv, "-envse", 6) == 0) { envset++; continue; } if (**argv == '-') { switch (argv[0][1]) { case 'T': if (*++argv == NULL) printf("; no arg for -T?\n"); else wait = atoi(*argv); break; case 'c': if(*++argv == NULL) printf("; no arg for -c?\n"); else if ((tmp = atoi(*argv)) || *argv[0] == '0') { queryClass = tmp; } else if ((tmp = StringToClass(*argv, 0, NULL) ) != 0) { queryClass = tmp; } else { printf( "; invalid class specified\n" ); } break; case 't': if (*++argv == NULL) printf("; no arg for -t?\n"); else if ((tmp = atoi(*argv)) || *argv[0]=='0') { if (ns_t_xfr_p(tmp)) { xfr = tmp; } else { queryType = tmp; qtypeSet++; } } else if ((tmp = StringToType(*argv, 0, NULL) ) != 0) { if (ns_t_xfr_p(tmp)) { xfr = tmp; } else { queryType = tmp; qtypeSet++; } } else { printf( "; invalid type specified\n" ); } break; case 'x': if (!qtypeSet) { queryType = T_ANY; qtypeSet++; } if ((addrc = *++argv) == NULL) { printf("; no arg for -x?\n"); break; } r = inet_pton(AF_INET6, addrc, &in6); if (r > 0) { reverse6(domain, &in6); break; } addrend = addrc + strlen(addrc); if (*addrend == '.') *addrend = '\0'; *domain = '\0'; while ((addrbegin = strrchr(addrc,'.'))) { strcat(domain, addrbegin+1); strcat(domain, "."); *addrbegin = '\0'; } strcat(domain, addrc); strcat(domain, ".in-addr.arpa."); break; case 'p': if (argv[0][2] != '\0') port = htons(atoi(argv[0]+2)); else if (*++argv == NULL) printf("; no arg for -p?\n"); else port = htons(atoi(*argv)); break; case 'P': if (argv[0][2] != '\0') { strcpy(pingstr, argv[0]+2); pingfmt = "%s %s 56 3 | %s -3"; } else { strcpy(pingstr, DIG_PING); pingfmt = DIG_PINGFMT; } break; case 'n': if (argv[0][2] != '\0') res.ndots = atoi(argv[0]+2); else if (*++argv == NULL) printf("; no arg for -n?\n"); else res.ndots = atoi(*argv); break; case 'b': { char *a, *p; if (argv[0][2] != '\0') a = argv[0]+2; else if (*++argv == NULL) { printf("; no arg for -b?\n"); break; } else a = *argv; if ((p = strchr(a, ':')) != NULL) { *p++ = '\0'; lport = htons(atoi(p)); } else lport = htons(0); if (inet_pton(AF_INET6, a, &myaddress6.sin6_addr) == 1) { myaddress6.sin6_port = lport; } else if (!inet_aton(a, &myaddress.sin_addr)) { fprintf(stderr, ";; bad -b addr\n"); exit(1); } else myaddress.sin_port = lport; } break; case 'k': /* -k keydir:keyname */ if (argv[0][2] != '\0') keyfile = argv[0]+2; else if (*++argv == NULL) { printf("; no arg for -k?\n"); break; } else keyfile = *argv; keyname = strchr(keyfile, ':'); if (keyname == NULL) { fprintf(stderr, "key option argument should be keydir:keyname\n"); exit(1); } *keyname++='\0'; break; } /* switch - */ continue; } /* if '-' */ if ((tmp = StringToType(*argv, -1, NULL)) != -1) { if ((T_ANY == tmp) && anyflag++) { queryClass = C_ANY; continue; } if (ns_t_xfr_p(tmp) && (tmp == ns_t_axfr || (res.options & RES_USEVC) != 0) ) { res.pfcode = PRF_ZONE; xfr = (ns_type)tmp; } else { queryType = tmp; qtypeSet++; } } else if ((tmp = StringToClass(*argv, -1, NULL)) != -1) { queryClass = tmp; } else { memset(domain, 0, sizeof domain); sprintf(domain,"%s",*argv); } } /* while argv remains */ /* process key options */ if (keyfile) { #ifdef PARSE_KEYFILE int i, n1; char buf[BUFSIZ], *p; FILE *fp = NULL; int file_major, file_minor, alg; fp = fopen(keyfile, "r"); if (fp == NULL) { perror(keyfile); exit(1); } /* Now read the header info from the file. */ i = fread(buf, 1, BUFSIZ, fp); if (i < 5) { fclose(fp); exit(1); } fclose(fp); p = buf; n=strlen(p); /* get length of strings */ n1=strlen("Private-key-format: v"); if (n1 > n || strncmp(buf, "Private-key-format: v", n1)) { fprintf(stderr, "Invalid key file format\n"); exit(1); /* not a match */ } p+=n1; /* advance pointer */ sscanf((char *)p, "%d.%d", &file_major, &file_minor); /* should do some error checking with these someday */ while (*p++!='\n'); /* skip to end of line */ n=strlen(p); /* get length of strings */ n1=strlen("Algorithm: "); if (n1 > n || strncmp(p, "Algorithm: ", n1)) { fprintf(stderr, "Invalid key file format\n"); exit(1); /* not a match */ } p+=n1; /* advance pointer */ if (sscanf((char *)p, "%d", &alg)!=1) { fprintf(stderr, "Invalid key file format\n"); exit(1); } while (*p++!='\n'); /* skip to end of line */ n=strlen(p); /* get length of strings */ n1=strlen("Key: "); if (n1 > n || strncmp(p, "Key: ", n1)) { fprintf(stderr, "Invalid key file format\n"); exit(1); /* not a match */ } p+=n1; /* advance pointer */ pp=p; while (*pp++!='\n'); /* skip to end of line, * terminate it */ *--pp='\0'; key.data=malloc(1024*sizeof(char)); key.len=b64_pton(p, key.data, 1024); strcpy(key.name, keyname); strcpy(key.alg, "HMAC-MD5.SIG-ALG.REG.INT"); #else /* use the dst* routines to parse the key files * * This requires that both the .key and the .private * files exist in your cwd, so the keyfile parmeter * here is assumed to be a path in which the * K*.{key,private} files exist. */ DST_KEY *dst_key; char cwd[PATH_MAX+1]; if (getcwd(cwd, PATH_MAX)==NULL) { perror("unable to get current directory"); exit(1); } if (chdir(keyfile)<0) { fprintf(stderr, "unable to chdir to %s: %s\n", keyfile, strerror(errno)); exit(1); } dst_init(); dst_key = dst_read_key(keyname, 0 /* not used for priv keys */, KEY_HMAC_MD5, DST_PRIVATE); if (!dst_key) { fprintf(stderr, "dst_read_key: error reading key\n"); exit(1); } key.data=malloc(1024*sizeof(char)); dst_key_to_buffer(dst_key, key.data, 1024); key.len=dst_key->dk_key_size; strcpy(key.name, keyname); strcpy(key.alg, "HMAC-MD5.SIG-ALG.REG.INT"); if (chdir(cwd)<0) { fprintf(stderr, "unable to chdir to %s: %s\n", cwd, strerror(errno)); exit(1); } #endif } if (res.pfcode & 0x80000) printf("; pfcode: %08lx, options: %08lx\n", (unsigned long)res.pfcode, (unsigned long)res.options); /* * Current env. (after this parse) is to become the * new "working" environmnet. Used in conj. with sticky. */ if (envset) { res_x = res; envset = 0; } /* * Current env. (after this parse) is to become the * new default saved environmnet. Save in user specified * file if exists else is SAVEENV (== "DiG.env"). */ if (envsave) { afile = (char *) getenv("LOCALDEF"); if ((afile && ((fp = open(afile, O_WRONLY|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE)) > 0)) || ((fp = open(SAVEENV, O_WRONLY|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE)) > 0)) { write(fp, (char *)&res, (sizeof res)); close(fp); } envsave = 0; } if (res.pfcode & RES_PRF_CMD) printf("%s\n", cmd); anyflag = 0; /* * Find address of server to query. If not dot-notation, then * try to resolve domain-name (if so, save and turn off print * options, this domain-query is not the one we want. Restore * user options when done. * Things get a bit wierd since we need to use resolver to be * able to "put the resolver to work". */ if (srv != NULL) { int nscount = 0; union res_sockaddr_union u[MAXNS]; struct addrinfo *answer = NULL; struct addrinfo *cur = NULL; struct addrinfo hint; memset(u, 0, sizeof(u)); res_t = res; res_ninit(&res); res.pfcode = 0; res.options = RES_DEFAULT; memset(&hint, 0, sizeof(hint)); hint.ai_socktype = SOCK_DGRAM; if (!getaddrinfo(srv, NULL, &hint, &answer)) { res = res_t; cur = answer; for (cur = answer; cur != NULL; cur = cur->ai_next) { if (nscount == MAXNS) break; switch (cur->ai_addr->sa_family) { case AF_INET6: u[nscount].sin6 = *(struct sockaddr_in6*)cur->ai_addr; u[nscount++].sin6.sin6_port = port; break; case AF_INET: u[nscount].sin = *(struct sockaddr_in*)cur->ai_addr; u[nscount++].sin.sin_port = port; break; } } if (nscount != 0) res_setservers(&res, u, nscount); freeaddrinfo(answer); } else { res = res_t; fflush(stdout); fprintf(stderr, "; Bad server: %s -- using default server and timer opts\n", srv); fflush(stderr); srv = NULL; } printf("; (%d server%s found)\n", res.nscount, (res.nscount==1)?"":"s"); res.id += res.retry; } if (ns_t_xfr_p(xfr)) { int i; int nscount; union res_sockaddr_union u[MAXNS]; nscount = res_getservers(&res, u, MAXNS); for (i = 0; i < nscount; i++) { int x; if (keyfile) x = printZone(xfr, domain, &u[i].sin, &key); else x = printZone(xfr, domain, &u[i].sin, NULL); if (res.pfcode & RES_PRF_STATS) { exectime = time(NULL); printf(";; FROM: %s to SERVER: %s\n", myhostname, p_sockun(u[i], ubuf, sizeof(ubuf))); printf(";; WHEN: %s", ctime(&exectime)); } if (!x) break; /* success */ } fflush(stdout); continue; } if (*domain && !qtypeSet) { queryType = T_A; qtypeSet++; } bytes_out = n = res_nmkquery(&res, QUERY, domain, queryClass, queryType, NULL, 0, NULL, packet, sizeof packet); if (n < 0) { fflush(stderr); printf(";; res_nmkquery: buffer too small\n\n"); fflush(stdout); continue; } if (queryType == T_IXFR) { HEADER *hp = (HEADER *) packet; u_char *cpp = packet + bytes_out; hp->nscount = htons(1+ntohs(hp->nscount)); n = dn_comp(domain, cpp, (sizeof packet) - (cpp - packet), NULL, NULL); cpp += n; PUTSHORT(T_SOA, cpp); /* type */ PUTSHORT(C_IN, cpp); /* class */ PUTLONG(0, cpp); /* ttl */ PUTSHORT(22, cpp); /* dlen */ *cpp++ = 0; /* mname */ *cpp++ = 0; /* rname */ PUTLONG(ixfr_serial, cpp); PUTLONG(0xDEAD, cpp); /* Refresh */ PUTLONG(0xBEEF, cpp); /* Retry */ PUTLONG(0xABCD, cpp); /* Expire */ PUTLONG(0x1776, cpp); /* Min TTL */ bytes_out = n = cpp - packet; }; #if defined(RES_USE_EDNS0) && defined(RES_USE_DNSSEC) if (n > 0 && (res.options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0) bytes_out = n = res_nopt(&res, n, packet, sizeof(packet), 4096); #endif eecode = 0; if (res.pfcode & RES_PRF_HEAD1) fp_resstat(&res, stdout); (void) gettimeofday(&start_time, NULL); if (keyfile) n = res_nsendsigned(&res, packet, n, &key, answer.b, sizeof(answer.b)); else n = res_nsend(&res, packet, n, answer.b, sizeof(answer.b)); if ((bytes_in = n) < 0) { fflush(stdout); n = 0 - n; if (keyfile) strcpy(msg, ";; res_nsendsigned"); else strcpy(msg, ";; res_nsend"); perror(msg); fflush(stderr); if (!dofile) { if (eecode) exit(eecode); else exit(9); } } (void) gettimeofday(&end_time, NULL); if (res.pfcode & RES_PRF_STATS) { union res_sockaddr_union u[MAXNS]; (void) res_getservers(&res, u, MAXNS); query_time = difftv(start_time, end_time); printf(";; Total query time: "); prnttime(query_time); putchar('\n'); exectime = time(NULL); printf(";; FROM: %s to SERVER: %s\n", myhostname, p_sockun(u[RES_GETLAST(res)], ubuf, sizeof(ubuf))); printf(";; WHEN: %s", ctime(&exectime)); printf(";; MSG SIZE sent: %d rcvd: %d\n", bytes_out, bytes_in); } fflush(stdout); /* * Argh ... not particularly elegant. Should put in *real* ping code. * Would necessitate root priviledges for icmp port though! */ if (*pingstr && srv != NULL) { sprintf(doping, pingfmt, pingstr, srv, DIG_TAIL); system(doping); } putchar('\n'); /* * Fairly crude method and low overhead method of keeping two * batches started at different sites somewhat synchronized. */ gettimeofday(&tv2, NULL); delay = (int)(tv2.tv_sec - tv1.tv_sec); if (delay < wait) { sleep(wait - delay); } tv1 = tv2; } return (eecode); }
static void test_res_fake_cname_query(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; ns_msg handle; ns_rr rr; /* expanded resource record */ const uint8_t *rrdata; char cname[MAXDNAME]; char addr[INET_ADDRSTRLEN]; (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "rwrap.org", ns_c_in, ns_t_cname, answer, sizeof(answer)); assert_in_range(rv, 1, 256); ns_initparse(answer, 256, &handle); ns_initparse(answer, sizeof(answer), &handle); /* * The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type CNAME and have the cname as in the * fake hosts file */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_cname); rrdata = ns_rr_rdata(rr); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, cname, MAXDNAME); assert_int_not_equal(rv, -1); assert_string_equal(cname, "web.cwrap.org"); /* The CNAME points to an A record that's present in the additional * section */ assert_int_equal(ns_msg_count(handle, ns_s_ar), 2); assert_int_equal(ns_parserr(&handle, ns_s_ar, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_cname); assert_string_equal(ns_rr_name(rr), "web.cwrap.org"); rrdata = ns_rr_rdata(rr); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, cname, MAXDNAME); assert_int_not_equal(rv, -1); assert_string_equal(cname, "www.cwrap.org"); assert_int_equal(ns_parserr(&handle, ns_s_ar, 1, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_a); assert_string_equal(ns_rr_name(rr), "www.cwrap.org"); assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, sizeof(addr))); assert_string_equal(addr, "127.0.0.22"); }
static void test_res_fake_a_via_cname(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; ns_msg handle; ns_rr rr; /* expanded resource record */ const uint8_t *rrdata; char cname[MAXDNAME]; char addr[INET_ADDRSTRLEN]; (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); /* Query for A record, but the key is a CNAME. The expected result is * that the whole chain of CNAMEs will be included in the answer section * along with the resulting A */ rv = res_nquery(&dnsstate, "rwrap.org", ns_c_in, ns_t_a, answer, sizeof(answer)); assert_in_range(rv, 1, 256); ns_initparse(answer, sizeof(answer), &handle); /* * The query must finish w/o an error, have three answers and the answers * must be a parseable RR of type CNAME and have the cname as in the * fake hosts file */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 3); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_cname); rrdata = ns_rr_rdata(rr); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, cname, MAXDNAME); assert_int_not_equal(rv, -1); assert_string_equal(cname, "web.cwrap.org"); assert_int_equal(ns_parserr(&handle, ns_s_an, 1, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_cname); rrdata = ns_rr_rdata(rr); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, cname, MAXDNAME); assert_int_not_equal(rv, -1); assert_string_equal(cname, "www.cwrap.org"); assert_int_equal(ns_parserr(&handle, ns_s_an, 2, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_a); assert_string_equal(ns_rr_name(rr), "www.cwrap.org"); assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, sizeof(addr))); assert_string_equal(addr, "127.0.0.22"); }