示例#1
0
static void
print_rdatasets(dns_name_t *name, dns_rdatasetiter_t *rdsiter) {
	isc_result_t result;
	dns_rdataset_t rdataset;

	dns_rdataset_init(&rdataset);
	result = dns_rdatasetiter_first(rdsiter);
	while (result == ISC_R_SUCCESS) {
		dns_rdatasetiter_current(rdsiter, &rdataset);
		print_rdataset(name, &rdataset);
		dns_rdataset_disassociate(&rdataset);
		result = dns_rdatasetiter_next(rdsiter);
	}
	if (result != ISC_R_NOMORE)
		print_result("", result);
}
示例#2
0
static void
resolve_ns(isc_task_t *task, isc_event_t *event) {
	struct probe_trans *trans = event->ev_arg;
	dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
	dns_name_t *name;
	dns_rdataset_t *rdataset;
	isc_result_t result = ISC_R_SUCCESS;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	struct probe_ns *pns;

	REQUIRE(task == probe_task);
	REQUIRE(trans->inuse == ISC_TRUE);
	INSIST(outstanding_probes > 0);

	for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
	     name = ISC_LIST_NEXT(name, link)) {
		for (rdataset = ISC_LIST_HEAD(name->list);
		     rdataset != NULL;
		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
			(void)print_rdataset(rdataset, name);

			if (rdataset->type != dns_rdatatype_ns)
				continue;

			for (result = dns_rdataset_first(rdataset);
			     result == ISC_R_SUCCESS;
			     result = dns_rdataset_next(rdataset)) {
				dns_rdata_ns_t ns;

				dns_rdataset_current(rdataset, &rdata);
				/*
				 * Extract the name from the NS record.
				 */
				result = dns_rdata_tostruct(&rdata, &ns, NULL);
				if (result != ISC_R_SUCCESS)
					continue;

				pns = isc_mem_get(mctx, sizeof(*pns));
				if (pns == NULL) {
					fprintf(stderr,
						"resolve_ns: mem_get failed");
					result = ISC_R_NOMEMORY;
					POST(result);
					/*
					 * XXX: should we continue with the
					 * available servers anyway?
					 */
					goto cleanup;
				}

				dns_fixedname_init(&pns->fixedname);
				pns->name =
					dns_fixedname_name(&pns->fixedname);
				ISC_LINK_INIT(pns, link);
				ISC_LIST_APPEND(trans->nslist, pns, link);
				ISC_LIST_INIT(pns->servers);

				dns_name_copy(&ns.name, pns->name, NULL);
				dns_rdata_reset(&rdata);
				dns_rdata_freestruct(&ns);
			}
		}
	}

 cleanup:
	dns_client_freeresanswer(client, &rev->answerlist);
	dns_client_destroyrestrans(&trans->resid);
	isc_event_free(&event);

	if (!ISC_LIST_EMPTY(trans->nslist)) {
		/* Go get addresses of NSes */
		trans->current_ns = ISC_LIST_HEAD(trans->nslist);
		result = fetch_nsaddress(trans);
	} else
		result = ISC_R_FAILURE;

	if (result == ISC_R_SUCCESS)
		return;

	reset_probe(trans);
}
示例#3
0
static void
resolve_nsaddress(isc_task_t *task, isc_event_t *event) {
	struct probe_trans *trans = event->ev_arg;
	dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
	dns_name_t *name;
	dns_rdataset_t *rdataset;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	struct probe_ns *pns = trans->current_ns;
	isc_result_t result;

	REQUIRE(task == probe_task);
	REQUIRE(trans->inuse == ISC_TRUE);
	REQUIRE(pns != NULL);
	INSIST(outstanding_probes > 0);

	for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
	     name = ISC_LIST_NEXT(name, link)) {
		for (rdataset = ISC_LIST_HEAD(name->list);
		     rdataset != NULL;
		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
			(void)print_rdataset(rdataset, name);

			if (rdataset->type != dns_rdatatype_a)
				continue;

			for (result = dns_rdataset_first(rdataset);
			     result == ISC_R_SUCCESS;
			     result = dns_rdataset_next(rdataset)) {
				dns_rdata_in_a_t rdata_a;
				struct server *server;

				dns_rdataset_current(rdataset, &rdata);
				result = dns_rdata_tostruct(&rdata, &rdata_a,
							    NULL);
				if (result != ISC_R_SUCCESS)
					continue;

				server = isc_mem_get(mctx, sizeof(*server));
				if (server == NULL) {
					fprintf(stderr, "resolve_nsaddress: "
						"mem_get failed");
					result = ISC_R_NOMEMORY;
					POST(result);
					goto cleanup;
				}
				isc_sockaddr_fromin(&server->address,
						    &rdata_a.in_addr, 53);
				ISC_LINK_INIT(server, link);
				server->result_a = none;
				server->result_aaaa = none;
				ISC_LIST_APPEND(pns->servers, server, link);
			}
		}
	}

 cleanup:
	dns_client_freeresanswer(client, &rev->answerlist);
	dns_client_destroyrestrans(&trans->resid);
	isc_event_free(&event);

 next_ns:
	trans->current_ns = ISC_LIST_NEXT(pns, link);
	if (trans->current_ns == NULL) {
		trans->current_ns = ISC_LIST_HEAD(trans->nslist);
		dns_fixedname_invalidate(&trans->fixedname);
		trans->qname = NULL;
		result = set_nextqname(trans);
		if (result == ISC_R_SUCCESS)
			 result = probe_name(trans, dns_rdatatype_a);
	} else {
		result = fetch_nsaddress(trans);
		if (result != ISC_R_SUCCESS)
			goto next_ns; /* XXX: this is unlikely to succeed */
	}

	if (result != ISC_R_SUCCESS)
		reset_probe(trans);
}
示例#4
0
static void
request_done(isc_task_t *task, isc_event_t *event) {
	struct probe_trans *trans = event->ev_arg;
	dns_clientreqevent_t *rev = (dns_clientreqevent_t *)event;
	dns_message_t *rmessage;
	struct probe_ns *pns;
	struct server *server;
	isc_result_t result;
	query_result_t *resultp;
	dns_name_t *name;
	dns_rdataset_t *rdataset;
	dns_rdatatype_t type;

	REQUIRE(task == probe_task);
	REQUIRE(trans != NULL && trans->inuse == ISC_TRUE);
	rmessage = rev->rmessage;
	REQUIRE(rmessage == trans->rmessage);
	INSIST(outstanding_probes > 0);

	server = trans->current_ns->current_server;
	INSIST(server != NULL);

	if (server->result_a == none) {
		type = dns_rdatatype_a;
		resultp = &server->result_a;
	} else {
		resultp = &server->result_aaaa;
		type = dns_rdatatype_aaaa;
	}

	if (rev->result == ISC_R_SUCCESS) {
		if ((rmessage->flags & DNS_MESSAGEFLAG_AA) == 0)
			*resultp = lame;
		else if (rmessage->rcode == dns_rcode_nxdomain)
			*resultp = nxdomain;
		else if (rmessage->rcode != dns_rcode_noerror)
			*resultp = othererr;
		else if (rmessage->counts[DNS_SECTION_ANSWER] == 0) {
			/* no error but empty answer */
			*resultp = notype;
		} else {
			result = dns_message_firstname(rmessage,
						       DNS_SECTION_ANSWER);
			while (result == ISC_R_SUCCESS) {
				name = NULL;
				dns_message_currentname(rmessage,
							DNS_SECTION_ANSWER,
							&name);
				for (rdataset = ISC_LIST_HEAD(name->list);
				     rdataset != NULL;
				     rdataset = ISC_LIST_NEXT(rdataset,
							      link)) {
					(void)print_rdataset(rdataset, name);

					if (rdataset->type ==
					    dns_rdatatype_cname ||
					    rdataset->type ==
					    dns_rdatatype_dname) {
						/* Should chase the chain? */
						*resultp = exist;
						goto found;
					} else if (rdataset->type == type) {
						*resultp = exist;
						goto found;
					}
				}
				result = dns_message_nextname(rmessage,
							      DNS_SECTION_ANSWER);
			}

			/*
			 * Something unexpected happened: the response
			 * contained a non-empty authoritative answer, but we
			 * could not find an expected result.
			 */
			*resultp = unexpected;
		}
	} else if (rev->result == DNS_R_RECOVERABLE ||
		   rev->result == DNS_R_BADLABELTYPE) {
		/* Broken response.  Try identifying known cases. */
		*resultp = brokenanswer;

		if (rmessage->counts[DNS_SECTION_ANSWER] > 0) {
			result = dns_message_firstname(rmessage,
						       DNS_SECTION_ANSWER);
			while (result == ISC_R_SUCCESS) {
				/*
				 * Check to see if the response has multiple
				 * CNAME RRs.  Update the result code if so.
				 */
				name = NULL;
				dns_message_currentname(rmessage,
							DNS_SECTION_ANSWER,
							&name);
				for (rdataset = ISC_LIST_HEAD(name->list);
				     rdataset != NULL;
				     rdataset = ISC_LIST_NEXT(rdataset,
							      link)) {
					if (rdataset->type ==
					    dns_rdatatype_cname &&
					    dns_rdataset_count(rdataset) > 1) {
						*resultp = multiplecname;
						goto found;
					}
				}
				result = dns_message_nextname(rmessage,
							      DNS_SECTION_ANSWER);
			}
		}

		if (rmessage->counts[DNS_SECTION_AUTHORITY] > 0) {
			result = dns_message_firstname(rmessage,
						       DNS_SECTION_AUTHORITY);
			while (result == ISC_R_SUCCESS) {
				/*
				 * Check to see if the response has multiple
				 * SOA RRs.  Update the result code if so.
				 */
				name = NULL;
				dns_message_currentname(rmessage,
							DNS_SECTION_AUTHORITY,
							&name);
				for (rdataset = ISC_LIST_HEAD(name->list);
				     rdataset != NULL;
				     rdataset = ISC_LIST_NEXT(rdataset,
							      link)) {
					if (rdataset->type ==
					    dns_rdatatype_soa &&
					    dns_rdataset_count(rdataset) > 1) {
						*resultp = multiplesoa;
						goto found;
					}
				}
				result = dns_message_nextname(rmessage,
							      DNS_SECTION_AUTHORITY);
			}
		}
	} else if (rev->result == ISC_R_TIMEDOUT)
		*resultp = timedout;
	else {
		fprintf(stderr, "unexpected result: %d (domain=%s, server=",
			rev->result, trans->domain);
		print_address(stderr, &server->address);
		fputc('\n', stderr);
		*resultp = unexpected;
	}

 found:
	INSIST(*resultp != none);
	if (type == dns_rdatatype_a && *resultp == exist)
		trans->qname_found = ISC_TRUE;

	dns_client_destroyreqtrans(&trans->reqid);
	isc_event_free(&event);
	dns_message_reset(trans->rmessage, DNS_MESSAGE_INTENTPARSE);

	result = probe_name(trans, type);
	if (result == ISC_R_NOMORE) {
		/* We've tried all addresses of all servers. */
		if (type == dns_rdatatype_a && trans->qname_found) {
			/*
			 * If we've explored A RRs and found an existent
			 * record, we can move to AAAA.
			 */
			trans->current_ns = ISC_LIST_HEAD(trans->nslist);
			probe_name(trans, dns_rdatatype_aaaa);
			result = ISC_R_SUCCESS;
		} else if (type == dns_rdatatype_a) {
			/*
			 * No server provided an existent A RR of this name.
			 * Try next label.
			 */
			dns_fixedname_invalidate(&trans->fixedname);
			trans->qname = NULL;
			result = set_nextqname(trans);
			if (result == ISC_R_SUCCESS) {
				trans->current_ns =
					ISC_LIST_HEAD(trans->nslist);
				for (pns = trans->current_ns; pns != NULL;
				     pns = ISC_LIST_NEXT(pns, link)) {
					for (server = ISC_LIST_HEAD(pns->servers);
					     server != NULL;
					     server = ISC_LIST_NEXT(server,
								    link)) {
						INSIST(server->result_aaaa ==
						       none);
						server->result_a = none;
					}
				}
				result = probe_name(trans, dns_rdatatype_a);
			}
		}
		if (result != ISC_R_SUCCESS) {
			/*
			 * We've explored AAAA RRs or failed to find a valid
			 * query label.  Wrap up the result and move to the
			 * next domain.
			 */
			reset_probe(trans);
		}
	} else if (result != ISC_R_SUCCESS)
		reset_probe(trans); /* XXX */
}
示例#5
0
static void
query(void) {
	char buf[1024];
	dns_fixedname_t name;
	dns_fixedname_t found;
	dns_db_t *db;
	char *s;
	isc_buffer_t buffer;
	isc_result_t result;
	dns_rdataset_t rdataset;
	dns_rdataset_t sigset;
	fd_set rfdset;

	db = NULL;
	result = dns_zone_getdb(zone, &db);
	if (result != ISC_R_SUCCESS) {
		fprintf(stderr, "%s() returned %s\n", "dns_zone_getdb",
			dns_result_totext(result));
		return;
	}

	dns_fixedname_init(&found);
	dns_rdataset_init(&rdataset);
	dns_rdataset_init(&sigset);

	do {

		fprintf(stdout, "zone_test ");
		fflush(stdout);
		FD_ZERO(&rfdset);
		FD_SET(0, &rfdset);
		select(1, &rfdset, NULL, NULL, NULL);
		if (fgets(buf, sizeof(buf), stdin) == NULL) {
			fprintf(stdout, "\n");
			break;
		}
		buf[sizeof(buf) - 1] = '\0';

		s = strchr(buf, '\n');
		if (s != NULL)
			*s = '\0';
		s = strchr(buf, '\r');
		if (s != NULL)
			*s = '\0';
		if (strcmp(buf, "dump") == 0) {
			dns_zone_dumptostream(zone, stdout);
			continue;
		}
		if (strlen(buf) == 0U)
			continue;
		dns_fixedname_init(&name);
		isc_buffer_init(&buffer, buf, strlen(buf));
		isc_buffer_add(&buffer, strlen(buf));
		result = dns_name_fromtext(dns_fixedname_name(&name),
				  &buffer, dns_rootname, 0, NULL);
		ERRCONT(result, "dns_name_fromtext");

		result = dns_db_find(db, dns_fixedname_name(&name),
				     NULL /*vesion*/,
				     dns_rdatatype_a,
				     0 /*options*/,
				     0 /*time*/,
				     NULL /*nodep*/,
				     dns_fixedname_name(&found),
				     &rdataset, &sigset);
		fprintf(stderr, "%s() returned %s\n", "dns_db_find",
			dns_result_totext(result));
		switch (result) {
		case DNS_R_DELEGATION:
			print_rdataset(dns_fixedname_name(&found), &rdataset);
			break;
		case ISC_R_SUCCESS:
			print_rdataset(dns_fixedname_name(&name), &rdataset);
			break;
		default:
			break;
		}

		if (dns_rdataset_isassociated(&rdataset))
			dns_rdataset_disassociate(&rdataset);
		if (dns_rdataset_isassociated(&sigset))
			dns_rdataset_disassociate(&sigset);
	} while (1);
	dns_rdataset_invalidate(&rdataset);
	dns_db_detach(&db);
}
示例#6
0
int
main(int argc, char *argv[]) {
	dns_db_t *db;
	dns_dbnode_t *node;
	isc_result_t result;
	dns_name_t name;
	dns_offsets_t offsets;
	size_t len;
	isc_buffer_t source, target;
	char s[1000];
	char b[255];
	dns_rdataset_t rdataset, sigrdataset;
	int ch;
	dns_rdatatype_t type = 1;
	isc_boolean_t printnode = ISC_FALSE;
	isc_boolean_t addmode = ISC_FALSE;
	isc_boolean_t delmode = ISC_FALSE;
	isc_boolean_t holdmode = ISC_FALSE;
	isc_boolean_t verbose = ISC_FALSE;
	isc_boolean_t done = ISC_FALSE;
	isc_boolean_t quiet = ISC_FALSE;
	isc_boolean_t time_lookups = ISC_FALSE;
	isc_boolean_t found_as;
	isc_boolean_t find_zonecut = ISC_FALSE;
	isc_boolean_t noexact_zonecut = ISC_FALSE;
	int i, v;
	dns_rdatasetiter_t *rdsiter;
	char t1[256];
	char t2[256];
	isc_buffer_t tb1, tb2;
	isc_region_t r1, r2;
	dns_fixedname_t foundname;
	dns_name_t *fname;
	unsigned int options = 0, zcoptions;
	isc_time_t start, finish;
	char *origintext;
	dbinfo *dbi;
	dns_dbversion_t *version;
	dns_name_t *origin;
	size_t memory_quota = 0;
	dns_trust_t trust = 0;
	unsigned int addopts;
	isc_log_t *lctx = NULL;
	size_t n;

	dns_result_register();

	RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
	RUNTIME_CHECK(dns_dbtable_create(mctx, dns_rdataclass_in, &dbtable) ==
		      ISC_R_SUCCESS);



	strcpy(dbtype, "rbt");
	while ((ch = isc_commandline_parse(argc, argv, "c:d:t:z:P:Q:glpqvT"))
	       != -1) {
		switch (ch) {
		case 'c':
			result = load(isc_commandline_argument, ".", ISC_TRUE);
			if (result != ISC_R_SUCCESS)
				printf("cache load(%s) %08x: %s\n",
				       isc_commandline_argument, result,
				       isc_result_totext(result));
			break;
		case 'd':
			n = strlcpy(dbtype, isc_commandline_argument,
				    sizeof(dbtype));
			if (n >= sizeof(dbtype)) {
				fprintf(stderr, "bad db type '%s'\n",
					isc_commandline_argument);
				exit(1);
			}
			break;
		case 'g':
			options |= (DNS_DBFIND_GLUEOK|DNS_DBFIND_VALIDATEGLUE);
			break;
		case 'l':
			RUNTIME_CHECK(isc_log_create(mctx, &lctx,
						     NULL) == ISC_R_SUCCESS);
			isc_log_setcontext(lctx);
			dns_log_init(lctx);
			dns_log_setcontext(lctx);
			break;
		case 'q':
			quiet = ISC_TRUE;
			verbose = ISC_FALSE;
			break;
		case 'p':
			printnode = ISC_TRUE;
			break;
		case 'P':
			pause_every = atoi(isc_commandline_argument);
			break;
		case 'Q':
			memory_quota = atoi(isc_commandline_argument);
			isc_mem_setquota(mctx, memory_quota);
			break;
		case 't':
			type = atoi(isc_commandline_argument);
			break;
		case 'T':
			time_lookups = ISC_TRUE;
			break;
		case 'v':
			verbose = ISC_TRUE;
			break;
		case 'z':
			origintext = strrchr(isc_commandline_argument, '/');
			if (origintext == NULL)
				origintext = isc_commandline_argument;
			else
				origintext++;	/* Skip '/'. */
			result = load(isc_commandline_argument, origintext,
				      ISC_FALSE);
			if (result != ISC_R_SUCCESS)
				printf("zone load(%s) %08x: %s\n",
				       isc_commandline_argument, result,
				       isc_result_totext(result));
			break;
		}
	}

	argc -= isc_commandline_index;
	argv += isc_commandline_index;
	POST(argv);

	if (argc != 0)
		printf("ignoring trailing arguments\n");

	/*
	 * Some final initialization...
	 */
	dns_fixedname_init(&foundname);
	fname = dns_fixedname_name(&foundname);
	dbi = NULL;
	origin = dns_rootname;
	version = NULL;

	if (time_lookups) {
		TIME_NOW(&start);
	}

	while (!done) {
		if (!quiet)
			printf("\n");
		if (fgets(s, sizeof(s), stdin) == NULL) {
			done = ISC_TRUE;
			continue;
		}
		len = strlen(s);
		if (len > 0U && s[len - 1] == '\n') {
			s[len - 1] = '\0';
			len--;
		}
		if (verbose && dbi != NULL) {
			if (dbi->wversion != NULL)
				printf("future version (%p)\n", dbi->wversion);
			for (i = 0; i < dbi->rcount; i++)
				if (dbi->rversions[i] != NULL)
					printf("open version %d (%p)\n", i,
					       dbi->rversions[i]);
		}
		dns_name_init(&name, offsets);
		if (strcmp(s, "!R") == 0) {
			DBI_CHECK(dbi);
			if (dbi->rcount == MAXVERSIONS) {
				printf("too many open versions\n");
				continue;
			}
			dns_db_currentversion(dbi->db,
					      &dbi->rversions[dbi->rcount]);
			printf("opened version %d\n", dbi->rcount);
			dbi->version = dbi->rversions[dbi->rcount];
			version = dbi->version;
			dbi->rcount++;
			continue;
		} else if (strcmp(s, "!W") == 0) {
			DBI_CHECK(dbi);
			if (dbi->wversion != NULL) {
				printf("using existing future version\n");
				dbi->version = dbi->wversion;
				version = dbi->version;
				continue;
			}
			result = dns_db_newversion(dbi->db, &dbi->wversion);
			if (result != ISC_R_SUCCESS)
				print_result("", result);
			else
				printf("newversion\n");
			dbi->version = dbi->wversion;
			version = dbi->version;
			continue;
		} else if (strcmp(s, "!C") == 0) {
			DBI_CHECK(dbi);
			addmode = ISC_FALSE;
			delmode = ISC_FALSE;
			if (dbi->version == NULL)
				continue;
			if (dbi->version == dbi->wversion) {
				printf("closing future version\n");
				dbi->wversion = NULL;
			} else {
				for (i = 0; i < dbi->rcount; i++) {
					if (dbi->version ==
					    dbi->rversions[i]) {
						dbi->rversions[i] = NULL;
					  printf("closing open version %d\n",
						 i);
						break;
					}
				}
			}
			dns_db_closeversion(dbi->db, &dbi->version, ISC_TRUE);
			version = NULL;
			continue;
		} else if (strcmp(s, "!X") == 0) {
			DBI_CHECK(dbi);
			addmode = ISC_FALSE;
			delmode = ISC_FALSE;
			if (dbi->version == NULL)
				continue;
			if (dbi->version == dbi->wversion) {
				printf("aborting future version\n");
				dbi->wversion = NULL;
			} else {
				for (i = 0; i < dbi->rcount; i++) {
					if (dbi->version ==
					    dbi->rversions[i]) {
						dbi->rversions[i] = NULL;
					  printf("closing open version %d\n",
						 i);
						break;
					}
				}
			}
			dns_db_closeversion(dbi->db, &dbi->version, ISC_FALSE);
			version = NULL;
			continue;
		} else if (strcmp(s, "!A") == 0) {
			DBI_CHECK(dbi);
			delmode = ISC_FALSE;
			if (addmode)
				addmode = ISC_FALSE;
			else
				addmode = ISC_TRUE;
			printf("addmode = %s\n", addmode ? "TRUE" : "FALSE");
			continue;
		} else if (strcmp(s, "!D") == 0) {
			DBI_CHECK(dbi);
			addmode = ISC_FALSE;
			if (delmode)
				delmode = ISC_FALSE;
			else
				delmode = ISC_TRUE;
			printf("delmode = %s\n", delmode ? "TRUE" : "FALSE");
			continue;
		} else if (strcmp(s, "!H") == 0) {
			DBI_CHECK(dbi);
			if (holdmode)
				holdmode = ISC_FALSE;
			else
				holdmode = ISC_TRUE;
			printf("holdmode = %s\n", holdmode ? "TRUE" : "FALSE");
			continue;
		} else if (strcmp(s, "!HR") == 0) {
			DBI_CHECK(dbi);
			for (i = 0; i < dbi->hold_count; i++)
				dns_db_detachnode(dbi->db,
						  &dbi->hold_nodes[i]);
			dbi->hold_count = 0;
			holdmode = ISC_FALSE;
			printf("held nodes have been detached\n");
			continue;
		} else if (strcmp(s, "!VC") == 0) {
			DBI_CHECK(dbi);
			printf("switching to current version\n");
			dbi->version = NULL;
			version = NULL;
			continue;
		} else if (strstr(s, "!V") == s) {
			DBI_CHECK(dbi);
			v = atoi(&s[2]);
			if (v >= dbi->rcount || v < 0) {
				printf("unknown open version %d\n", v);
				continue;
			}
			if (dbi->rversions[v] == NULL) {
				printf("version %d is not open\n", v);
				continue;
			}
			printf("switching to open version %d\n", v);
			dbi->version = dbi->rversions[v];
			version = dbi->version;
			continue;
		} else if (strstr(s, "!TR") == s) {
			trust = (unsigned int)atoi(&s[3]);
			printf("trust level is now %u\n", (unsigned int)trust);
			continue;
		} else if (strstr(s, "!T") == s) {
			type = (unsigned int)atoi(&s[2]);
			printf("now searching for type %u\n", type);
			continue;
		} else if (strcmp(s, "!G") == 0) {
			if ((options & DNS_DBFIND_GLUEOK) != 0)
				options &= ~DNS_DBFIND_GLUEOK;
			else
				options |= DNS_DBFIND_GLUEOK;
			printf("glue ok = %s\n",
			       ((options & DNS_DBFIND_GLUEOK) != 0) ?
			       "TRUE" : "FALSE");
			continue;
		} else if (strcmp(s, "!GV") == 0) {
			if ((options & DNS_DBFIND_VALIDATEGLUE) != 0)
				options &= ~DNS_DBFIND_VALIDATEGLUE;
			else
				options |= DNS_DBFIND_VALIDATEGLUE;
			printf("validate glue = %s\n",
			       ((options & DNS_DBFIND_VALIDATEGLUE) != 0) ?
			       "TRUE" : "FALSE");
			continue;
		} else if (strcmp(s, "!WC") == 0) {
			if ((options & DNS_DBFIND_NOWILD) != 0)
				options &= ~DNS_DBFIND_NOWILD;
			else
				options |= DNS_DBFIND_NOWILD;
			printf("wildcard matching = %s\n",
			       ((options & DNS_DBFIND_NOWILD) == 0) ?
			       "TRUE" : "FALSE");
			continue;
		} else if (strstr(s, "!LS ") == s) {
			DBI_CHECK(dbi);
			list(dbi, &s[4]);
			continue;
		} else if (strcmp(s, "!LS") == 0) {
			DBI_CHECK(dbi);
			list(dbi, NULL);
			continue;
		} else if (strstr(s, "!DU ") == s) {
			DBI_CHECK(dbi);
			result = dns_db_dump(dbi->db, dbi->version, s+4);
			if (result != ISC_R_SUCCESS) {
				printf("\n");
				print_result("", result);
			}
			continue;
		} else if (strcmp(s, "!PN") == 0) {
			if (printnode)
				printnode = ISC_FALSE;
			else
				printnode = ISC_TRUE;
			printf("printnode = %s\n",
			       printnode ? "TRUE" : "FALSE");
			continue;
		} else if (strstr(s, "!P") == s) {
			DBI_CHECK(dbi);
			v = atoi(&s[2]);
			dbi->pause_every = v;
			continue;
		} else if (strcmp(s, "!+") == 0) {
			DBI_CHECK(dbi);
			dbi->ascending = ISC_TRUE;
			continue;
		} else if (strcmp(s, "!-") == 0) {
			DBI_CHECK(dbi);
			dbi->ascending = ISC_FALSE;
			continue;
		} else if (strcmp(s, "!DB") == 0) {
			dbi = NULL;
			origin = dns_rootname;
			version = NULL;
			printf("now searching all databases\n");
			continue;
		} else if (strncmp(s, "!DB ", 4) == 0) {
			dbi = select_db(s+4);
			if (dbi != NULL) {
				db = dbi->db;
				origin = dns_db_origin(dbi->db);
				version = dbi->version;
				addmode = ISC_FALSE;
				delmode = ISC_FALSE;
				holdmode = ISC_FALSE;
			} else {
				db = NULL;
				version = NULL;
				origin = dns_rootname;
				printf("database not found; "
				       "now searching all databases\n");
			}
			continue;
		} else if (strcmp(s, "!ZC") == 0) {
			if (find_zonecut)
				find_zonecut = ISC_FALSE;
			else
				find_zonecut = ISC_TRUE;
			printf("find_zonecut = %s\n",
			       find_zonecut ? "TRUE" : "FALSE");
			continue;
		} else if (strcmp(s, "!NZ") == 0) {
			if (noexact_zonecut)
				noexact_zonecut = ISC_FALSE;
			else
				noexact_zonecut = ISC_TRUE;
			printf("noexact_zonecut = %s\n",
			       noexact_zonecut ? "TRUE" : "FALSE");
			continue;
		}

		isc_buffer_init(&source, s, len);
		isc_buffer_add(&source, len);
		isc_buffer_init(&target, b, sizeof(b));
		result = dns_name_fromtext(&name, &source, origin, 0, &target);
		if (result != ISC_R_SUCCESS) {
			print_result("bad name: ", result);
			continue;
		}

		if (dbi == NULL) {
			zcoptions = 0;
			if (noexact_zonecut)
				zcoptions |= DNS_DBTABLEFIND_NOEXACT;
			db = NULL;
			result = dns_dbtable_find(dbtable, &name, zcoptions,
						  &db);
			if (result != ISC_R_SUCCESS &&
			    result != DNS_R_PARTIALMATCH) {
				if (!quiet) {
					printf("\n");
					print_result("", result);
				}
				continue;
			}
			isc_buffer_init(&tb1, t1, sizeof(t1));
			result = dns_name_totext(dns_db_origin(db), ISC_FALSE,
						 &tb1);
			if (result != ISC_R_SUCCESS) {
				printf("\n");
				print_result("", result);
				dns_db_detach(&db);
				continue;
			}
			isc_buffer_usedregion(&tb1, &r1);
			printf("\ndatabase = %.*s (%s)\n",
			       (int)r1.length, r1.base,
			       (dns_db_iszone(db)) ? "zone" : "cache");
		}
		node = NULL;
		dns_rdataset_init(&rdataset);
		dns_rdataset_init(&sigrdataset);

		if (find_zonecut && dns_db_iscache(db)) {
			zcoptions = options;
			if (noexact_zonecut)
				zcoptions |= DNS_DBFIND_NOEXACT;
			result = dns_db_findzonecut(db, &name, zcoptions,
						    0, &node, fname,
						    &rdataset, &sigrdataset);
		} else {
			result = dns_db_find(db, &name, version, type,
					     options, 0, &node, fname,
					     &rdataset, &sigrdataset);
		}

		if (!quiet) {
			if (dbi != NULL)
				printf("\n");
			print_result("", result);
		}

		found_as = ISC_FALSE;
		switch (result) {
		case ISC_R_SUCCESS:
		case DNS_R_GLUE:
		case DNS_R_CNAME:
		case DNS_R_ZONECUT:
			break;
		case DNS_R_DNAME:
		case DNS_R_DELEGATION:
			found_as = ISC_TRUE;
			break;
		case DNS_R_NXRRSET:
			if (dns_rdataset_isassociated(&rdataset))
				break;
			if (dbi != NULL) {
				if (holdmode) {
					RUNTIME_CHECK(dbi->hold_count <
						      MAXHOLD);
					dbi->hold_nodes[dbi->hold_count++] =
						node;
					node = NULL;
				} else
					dns_db_detachnode(db, &node);
			} else {
				dns_db_detachnode(db, &node);
				dns_db_detach(&db);
			}
			continue;
		case DNS_R_NXDOMAIN:
			if (dns_rdataset_isassociated(&rdataset))
				break;
			/* FALLTHROUGH */
		default:
			if (dbi == NULL)
				dns_db_detach(&db);
			if (quiet)
				print_result("", result);
			continue;
		}
		if (found_as && !quiet) {
			isc_buffer_init(&tb1, t1, sizeof(t1));
			isc_buffer_init(&tb2, t2, sizeof(t2));
			result = dns_name_totext(&name, ISC_FALSE, &tb1);
			if (result != ISC_R_SUCCESS) {
				print_result("", result);
				dns_db_detachnode(db, &node);
				if (dbi == NULL)
					dns_db_detach(&db);
				continue;
			}
			result = dns_name_totext(fname, ISC_FALSE, &tb2);
			if (result != ISC_R_SUCCESS) {
				print_result("", result);
				dns_db_detachnode(db, &node);
				if (dbi == NULL)
					dns_db_detach(&db);
				continue;
			}
			isc_buffer_usedregion(&tb1, &r1);
			isc_buffer_usedregion(&tb2, &r2);
			printf("found %.*s as %.*s\n",
			       (int)r1.length, r1.base,
			       (int)r2.length, r2.base);
		}

		if (printnode)
			dns_db_printnode(db, node, stdout);

		if (!found_as && type == dns_rdatatype_any) {
			rdsiter = NULL;
			result = dns_db_allrdatasets(db, node, version, 0,
						     &rdsiter);
			if (result == ISC_R_SUCCESS) {
				if (!quiet)
					print_rdatasets(fname, rdsiter);
				dns_rdatasetiter_destroy(&rdsiter);
			} else
				print_result("", result);
		} else {
			if (!quiet)
				print_rdataset(fname, &rdataset);
			if (dns_rdataset_isassociated(&sigrdataset)) {
				if (!quiet)
					print_rdataset(fname, &sigrdataset);
				dns_rdataset_disassociate(&sigrdataset);
			}
			if (dbi != NULL && addmode && !found_as) {
				rdataset.ttl++;
				rdataset.trust = trust;
				if (dns_db_iszone(db))
					addopts = DNS_DBADD_MERGE;
				else
					addopts = 0;
				result = dns_db_addrdataset(db, node, version,
							    0, &rdataset,
							    addopts, NULL);
				if (result != ISC_R_SUCCESS)
					print_result("", result);
				if (printnode)
					dns_db_printnode(db, node, stdout);
			} else if (dbi != NULL && delmode && !found_as) {
				result = dns_db_deleterdataset(db, node,
							       version, type,
							       0);
				if (result != ISC_R_SUCCESS)
					print_result("", result);
				if (printnode)
					dns_db_printnode(db, node, stdout);
			}
			dns_rdataset_disassociate(&rdataset);
		}

		if (dbi != NULL) {
			if (holdmode) {
				RUNTIME_CHECK(dbi->hold_count < MAXHOLD);
				dbi->hold_nodes[dbi->hold_count++] = node;
				node = NULL;
			} else
				dns_db_detachnode(db, &node);
		} else {
			dns_db_detachnode(db, &node);
			dns_db_detach(&db);
		}
	}

	if (time_lookups) {
		isc_uint64_t usec;

		TIME_NOW(&finish);

		usec = isc_time_microdiff(&finish, &start);

		printf("elapsed time: %lu.%06lu seconds\n",
		       (unsigned long)(usec / 1000000),
		       (unsigned long)(usec % 1000000));
	}

	unload_all();

	dns_dbtable_detach(&dbtable);

	if (lctx != NULL)
		isc_log_destroy(&lctx);

	if (!quiet)
		isc_mem_stats(mctx, stdout);

	return (0);
}