Ejemplo n.º 1
0
/*%
 * Destroy any finds.  This can be used to "start over from scratch" and
 * should only be called when events are _not_ being generated by the finds.
 */
static void
cleanup_gabn(ns_lwdclient_t *client) {
	ns_lwdclient_log(50, "cleaning up client %p", client);

	if (client->v6find != NULL) {
		if (client->v6find == client->v4find)
			client->v6find = NULL;
		else
			dns_adb_destroyfind(&client->v6find);
	}
	if (client->v4find != NULL)
		dns_adb_destroyfind(&client->v4find);
}
static void
lookup_callback(isc_task_t *task, isc_event_t *ev) {
	client_t *client;

	client = ev->ev_arg;
	INSIST(client->find == ev->ev_sender);

	printf("NAME %s:\n\tTask %p got event %p type %08x from %p, client %p\n\terr4: %s  err6: %s\n",
	       client->target,
	       task, ev, ev->ev_type, client->find, client,
	       isc_result_totext(client->find->result_v4),
	       isc_result_totext(client->find->result_v6));

	isc_event_free(&ev);
	ev = NULL;

	CLOCK();

	dns_adb_dumpfind(client->find, stderr);
	dns_adb_destroyfind(&client->find);

	ISC_LIST_UNLINK(clients, client, link);
	free_client(&client);

	CUNLOCK();
}
Ejemplo n.º 3
0
static void
do_find(isc_boolean_t want_event) {
	isc_result_t result;
	isc_boolean_t done = ISC_FALSE;
	unsigned int options;

	options = DNS_ADBFIND_INET | DNS_ADBFIND_INET6;
	if (want_event)
		options |= DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_EMPTYEVENT;
	dns_fixedname_init(&target);
	result = dns_adb_createfind(view->adb, task, adb_callback, NULL,
				    dns_fixedname_name(&fixed),
				    dns_rootname, 0, options, 0,
				    dns_fixedname_name(&target), 0,
				    &find);
	if (result == ISC_R_SUCCESS) {
		if (!ISC_LIST_EMPTY(find->list)) {
			/*
			 * We have at least some of the addresses for the
			 * name.
			 */
			INSIST((find->options & DNS_ADBFIND_WANTEVENT) == 0);
			print_addresses(find);
			done = ISC_TRUE;
		} else {
			/*
			 * We don't know any of the addresses for this
			 * name.
			 */
			if ((find->options & DNS_ADBFIND_WANTEVENT) == 0) {
				/*
				 * And ADB isn't going to send us any events
				 * either.  This query loses.
				 */
				done = ISC_TRUE;
			}
			/*
			 * If the DNS_ADBFIND_WANTEVENT flag was set, we'll
			 * get an event when something happens.
			 */
		}
	} else if (result == DNS_R_ALIAS) {
		print_name(dns_fixedname_name(&target));
		done = ISC_TRUE;
	} else {
		printf("dns_adb_createfind() returned %s\n",
		       isc_result_totext(result));
		done = ISC_TRUE;
	}

	if (done) {
		if (find != NULL)
			dns_adb_destroyfind(&find);
		isc_app_shutdown();
	}
}
Ejemplo n.º 4
0
static void
lookup(const char *target) {
	dns_name_t name;
	unsigned char namedata[256];
	client_t *client;
	isc_buffer_t t, namebuf;
	isc_result_t result;
	unsigned int options;

	INSIST(target != NULL);

	client = new_client();
	isc_buffer_init(&t, target, strlen(target));
	isc_buffer_add(&t, strlen(target));
	isc_buffer_init(&namebuf, namedata, sizeof(namedata));
	dns_name_init(&name, NULL);
	result = dns_name_fromtext(&name, &t, dns_rootname, ISC_FALSE,
				   &namebuf);
	check_result(result, "dns_name_fromtext %s", target);

	result = dns_name_dup(&name, mctx, &client->name);
	check_result(result, "dns_name_dup %s", target);

	options = 0;
	options |= DNS_ADBFIND_INET;
	options |= DNS_ADBFIND_INET6;
	options |= DNS_ADBFIND_WANTEVENT;
	options |= DNS_ADBFIND_HINTOK;
	options |= DNS_ADBFIND_GLUEOK;
	result = dns_adb_createfind(adb, t2, lookup_callback, client,
				    &client->name, dns_rootname, options,
				    now, NULL, view->dstport, &client->find);
#if 0
	check_result(result, "dns_adb_createfind()");
#endif
	dns_adb_dumpfind(client->find, stderr);

	if ((client->find->options & DNS_ADBFIND_WANTEVENT) != 0) {
		client->target = target;
		ISC_LIST_APPEND(clients, client, link);
	} else {
		printf("NAME %s:  err4 %s, err6 %s\n",
		       target, isc_result_totext(client->find->result_v4),
		       isc_result_totext(client->find->result_v6));

		dns_adb_destroyfind(&client->find);
		free_client(&client);
	}
}
Ejemplo n.º 5
0
static void
adb_callback(isc_task_t *etask, isc_event_t *event) {
	unsigned int type = event->ev_type;

	REQUIRE(etask == task);

	isc_event_free(&event);
	dns_adb_destroyfind(&find);

	if (type == DNS_EVENT_ADBMOREADDRESSES)
		do_find(ISC_FALSE);
	else if (type == DNS_EVENT_ADBNOMOREADDRESSES) {
		printf("no more addresses\n");
		isc_app_shutdown();
	} else {
		printf("unexpected ADB event type %u\n", type);
		isc_app_shutdown();
	}
}
Ejemplo n.º 6
0
static void
restart_find(ns_lwdclient_t *client) {
	unsigned int options;
	isc_result_t result;
	isc_boolean_t claimed;

	ns_lwdclient_log(50, "starting find for client %p", client);

	/*
	 * Issue a find for the name contained in the request.  We won't
	 * set the bit that says "anything is good enough" -- we want it
	 * all.
	 */
	options = 0;
	options |= DNS_ADBFIND_WANTEVENT;
	options |= DNS_ADBFIND_RETURNLAME;

	/*
	 * Set the bits up here to mark that we want this address family
	 * and that we do not currently have a find pending.  We will
	 * set that bit again below if it turns out we will get an event.
	 */
	if (NEED_V4(client))
		options |= DNS_ADBFIND_INET;
	if (NEED_V6(client))
		options |= DNS_ADBFIND_INET6;

 find_again:
	INSIST(client->find == NULL);
	result = dns_adb_createfind(client->clientmgr->view->adb,
				    client->clientmgr->task,
				    process_gabn_finddone, client,
				    dns_fixedname_name(&client->target_name),
				    dns_rootname, 0, options, 0,
				    dns_fixedname_name(&client->target_name),
				    client->clientmgr->view->dstport,
				    &client->find);

	/*
	 * Did we get an alias?  If so, save it and re-issue the query.
	 */
	if (result == DNS_R_ALIAS) {
		ns_lwdclient_log(50, "found alias, restarting query");
		dns_adb_destroyfind(&client->find);
		cleanup_gabn(client);
		result = add_alias(client);
		if (result != ISC_R_SUCCESS) {
			ns_lwdclient_log(50,
					 "out of buffer space adding alias");
			ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE);
			return;
		}
		goto find_again;
	}

	ns_lwdclient_log(50, "find returned %d (%s)", result,
			 isc_result_totext(result));

	/*
	 * Did we get an error?
	 */
	if (result != ISC_R_SUCCESS) {
		if (client->find != NULL)
			dns_adb_destroyfind(&client->find);
		cleanup_gabn(client);
		ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE);
		return;
	}

	claimed = ISC_FALSE;

	/*
	 * Did we get our answer to V4 addresses?
	 */
	if (NEED_V4(client)
	    && ((client->find->query_pending & DNS_ADBFIND_INET) == 0)) {
		ns_lwdclient_log(50, "client %p ipv4 satisfied by find %p",
				 client, client->find);
		claimed = ISC_TRUE;
		client->v4find = client->find;
	}

	/*
	 * Did we get our answer to V6 addresses?
	 */
	if (NEED_V6(client)
	    && ((client->find->query_pending & DNS_ADBFIND_INET6) == 0)) {
		ns_lwdclient_log(50, "client %p ipv6 satisfied by find %p",
				 client, client->find);
		claimed = ISC_TRUE;
		client->v6find = client->find;
	}

	/*
	 * If we're going to get an event, set our internal pending flag
	 * and return.  When we get an event back we'll do the right
	 * thing, basically by calling this function again, perhaps with a
	 * new target name.
	 *
	 * If we have both v4 and v6, and we are still getting an event,
	 * we have a programming error, so die hard.
	 */
	if ((client->find->options & DNS_ADBFIND_WANTEVENT) != 0) {
		ns_lwdclient_log(50, "event will be sent");
		INSIST(client->v4find == NULL || client->v6find == NULL);
		return;
	}
	ns_lwdclient_log(50, "no event will be sent");
	if (claimed)
		client->find = NULL;
	else
		dns_adb_destroyfind(&client->find);

	/*
	 * We seem to have everything we asked for, or at least we are
	 * able to respond with things we've learned.
	 */

	generate_reply(client);
}
Ejemplo n.º 7
0
static void
process_gabn_finddone(isc_task_t *task, isc_event_t *ev) {
	ns_lwdclient_t *client = ev->ev_arg;
	isc_eventtype_t evtype;
	isc_boolean_t claimed;

	ns_lwdclient_log(50, "find done for task %p, client %p", task, client);

	evtype = ev->ev_type;
	isc_event_free(&ev);

	/*
	 * No more info to be had?  If so, we have all the good stuff
	 * right now, so we can render things.
	 */
	claimed = ISC_FALSE;
	if (evtype == DNS_EVENT_ADBNOMOREADDRESSES) {
		if (NEED_V4(client)) {
			client->v4find = client->find;
			claimed = ISC_TRUE;
		}
		if (NEED_V6(client)) {
			client->v6find = client->find;
			claimed = ISC_TRUE;
		}
		if (client->find != NULL) {
			if (claimed)
				client->find = NULL;
			else
				dns_adb_destroyfind(&client->find);

		}
		generate_reply(client);
		return;
	}

	/*
	 * We probably don't need this find anymore.  We're either going to
	 * reissue it, or an error occurred.  Either way, we're done with
	 * it.
	 */
	if ((client->find != client->v4find)
	    && (client->find != client->v6find)) {
		dns_adb_destroyfind(&client->find);
	} else {
		client->find = NULL;
	}

	/*
	 * We have some new information we can gather.  Run off and fetch
	 * it.
	 */
	if (evtype == DNS_EVENT_ADBMOREADDRESSES) {
		restart_find(client);
		return;
	}

	/*
	 * An error or other strangeness happened.  Drop this query.
	 */
	cleanup_gabn(client);
	ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE);
}
Ejemplo n.º 8
0
static void
generate_reply(ns_lwdclient_t *client) {
	isc_result_t result;
	int lwres;
	isc_region_t r;
	lwres_buffer_t lwb;
	ns_lwdclientmgr_t *cm;

	cm = client->clientmgr;
	lwb.base = NULL;

	ns_lwdclient_log(50, "generating gabn reply for client %p", client);

	/*
	 * We must make certain the client->find is not still active.
	 * If it is either the v4 or v6 answer, just set it to NULL and
	 * let the cleanup code destroy it.  Otherwise, destroy it now.
	 */
	if (client->find == client->v4find || client->find == client->v6find)
		client->find = NULL;
	else
		if (client->find != NULL)
			dns_adb_destroyfind(&client->find);

	/*
	 * perhaps there are some here?
	 */
	if (NEED_V6(client) && client->v4find != NULL)
		client->v6find = client->v4find;

	/*
	 * Run through the finds we have and wire them up to the gabn
	 * structure.
	 */
	LWRES_LIST_INIT(client->gabn.addrs);
	if (client->v4find != NULL)
		setup_addresses(client, client->v4find, DNS_ADBFIND_INET);
	if (client->v6find != NULL)
		setup_addresses(client, client->v6find, DNS_ADBFIND_INET6);

	/*
	 * If there are no addresses, try the next element in the search
	 * path, if there are any more.  Otherwise, fall through into
	 * the error handling code below.
	 */
	if (client->gabn.naddrs == 0) {
		do {
			result = ns_lwsearchctx_next(&client->searchctx);
			if (result == ISC_R_SUCCESS) {
				cleanup_gabn(client);
				result = start_find(client);
				if (result == ISC_R_SUCCESS)
					return;
			}
		} while (result == ISC_R_SUCCESS);
	}

	/*
	 * Render the packet.
	 */
	client->pkt.recvlength = LWRES_RECVLENGTH;
	client->pkt.authtype = 0; /* XXXMLG */
	client->pkt.authlength = 0;

	/*
	 * If there are no addresses, return failure.
	 */
	if (client->gabn.naddrs != 0)
		client->pkt.result = LWRES_R_SUCCESS;
	else
		client->pkt.result = LWRES_R_NOTFOUND;

	sort_addresses(client);

	lwres = lwres_gabnresponse_render(cm->lwctx, &client->gabn,
					  &client->pkt, &lwb);
	if (lwres != LWRES_R_SUCCESS)
		goto out;

	r.base = lwb.base;
	r.length = lwb.used;
	client->sendbuf = r.base;
	client->sendlength = r.length;
	result = ns_lwdclient_sendreply(client, &r);
	if (result != ISC_R_SUCCESS)
		goto out;

	NS_LWDCLIENT_SETSEND(client);

	/*
	 * All done!
	 */
	cleanup_gabn(client);

	return;

 out:
	cleanup_gabn(client);

	if (lwb.base != NULL)
		lwres_context_freemem(client->clientmgr->lwctx,
				      lwb.base, lwb.length);

	ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE);
}