void res_print (const struct res *res, bool backward) { if (!backward && res->parent) res_print (res->parent, backward); printf ("-> Port: %d", res->port); printf ("\n"); printf ("-> HS: \n"); hs_print (&res->hs); if (res->rules.cur) { printf (", Rules: "); for (int i = 0; i < res->rules.cur; i++) { if (i) printf (", "); const struct res_rule *r = &res->rules.arr[i]; printf ("%s_%d", r->tf ? r->tf : "", r->rule); printf ("\n"); rule_print (r->tf_rule, r->tf_tf); } } printf ("\n"); if (backward && res->parent) res_print (res->parent, backward); }
void list_res_print (const struct list_res *l, bool backward) { int count = 0; for (const struct res *res = l->head; res; res = res->next, count++) { res_print (res, backward); printf (" HS: "); hs_print (&res->hs); hs_print_json (&res->hs); printf ("-----\n"); } printf ("Count: %d\n", count); }
// 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); }