Fix a crash in dig NS search mode
In special NS search mode, after the initial lookup, dig starts the followup lookup with discovered NS servers in the queries list. If one of those queries then fail, dig, as usual, tries to start the next query in the list, which results in a crash, because the NS search mode is special in a way that the queries are running in parallel, so the next query is usually already started. Apply some special logic in `recv_done()` function to deal with the described situation when handling the query result for the NS search mode. Particularly, print a warning message for the failed query, and do not try to start the next query in the list. Also, set a non-zero exit code if all the queries in the followup lookup fail.
This commit is contained in:
@@ -3879,6 +3879,51 @@ recv_done(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
|
||||
goto next_lookup;
|
||||
}
|
||||
|
||||
/*
|
||||
* NSSEARCH mode is special, because the queries in the followup lookup
|
||||
* are independent and they are being started in parallel, so if one of
|
||||
* them fails there is no need to start the next query in the lookup,
|
||||
* and this failure can be treated as a soft error (with a warning
|
||||
* message), because there are usually more than one NS servers in the
|
||||
* lookup's queries list. However, if there was not a single successful
|
||||
* query in the followup lookup, then print an error message and exit
|
||||
* with a non-zero exit code.
|
||||
*/
|
||||
if (l->ns_search_only && !l->trace_root) {
|
||||
if (eresult == ISC_R_SUCCESS) {
|
||||
l->ns_search_success = true;
|
||||
} else {
|
||||
char sockstr[ISC_SOCKADDR_FORMATSIZE];
|
||||
isc_sockaddr_format(&query->sockaddr, sockstr,
|
||||
sizeof(sockstr));
|
||||
|
||||
dighost_warning("communications error to %s: %s",
|
||||
sockstr, isc_result_totext(eresult));
|
||||
|
||||
/*
|
||||
* If this is not the last query, then we detach the
|
||||
* query, but keep the lookup running.
|
||||
*/
|
||||
if (!check_if_queries_done(l, query)) {
|
||||
goto detach_query;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the last query, and if there was not a
|
||||
* single successful query in the whole lookup, then
|
||||
* treat the situation as an error.
|
||||
*/
|
||||
if (!l->ns_search_success) {
|
||||
dighost_error("no NS servers could be reached");
|
||||
if (exitcode < 9) {
|
||||
exitcode = 9;
|
||||
}
|
||||
}
|
||||
|
||||
goto cancel_lookup;
|
||||
}
|
||||
}
|
||||
|
||||
if (eresult == ISC_R_TIMEDOUT) {
|
||||
if (l->retries > 1 && !l->tcp_mode) {
|
||||
dig_query_t *newq = NULL;
|
||||
|
||||
@@ -114,8 +114,8 @@ struct dig_lookup {
|
||||
idnin, idnout, ignore, multiline, need_search, new_search,
|
||||
noclass, nocrypto, nottl, ns_search_only, /*%< dig +nssearch,
|
||||
host -C */
|
||||
nsid, /*% Name Server ID (RFC 5001) */
|
||||
onesoa, pending, /*%< Pending a successful answer */
|
||||
ns_search_success, nsid, /*% Name Server ID (RFC 5001) */
|
||||
onesoa, pending, /*%< Pending a successful answer */
|
||||
print_unknown_format, qr, raflag, recurse, section_additional,
|
||||
section_answer, section_authority, section_question,
|
||||
seenbadcookie, sendcookie, servfail_stops,
|
||||
|
||||
Reference in New Issue
Block a user