/* * クエリを投げる. * @return */ static int DnsResolver_query(DnsResolver *self, const char *domain, int rrtype) { self->resolver.res_h_errno = 0; self->resolv_errno = 0; self->resolv_h_errno = NETDB_SUCCESS; self->msglen = res_nquery(&self->resolver, domain, ns_c_in, rrtype, self->msgbuf, NS_MAXMSG); if (0 > self->msglen) { goto queryfail; } // end if if (0 > ns_initparse(self->msgbuf, self->msglen, &self->msghanlde)) { self->resolver.res_h_errno = NO_RECOVERY; goto queryfail; } // end if int rcode_flag = ns_msg_getflag(self->msghanlde, ns_f_rcode); if (rcode_flag != ns_r_noerror) { self->resolver.res_h_errno = DnsResolver_rcode2statcode(rcode_flag); goto queryfail; } // end if return NETDB_SUCCESS; queryfail: return DnsResolver_setError(self, self->resolver.res_h_errno); } // end function : DnsResolver_query
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"); }
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); }
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; }
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 */ } }
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"); }
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); }
// 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 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; }
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"); }
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_soa_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 nameser[MAXDNAME]; char admin[MAXDNAME]; int serial; int refresh; int retry; int expire; int minimum; (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_soa, 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 SOA and have the data 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_soa); rrdata = ns_rr_rdata(rr); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, nameser, MAXDNAME); assert_int_not_equal(rv, -1); rrdata += rv; rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, admin, MAXDNAME); assert_int_not_equal(rv, -1); rrdata += rv; NS_GET32(serial, rrdata); NS_GET32(refresh, rrdata); NS_GET32(retry, rrdata); NS_GET32(expire, rrdata); NS_GET32(minimum, rrdata); assert_string_equal(nameser, "ns1.cwrap.org"); assert_string_equal(admin, "admin.cwrap.org"); assert_int_equal(serial, 2014100457); assert_int_equal(refresh, 3600); assert_int_equal(retry, 300); assert_int_equal(expire, 1814400); assert_int_equal(minimum, 600); }
/* * Test the case of a SRV record query where the * fake hosts file entry is minimal in the sense * that it omits the priority and weight entries. * The server then fills in some default values. */ static void test_res_fake_srv_query_minimal(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]; 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, "_krb5._tcp.cwrap.org", ns_c_in, ns_t_srv, answer, sizeof(answer)); assert_in_range(rv, 1, 256); 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, 100); assert_int_equal(port, 88); assert_string_equal(hostname, "krb5.cwrap.org"); /* The additional section contains the A record of krb5.cwrap.org */ assert_int_equal(ns_msg_count(handle, ns_s_ar), 1); assert_int_equal(ns_parserr(&handle, ns_s_ar, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_a); assert_string_equal(ns_rr_name(rr), "krb5.cwrap.org"); assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, sizeof(addr))); assert_string_equal(addr, "127.0.0.23"); }
DWORD LWNetDnsQueryWithBuffer( IN PCSTR pszQuestion, IN BOOLEAN bReInit, IN BOOLEAN bUseTcp, OUT PVOID pBuffer, IN DWORD dwBufferSize, OUT PDWORD pdwResponseSize ) { DWORD dwError = 0; PDNS_RESPONSE_HEADER pHeader = (PDNS_RESPONSE_HEADER)pBuffer; int responseSize = 0; BOOLEAN bInLock = FALSE; #if HAVE_DECL_RES_NINIT union { struct __res_state res; #ifdef __LWI_AIX__ // struct __res_state was enlarged from 720 in AIX 5.2 to 824 in AIX // 5.3. This means calling res_ninit on AIX 5.3 on a structure compiled // on AIX 5.2 will result in a buffer overflow. Furthermore, even on // AIX 5.3, res_ninit seems to expect 1596 bytes in the structure (1491 // on AIX 5.2). As a workaround, this padding will ensure enough space // is allocated on the stack. char buffer[2048]; #endif } resLocal = { {0} }; res_state res = &resLocal.res; #else struct __res_state *res = &_res; #endif LWNET_LOCK_RESOLVER_API(bInLock); #if HAVE_DECL_RES_NINIT if (res_ninit(res) != 0) #else if (res_init() != 0) #endif { dwError = ERROR_NOT_FOUND; BAIL_ON_LWNET_ERROR(dwError); } if (dwBufferSize < CT_MIN(sizeof(DNS_RESPONSE_HEADER), MAX_DNS_UDP_BUFFER)) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_LWNET_ERROR(dwError); } // TODO: Add lock on calling resolver due to global options, which may or // may not be safe depending on the system. if (bUseTcp) { res->options |= RES_USEVC; } else { res->options &= ~(RES_USEVC); } /* Assertion: pResolverContext != NULL && pResolverContext->bLocked == TRUE */ #if HAVE_DECL_RES_NINIT responseSize = res_nquery(res, pszQuestion, ns_c_in, ns_t_srv, (PBYTE) pBuffer, dwBufferSize); #else responseSize = res_query(pszQuestion, ns_c_in, ns_t_srv, (PBYTE) pBuffer, dwBufferSize); #endif if (responseSize < 0) { LWNET_LOG_VERBOSE("DNS lookup for '%s' failed with errno %d, h_errno = %d", pszQuestion, errno, h_errno); dwError = DNS_ERROR_BAD_PACKET; BAIL_ON_LWNET_ERROR(dwError); } if (responseSize < CT_FIELD_OFFSET(DNS_RESPONSE_HEADER, data)) { dwError = DNS_ERROR_BAD_PACKET; BAIL_ON_LWNET_ERROR(dwError); } if (responseSize > dwBufferSize) { dwError = DNS_ERROR_BAD_PACKET; BAIL_ON_LWNET_ERROR(dwError); } LWNetDnsFixHeaderForEndianness(pHeader); if (!LWNetDnsIsValidResponse(pHeader)) { dwError = DNS_ERROR_BAD_PACKET; BAIL_ON_LWNET_ERROR(dwError); } error: #if HAVE_DECL_RES_NINIT res_nclose(res); #else /* Indicate that we are done with the resolver, except on HPUX which does not implement the res_close function. */ #ifndef __LWI_HP_UX__ res_close(); #endif #endif LWNET_UNLOCK_RESOLVER_API(bInLock); if (dwError) { responseSize = 0; } *pdwResponseSize = responseSize; return dwError; }