Exemple #1
0
isc_result_t
bind9_getaddresses(const char *hostname, in_port_t port,
		   isc_sockaddr_t *addrs, int addrsize, int *addrcount)
{
	struct in_addr in4;
	struct in6_addr in6;
	isc_boolean_t have_ipv4, have_ipv6;
	int i;

#ifdef USE_GETADDRINFO
	struct addrinfo *ai = NULL, *tmpai, hints;
	int result;
#else
	struct hostent *he;
#endif

	REQUIRE(hostname != NULL);
	REQUIRE(addrs != NULL);
	REQUIRE(addrcount != NULL);
	REQUIRE(addrsize > 0);

	have_ipv4 = ISC_TF((isc_net_probeipv4() == ISC_R_SUCCESS));
	have_ipv6 = ISC_TF((isc_net_probeipv6() == ISC_R_SUCCESS));

	/*
	 * Try IPv4, then IPv6.  In order to handle the extended format
	 * for IPv6 scoped addresses (address%scope_ID), we'll use a local
	 * working buffer of 128 bytes.  The length is an ad-hoc value, but
	 * should be enough for this purpose; the buffer can contain a string
	 * of at least 80 bytes for scope_ID in addition to any IPv6 numeric
	 * addresses (up to 46 bytes), the delimiter character and the
	 * terminating NULL character.
	 */
	if (inet_pton(AF_INET, hostname, &in4) == 1) {
		if (have_ipv4)
			isc_sockaddr_fromin(&addrs[0], &in4, port);
		else
			isc_sockaddr_v6fromin(&addrs[0], &in4, port);
		*addrcount = 1;
		return (ISC_R_SUCCESS);
	} else if (strlen(hostname) <= 127U) {
		char tmpbuf[128], *d;
		isc_uint32_t zone = 0;

		strcpy(tmpbuf, hostname);
		d = strchr(tmpbuf, '%');
		if (d != NULL)
			*d = '\0';

		if (inet_pton(AF_INET6, tmpbuf, &in6) == 1) {
			isc_netaddr_t na;

			if (!have_ipv6)
				return (ISC_R_FAMILYNOSUPPORT);

			if (d != NULL) {
#ifdef ISC_PLATFORM_HAVESCOPEID
				isc_result_t result;

				result = isc_netscope_pton(AF_INET6, d + 1,
							   &in6, &zone);
				    
				if (result != ISC_R_SUCCESS)
					return (result);
#else
				/*
				 * The extended format is specified while the
				 * system does not provide the ability to use
				 * it.  Throw an explicit error instead of
				 * ignoring the specified value.
				 */
				return (ISC_R_BADADDRESSFORM);
#endif
			}

			isc_netaddr_fromin6(&na, &in6);
			isc_netaddr_setzone(&na, zone);
			isc_sockaddr_fromnetaddr(&addrs[0],
						 (const isc_netaddr_t *)&na,
						 port);

			*addrcount = 1;
			return (ISC_R_SUCCESS);
			
		}
	}
#ifdef USE_GETADDRINFO
	memset(&hints, 0, sizeof(hints));
	if (!have_ipv6)
		hints.ai_family = PF_INET;
	else if (!have_ipv4)
		hints.ai_family = PF_INET6;
	else {
		hints.ai_family = PF_UNSPEC;
#ifdef AI_ADDRCONFIG
		hints.ai_flags = AI_ADDRCONFIG;
#endif
	}
	hints.ai_socktype = SOCK_STREAM;
#ifdef AI_ADDRCONFIG
 again:
#endif
	result = getaddrinfo(hostname, NULL, &hints, &ai);
	switch (result) {
	case 0:
		break;
	case EAI_NONAME:
#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
	case EAI_NODATA:
#endif
		return (ISC_R_NOTFOUND);
#ifdef AI_ADDRCONFIG
	case EAI_BADFLAGS:
		if ((hints.ai_flags & AI_ADDRCONFIG) != 0) {
			hints.ai_flags &= ~AI_ADDRCONFIG;
			goto again;
		}
#endif
	default:
		return (ISC_R_FAILURE);
	}
	for (tmpai = ai, i = 0;
	     tmpai != NULL && i < addrsize;
	     tmpai = tmpai->ai_next)
	{
		if (tmpai->ai_family != AF_INET &&
		    tmpai->ai_family != AF_INET6)
			continue;
		if (tmpai->ai_family == AF_INET) {
			struct sockaddr_in *sin;
			sin = (struct sockaddr_in *)tmpai->ai_addr;
			isc_sockaddr_fromin(&addrs[i], &sin->sin_addr, port);
		} else {
			struct sockaddr_in6 *sin6;
			sin6 = (struct sockaddr_in6 *)tmpai->ai_addr;
			isc_sockaddr_fromin6(&addrs[i], &sin6->sin6_addr,
					     port);
		}
		i++;

	}
	freeaddrinfo(ai);
	*addrcount = i;
#else
	he = gethostbyname(hostname);
	if (he == NULL) {
		switch (h_errno) {
		case HOST_NOT_FOUND:
#ifdef NO_DATA
		case NO_DATA:
#endif
#if defined(NO_ADDRESS) && (!defined(NO_DATA) || (NO_DATA != NO_ADDRESS))
		case NO_ADDRESS:
#endif
			return (ISC_R_NOTFOUND);
		default:
			return (ISC_R_FAILURE);
		}
	}
	if (he->h_addrtype != AF_INET && he->h_addrtype != AF_INET6)
		return (ISC_R_NOTFOUND);
	for (i = 0; i < addrsize; i++) {
		if (he->h_addrtype == AF_INET) {
			struct in_addr *inp;
			inp = (struct in_addr *)(he->h_addr_list[i]);
			if (inp == NULL)
				break;
			isc_sockaddr_fromin(&addrs[i], inp, port);
		} else {
			struct in6_addr *in6p;
			in6p = (struct in6_addr *)(he->h_addr_list[i]);
			if (in6p == NULL)
				break;
			isc_sockaddr_fromin6(&addrs[i], in6p, port);
		}
	}
	*addrcount = i;
#endif
	if (*addrcount == 0)
		return (ISC_R_NOTFOUND);
	else
		return (ISC_R_SUCCESS);
}
Exemple #2
0
int
main(int argc, char *argv[]) {
	isc_task_t *t1, *t2;
	isc_timermgr_t *timgr;
	isc_time_t expires;
	isc_interval_t interval;
	isc_timer_t *ti1;
	unsigned int workers;
	isc_socketmgr_t *socketmgr;
	isc_socket_t *so1, *so2;
	isc_sockaddr_t sockaddr;
	struct in_addr ina;
	struct in6_addr in6a;
	isc_result_t result;
	int pf;

	if (argc > 1)
		workers = atoi(argv[1]);
	else
		workers = 2;
	printf("%d workers\n", workers);

	if (isc_net_probeipv6() == ISC_R_SUCCESS)
		pf = PF_INET6;
	else
		pf = PF_INET;

	/*
	 * EVERYTHING needs a memory context.
	 */
	mctx = NULL;
	RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);

	/*
	 * The task manager is independent (other than memory context)
	 */
	manager = NULL;
	RUNTIME_CHECK(isc_taskmgr_create(mctx, workers, 0, &manager) ==
		      ISC_R_SUCCESS);

	/*
	 * Timer manager depends only on the memory context as well.
	 */
	timgr = NULL;
	RUNTIME_CHECK(isc_timermgr_create(mctx, &timgr) == ISC_R_SUCCESS);

	t1 = NULL;
	RUNTIME_CHECK(isc_task_create(manager, 0, &t1) == ISC_R_SUCCESS);
	t2 = NULL;
	RUNTIME_CHECK(isc_task_create(manager, 0, &t2) == ISC_R_SUCCESS);
	RUNTIME_CHECK(isc_task_onshutdown(t1, my_shutdown, "1") ==
		      ISC_R_SUCCESS);
	RUNTIME_CHECK(isc_task_onshutdown(t2, my_shutdown, "2") ==
		      ISC_R_SUCCESS);

	printf("task 1 = %p\n", t1);
	printf("task 2 = %p\n", t2);

	socketmgr = NULL;
	RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS);

	/*
	 * Open up a listener socket.
	 */
	so1 = NULL;

	if (pf == PF_INET6) {
		in6a = in6addr_any;
		isc_sockaddr_fromin6(&sockaddr, &in6a, 5544);
	} else {
		ina.s_addr = INADDR_ANY;
		isc_sockaddr_fromin(&sockaddr, &ina, 5544);
	}
	RUNTIME_CHECK(isc_socket_create(socketmgr, pf, isc_sockettype_tcp,
					&so1) == ISC_R_SUCCESS);
	result = isc_socket_bind(so1, &sockaddr, ISC_SOCKET_REUSEADDRESS);
	RUNTIME_CHECK(result == ISC_R_SUCCESS);
	RUNTIME_CHECK(isc_socket_listen(so1, 0) == ISC_R_SUCCESS);

	/*
	 * Queue up the first accept event.
	 */
	RUNTIME_CHECK(isc_socket_accept(so1, t1, my_listen, "so1")
		      == ISC_R_SUCCESS);
	isc_time_settoepoch(&expires);
	isc_interval_set(&interval, 10, 0);
	ti1 = NULL;
	RUNTIME_CHECK(isc_timer_create(timgr, isc_timertype_once, &expires,
				       &interval, t1, timeout, so1, &ti1) ==
		      ISC_R_SUCCESS);

	/*
	 * Open up a socket that will connect to www.flame.org, port 80.
	 * Why not.  :)
	 */
	so2 = NULL;
	ina.s_addr = inet_addr("204.152.184.97");
	if (0 && pf == PF_INET6)
		isc_sockaddr_v6fromin(&sockaddr, &ina, 80);
	else
		isc_sockaddr_fromin(&sockaddr, &ina, 80);
	RUNTIME_CHECK(isc_socket_create(socketmgr, isc_sockaddr_pf(&sockaddr),
					isc_sockettype_tcp,
					&so2) == ISC_R_SUCCESS);

	RUNTIME_CHECK(isc_socket_connect(so2, &sockaddr, t2,
					 my_connect, "so2") == ISC_R_SUCCESS);

	/*
	 * Detaching these is safe, since the socket will attach to the
	 * task for any outstanding requests.
	 */
	isc_task_detach(&t1);
	isc_task_detach(&t2);

	/*
	 * Wait a short while.
	 */
	sleep(10);

	fprintf(stderr, "Destroying socket manager\n");
	isc_socketmgr_destroy(&socketmgr);

	fprintf(stderr, "Destroying timer manager\n");
	isc_timermgr_destroy(&timgr);

	fprintf(stderr, "Destroying task manager\n");
	isc_taskmgr_destroy(&manager);

	isc_mem_stats(mctx, stdout);
	isc_mem_destroy(&mctx);

	return (0);
}