Ejemplo n.º 1
0
static isc_result_t
linux_if_inet6_current(isc_interfaceiter_t *iter) {
	char address[33];
	char name[IF_NAMESIZE+1];
	struct in6_addr addr6;
	int ifindex, prefix, flag3, flag4;
	int res;
	unsigned int i;

	if (iter->valid != ISC_R_SUCCESS)
		return (iter->valid);
	if (iter->proc == NULL) {
		isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
			      ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
			      "/proc/net/if_inet6:iter->proc == NULL");
		return (ISC_R_FAILURE);
	}

	res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n",
		     address, &ifindex, &prefix, &flag3, &flag4, name);
	if (res != 6) {
		isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
			      ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
			      "/proc/net/if_inet6:sscanf() -> %d (expected 6)",
			      res);
		return (ISC_R_FAILURE);
	}
	if (strlen(address) != 32) {
		isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
			      ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
			      "/proc/net/if_inet6:strlen(%s) != 32", address);
		return (ISC_R_FAILURE);
	}
	for (i = 0; i < 16; i++) {
		unsigned char byte;
		static const char hex[] = "0123456789abcdef";
		byte = ((strchr(hex, address[i * 2]) - hex) << 4) |
		       (strchr(hex, address[i * 2 + 1]) - hex);
		addr6.s6_addr[i] = byte;
	}
	iter->current.af = AF_INET6;
	iter->current.flags = INTERFACE_F_UP;
	isc_netaddr_fromin6(&iter->current.address, &addr6);
	if (isc_netaddr_islinklocal(&iter->current.address)) {
		isc_netaddr_setzone(&iter->current.address,
				    (isc_uint32_t)ifindex);
	}
	for (i = 0; i < 16; i++) {
		if (prefix > 8) {
			addr6.s6_addr[i] = 0xff;
			prefix -= 8;
		} else {
			addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff;
			prefix = 0;
		}
	}
	isc_netaddr_fromin6(&iter->current.netmask, &addr6);
	strncpy(iter->current.name, name, sizeof(iter->current.name));
	return (ISC_R_SUCCESS);
}
Ejemplo n.º 2
0
static isc_result_t
do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
	isc_boolean_t verbose)
{
	isc_interfaceiter_t *iter = NULL;
	isc_boolean_t scan_ipv4 = ISC_FALSE;
	isc_boolean_t scan_ipv6 = ISC_FALSE;
	isc_boolean_t adjusting = ISC_FALSE;
	isc_boolean_t ipv6only = ISC_TRUE;
	isc_boolean_t ipv6pktinfo = ISC_TRUE;
	isc_result_t result;
	isc_netaddr_t zero_address, zero_address6;
	ns_listenelt_t *le;
	isc_sockaddr_t listen_addr;
	ns_interface_t *ifp;
	isc_boolean_t log_explicit = ISC_FALSE;
	isc_boolean_t dolistenon;

	if (ext_listen != NULL)
		adjusting = ISC_TRUE;

	if (isc_net_probeipv6() == ISC_R_SUCCESS)
		scan_ipv6 = ISC_TRUE;
#ifdef WANT_IPV6
	else
		isc_log_write(IFMGR_COMMON_LOGARGS,
			      verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
			      "no IPv6 interfaces found");
#endif

	if (isc_net_probeipv4() == ISC_R_SUCCESS)
		scan_ipv4 = ISC_TRUE;
	else
		isc_log_write(IFMGR_COMMON_LOGARGS,
			      verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
			      "no IPv4 interfaces found");

	/*
	 * A special, but typical case; listen-on-v6 { any; }.
	 * When we can make the socket IPv6-only, open a single wildcard
	 * socket for IPv6 communication.  Otherwise, make separate socket
	 * for each IPv6 address in order to avoid accepting IPv4 packets
	 * as the form of mapped addresses unintentionally unless explicitly
	 * allowed.
	 */
#ifndef ISC_ALLOW_MAPPED
	if (scan_ipv6 == ISC_TRUE &&
	    isc_net_probe_ipv6only() != ISC_R_SUCCESS) {
		ipv6only = ISC_FALSE;
		log_explicit = ISC_TRUE;
	}
#endif
	if (scan_ipv6 == ISC_TRUE &&
	    isc_net_probe_ipv6pktinfo() != ISC_R_SUCCESS) {
		ipv6pktinfo = ISC_FALSE;
		log_explicit = ISC_TRUE;
	}
	if (scan_ipv6 == ISC_TRUE && ipv6only && ipv6pktinfo) {
		for (le = ISC_LIST_HEAD(mgr->listenon6->elts);
		     le != NULL;
		     le = ISC_LIST_NEXT(le, link)) {
			struct in6_addr in6a;

			if (!listenon_is_ip6_any(le))
				continue;

			in6a = in6addr_any;
			isc_sockaddr_fromin6(&listen_addr, &in6a, le->port);

			ifp = find_matching_interface(mgr, &listen_addr);
			if (ifp != NULL) {
				ifp->generation = mgr->generation;
			} else {
				isc_log_write(IFMGR_COMMON_LOGARGS,
					      ISC_LOG_INFO,
					      "listening on IPv6 "
					      "interfaces, port %u",
					      le->port);
				result = ns_interface_setup(mgr, &listen_addr,
							    "<any>", &ifp,
							    ISC_TRUE);
				if (result == ISC_R_SUCCESS)
					ifp->flags |= NS_INTERFACEFLAG_ANYADDR;
				else
					isc_log_write(IFMGR_COMMON_LOGARGS,
						      ISC_LOG_ERROR,
						      "listening on all IPv6 "
						      "interfaces failed");
				/* Continue. */
			}
		}
	}

	isc_netaddr_any(&zero_address);
	isc_netaddr_any6(&zero_address6);

	result = isc_interfaceiter_create(mgr->mctx, &iter);
	if (result != ISC_R_SUCCESS)
		return (result);

	if (adjusting == ISC_FALSE) {
		result = clearacl(mgr->mctx, &mgr->aclenv.localhost);
		if (result != ISC_R_SUCCESS)
			goto cleanup_iter;
		result = clearacl(mgr->mctx, &mgr->aclenv.localnets);
		if (result != ISC_R_SUCCESS)
			goto cleanup_iter;
		clearlistenon(mgr);
	}

	for (result = isc_interfaceiter_first(iter);
	     result == ISC_R_SUCCESS;
	     result = isc_interfaceiter_next(iter))
	{
		isc_interface_t interface;
		ns_listenlist_t *ll;
		unsigned int family;

		result = isc_interfaceiter_current(iter, &interface);
		if (result != ISC_R_SUCCESS)
			break;

		family = interface.address.family;
		if (family != AF_INET && family != AF_INET6)
			continue;
		if (scan_ipv4 == ISC_FALSE && family == AF_INET)
			continue;
		if (scan_ipv6 == ISC_FALSE && family == AF_INET6)
			continue;

		/*
		 * Test for the address being nonzero rather than testing
		 * INTERFACE_F_UP, because on some systems the latter
		 * follows the media state and we could end up ignoring
		 * the interface for an entire rescan interval due to
		 * a temporary media glitch at rescan time.
		 */
		if (family == AF_INET &&
		    isc_netaddr_equal(&interface.address, &zero_address)) {
			continue;
		}
		if (family == AF_INET6 &&
		    isc_netaddr_equal(&interface.address, &zero_address6)) {
			continue;
		}

		if (adjusting == ISC_FALSE) {
			result = setup_locals(mgr, &interface);
			if (result != ISC_R_SUCCESS)
				goto ignore_interface;
		}

		ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6;
		dolistenon = ISC_TRUE;
		for (le = ISC_LIST_HEAD(ll->elts);
		     le != NULL;
		     le = ISC_LIST_NEXT(le, link))
		{
			int match;
			isc_boolean_t ipv6_wildcard = ISC_FALSE;
			isc_netaddr_t listen_netaddr;
			isc_sockaddr_t listen_sockaddr;

			/*
			 * Construct a socket address for this IP/port
			 * combination.
			 */
			if (family == AF_INET) {
				isc_netaddr_fromin(&listen_netaddr,
						   &interface.address.type.in);
			} else {
				isc_netaddr_fromin6(&listen_netaddr,
						    &interface.address.type.in6);
				isc_netaddr_setzone(&listen_netaddr,
						    interface.address.zone);
			}
			isc_sockaddr_fromnetaddr(&listen_sockaddr,
						 &listen_netaddr,
						 le->port);

			/*
			 * See if the address matches the listen-on statement;
			 * if not, ignore the interface.
			 */
			(void)dns_acl_match(&listen_netaddr, NULL, le->acl,
					    &mgr->aclenv, &match, NULL);
			if (match <= 0)
				continue;

			if (adjusting == ISC_FALSE && dolistenon == ISC_TRUE) {
				setup_listenon(mgr, &interface, le->port);
				dolistenon = ISC_FALSE;
			}

			/*
			 * The case of "any" IPv6 address will require
			 * special considerations later, so remember it.
			 */
			if (family == AF_INET6 && ipv6only && ipv6pktinfo &&
			    listenon_is_ip6_any(le))
				ipv6_wildcard = ISC_TRUE;

			/*
			 * When adjusting interfaces with extra a listening
			 * list, see if the address matches the extra list.
			 * If it does, and is also covered by a wildcard
			 * interface, we need to listen on the address
			 * explicitly.
			 */
			if (adjusting == ISC_TRUE) {
				ns_listenelt_t *ele;

				match = 0;
				for (ele = ISC_LIST_HEAD(ext_listen->elts);
				     ele != NULL;
				     ele = ISC_LIST_NEXT(ele, link)) {
					(void)dns_acl_match(&listen_netaddr,
							    NULL, ele->acl,
							    NULL, &match, NULL);
					if (match > 0 &&
					    (ele->port == le->port ||
					    ele->port == 0))
						break;
					else
						match = 0;
				}
				if (ipv6_wildcard == ISC_TRUE && match == 0)
					continue;
			}

			ifp = find_matching_interface(mgr, &listen_sockaddr);
			if (ifp != NULL) {
				ifp->generation = mgr->generation;
			} else {
				char sabuf[ISC_SOCKADDR_FORMATSIZE];

				if (adjusting == ISC_FALSE &&
				    ipv6_wildcard == ISC_TRUE)
					continue;

				if (log_explicit && family == AF_INET6 &&
				    !adjusting && listenon_is_ip6_any(le)) {
					isc_log_write(IFMGR_COMMON_LOGARGS,
						      verbose ? ISC_LOG_INFO :
							      ISC_LOG_DEBUG(1),
						      "IPv6 socket API is "
						      "incomplete; explicitly "
						      "binding to each IPv6 "
						      "address separately");
					log_explicit = ISC_FALSE;
				}
				isc_sockaddr_format(&listen_sockaddr,
						    sabuf, sizeof(sabuf));
				isc_log_write(IFMGR_COMMON_LOGARGS,
					      ISC_LOG_INFO,
					      "%s"
					      "listening on %s interface "
					      "%s, %s",
					      (adjusting == ISC_TRUE) ?
					      "additionally " : "",
					      (family == AF_INET) ?
					      "IPv4" : "IPv6",
					      interface.name, sabuf);

				result = ns_interface_setup(mgr,
							    &listen_sockaddr,
							    interface.name,
							    &ifp,
							    (adjusting == ISC_TRUE) ?
							    ISC_FALSE :
							    ISC_TRUE);

				if (result != ISC_R_SUCCESS) {
					isc_log_write(IFMGR_COMMON_LOGARGS,
						      ISC_LOG_ERROR,
						      "creating %s interface "
						      "%s failed; interface "
						      "ignored",
						      (family == AF_INET) ?
						      "IPv4" : "IPv6",
						      interface.name);
				}
				/* Continue. */
			}

		}
		continue;

	ignore_interface:
		isc_log_write(IFMGR_COMMON_LOGARGS,
			      ISC_LOG_ERROR,
			      "ignoring %s interface %s: %s",
			      (family == AF_INET) ? "IPv4" : "IPv6",
			      interface.name, isc_result_totext(result));
		continue;
	}
	if (result != ISC_R_NOMORE)
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "interface iteration failed: %s",
				 isc_result_totext(result));
	else
		result = ISC_R_SUCCESS;
 cleanup_iter:
	isc_interfaceiter_destroy(&iter);
	return (result);
}
Ejemplo n.º 3
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);
}
Ejemplo n.º 4
0
static isc_result_t
internal_current6(isc_interfaceiter_t *iter) {
	struct LIFREQ *ifrp;
	struct LIFREQ lifreq;
	int family;
	char strbuf[ISC_STRERRORSIZE];
	int fd;

	REQUIRE(VALID_IFITER(iter));
	if (iter->result6 != ISC_R_SUCCESS)
		return (iter->result6);
	REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);

	ifrp = (void *)((char *)iter->lifc.lifc_req + iter->pos6);

	memset(&lifreq, 0, sizeof(lifreq));
	memcpy(&lifreq, ifrp, sizeof(lifreq));

	family = lifreq.lifr_addr.ss_family;
#ifdef ISC_PLATFORM_HAVEIPV6
	if (family != AF_INET && family != AF_INET6)
#else
	if (family != AF_INET)
#endif
		return (ISC_R_IGNORE);

	memset(&iter->current, 0, sizeof(iter->current));
	iter->current.af = family;

	INSIST(sizeof(lifreq.lifr_name) <= sizeof(iter->current.name));
	memset(iter->current.name, 0, sizeof(iter->current.name));
	memcpy(iter->current.name, lifreq.lifr_name, sizeof(lifreq.lifr_name));

	get_addr(family, &iter->current.address,
		 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);

	if (isc_netaddr_islinklocal(&iter->current.address))
		isc_netaddr_setzone(&iter->current.address, 
				    (isc_uint32_t)lifreq.lifr_index);

	/*
	 * If the interface does not have a address ignore it.
	 */
	switch (family) {
	case AF_INET:
		if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
			return (ISC_R_IGNORE);
		break;
	case AF_INET6:
		if (memcmp(&iter->current.address.type.in6, &in6addr_any,
			   sizeof(in6addr_any)) == 0)
			return (ISC_R_IGNORE);
		break;
	}

	/*
	 * Get interface flags.
	 */

	iter->current.flags = 0;

	if (family == AF_INET6)
		fd = iter->socket6;
	else
		fd = iter->socket;

	/*
	 * Ignore the HP/UX warning about "integer overflow during
	 * conversion.  It comes from its own macro definition,
	 * and is really hard to shut up.
	 */
	if (isc_ioctl(fd, SIOCGLIFFLAGS, (char *) &lifreq) < 0) {
		isc__strerror(errno, strbuf, sizeof(strbuf));
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "%s: getting interface flags: %s",
				 lifreq.lifr_name, strbuf);
		return (ISC_R_IGNORE);
	}

	if ((lifreq.lifr_flags & IFF_UP) != 0)
		iter->current.flags |= INTERFACE_F_UP;

#ifdef IFF_POINTOPOINT
	if ((lifreq.lifr_flags & IFF_POINTOPOINT) != 0)
		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
#endif

	if ((lifreq.lifr_flags & IFF_LOOPBACK) != 0)
		iter->current.flags |= INTERFACE_F_LOOPBACK;

	if ((lifreq.lifr_flags & IFF_BROADCAST) != 0) {
		iter->current.flags |= INTERFACE_F_BROADCAST;
	}

#ifdef IFF_MULTICAST
	if ((lifreq.lifr_flags & IFF_MULTICAST) != 0) {
		iter->current.flags |= INTERFACE_F_MULTICAST;
	}
#endif

#ifdef IFF_POINTOPOINT
	/*
	 * If the interface is point-to-point, get the destination address.
	 */
	if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
		/*
		 * Ignore the HP/UX warning about "integer overflow during
		 * conversion.  It comes from its own macro definition,
		 * and is really hard to shut up.
		 */
		if (isc_ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifreq)
		    < 0) {
			isc__strerror(errno, strbuf, sizeof(strbuf));
			UNEXPECTED_ERROR(__FILE__, __LINE__,
				isc_msgcat_get(isc_msgcat,
					       ISC_MSGSET_IFITERIOCTL,
					       ISC_MSG_GETDESTADDR,
					       "%s: getting "
					       "destination address: %s"),
					 lifreq.lifr_name, strbuf);
			return (ISC_R_IGNORE);
		}
		get_addr(family, &iter->current.dstaddress,
			 (struct sockaddr *)&lifreq.lifr_dstaddr,
			 lifreq.lifr_name);
	}
#endif

#ifdef SIOCGLIFBRDADDR
	if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) {
		/*
		 * Ignore the HP/UX warning about "integer overflow during
		 * conversion.  It comes from its own macro definition,
		 * and is really hard to shut up.
		 */
		if (isc_ioctl(iter->socket, SIOCGLIFBRDADDR, (char *)&lifreq)
		    < 0) {
			isc__strerror(errno, strbuf, sizeof(strbuf));
			UNEXPECTED_ERROR(__FILE__, __LINE__,
				isc_msgcat_get(isc_msgcat,
					       ISC_MSGSET_IFITERIOCTL,
					       ISC_MSG_GETBCSTADDR,
					       "%s: getting "
					       "broadcast address: %s"),
					 lifreq.lifr_name, strbuf);
			return (ISC_R_IGNORE);
		}
		get_addr(family, &iter->current.broadcast,
			 (struct sockaddr *)&lifreq.lifr_broadaddr,
			 lifreq.lifr_name);
	}
#endif	/* SIOCGLIFBRDADDR */

	/*
	 * Get the network mask.  Netmask already zeroed.
	 */
	memset(&lifreq, 0, sizeof(lifreq));
	memcpy(&lifreq, ifrp, sizeof(lifreq));

#ifdef lifr_addrlen
	/*
	 * Special case: if the system provides lifr_addrlen member, the
	 * netmask of an IPv6 address can be derived from the length, since
	 * an IPv6 address always has a contiguous mask.
	 */
	if (family == AF_INET6) {
		int i, bits;

		iter->current.netmask.family = family;
		for (i = 0; i < lifreq.lifr_addrlen; i += 8) {
			bits = lifreq.lifr_addrlen - i;
			bits = (bits < 8) ? (8 - bits) : 0;
			iter->current.netmask.type.in6.s6_addr[i / 8] =
				(~0 << bits) & 0xff;
		}
#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
		iter->current.ifindex = if_nametoindex(iter->current.name);
#endif
		return (ISC_R_SUCCESS);
	}
#endif

	/*
	 * Ignore the HP/UX warning about "integer overflow during
	 * conversion.  It comes from its own macro definition,
	 * and is really hard to shut up.
	 */
	if (isc_ioctl(fd, SIOCGLIFNETMASK, (char *)&lifreq) < 0) {
		isc__strerror(errno, strbuf, sizeof(strbuf));
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 isc_msgcat_get(isc_msgcat,
						ISC_MSGSET_IFITERIOCTL,
						ISC_MSG_GETNETMASK,
						"%s: getting netmask: %s"),
				 lifreq.lifr_name, strbuf);
		return (ISC_R_IGNORE);
	}
	get_addr(family, &iter->current.netmask,
		 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);

#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
	iter->current.ifindex = if_nametoindex(iter->current.name);
#endif
	return (ISC_R_SUCCESS);
}
Ejemplo n.º 5
0
static isc_result_t
linux_if_inet6_current(isc_interfaceiter_t *iter) {
	char address[33];
	char name[IF_NAMESIZE+1];
	char strbuf[ISC_STRERRORSIZE];
	struct in6_addr addr6;
	struct ifreq ifreq;
	int ifindex, prefix, scope, flags;
	int res;
	unsigned int i;

	if (iter->valid != ISC_R_SUCCESS)
		return (iter->valid);
	if (iter->proc == NULL) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
			      "/proc/net/if_inet6:iter->proc == NULL");
		return (ISC_R_FAILURE);
	}

	/*
	 * Format for /proc/net/if_inet6:
	 * (see iface_proc_info() in net/ipv6/addrconf.c)
	 * <addr6:32> <ifindex:2> <prefix:2> <scope:2> <flags:2> <name:8>
	 */
	res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n",
		     address, &ifindex, &prefix, &scope, &flags, name);
	if (res != 6) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
			      "/proc/net/if_inet6:sscanf() -> %d (expected 6)",
			      res);
		return (ISC_R_FAILURE);
	}
	if (strlen(address) != 32) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
			      "/proc/net/if_inet6:strlen(%s) != 32", address);
		return (ISC_R_FAILURE);
	}
	for (i = 0; i < 16; i++) {
		unsigned char byte;
		static const char hex[] = "0123456789abcdef";
		byte = ((index(hex, address[i * 2]) - hex) << 4) |
		       (index(hex, address[i * 2 + 1]) - hex);
		addr6.s6_addr[i] = byte;
	}
	iter->current.af = AF_INET6;
	/* iter->current.ifindex = ifindex; */
	iter->current.flags = 0;

	memset(&ifreq, 0, sizeof(ifreq));
	INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
	strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));

	if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
		isc__strerror(errno, strbuf, sizeof(strbuf));
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "%s: getting interface flags: %s",
				 ifreq.ifr_name, strbuf);
		return (ISC_R_IGNORE);
	}

	if ((ifreq.ifr_flags & IFF_UP) != 0)
		iter->current.flags |= INTERFACE_F_UP;
#ifdef IFF_POINTOPOINT
	if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0) 
		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
#endif
	if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
		iter->current.flags |= INTERFACE_F_LOOPBACK;
	if ((ifreq.ifr_flags & IFF_BROADCAST) != 0)
		iter->current.flags |= INTERFACE_F_BROADCAST;
#ifdef IFF_MULTICAST
	if ((ifreq.ifr_flags & IFF_MULTICAST) != 0)
		iter->current.flags |= INTERFACE_F_MULTICAST;
#endif

	/*
	 * enable_multicast_if() requires scopeid for setsockopt,
	 * so associate address with their corresponding ifindex.
	 */
	isc_netaddr_fromin6(&iter->current.address, &addr6);
	isc_netaddr_setzone(&iter->current.address, (isc_uint32_t)ifindex);

	for (i = 0; i < 16; i++) {
		if (prefix > 8) {
			addr6.s6_addr[i] = 0xff;
			prefix -= 8;
		} else {
			addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff;
			prefix = 0;
		}
	}
	isc_netaddr_fromin6(&iter->current.netmask, &addr6);
	strncpy(iter->current.name, name, sizeof(iter->current.name));
	return (ISC_R_SUCCESS);
}
Ejemplo n.º 6
0
static void
get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src,
	 char *ifname)
{
	struct sockaddr_in6 *sa6;

#if !defined(ISC_PLATFORM_HAVEIFNAMETOINDEX) || \
    !defined(ISC_PLATFORM_HAVESCOPEID)
	UNUSED(ifname);
#endif

	/* clear any remaining value for safety */
	memset(dst, 0, sizeof(*dst));

	dst->family = family;
	switch (family) {
	case AF_INET:
		memcpy(&dst->type.in,
		       &((struct sockaddr_in *) src)->sin_addr,
		       sizeof(struct in_addr));
		break;
	case AF_INET6:
		sa6 = (struct sockaddr_in6 *)src;
		memcpy(&dst->type.in6, &sa6->sin6_addr,
		       sizeof(struct in6_addr));
#ifdef ISC_PLATFORM_HAVESCOPEID
		if (sa6->sin6_scope_id != 0)
			isc_netaddr_setzone(dst, sa6->sin6_scope_id);
		else {
			/*
			 * BSD variants embed scope zone IDs in the 128bit
			 * address as a kernel internal form.  Unfortunately,
			 * the embedded IDs are not hidden from applications
			 * when getting access to them by sysctl or ioctl.
			 * We convert the internal format to the pure address
			 * part and the zone ID part.
			 * Since multicast addresses should not appear here
			 * and they cannot be distinguished from netmasks,
			 * we only consider unicast link-local addresses.
			 */
			if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
				isc_uint16_t zone16;

				memcpy(&zone16, &sa6->sin6_addr.s6_addr[2],
				       sizeof(zone16));
				zone16 = ntohs(zone16);
				if (zone16 != 0) {
					/* the zone ID is embedded */
					isc_netaddr_setzone(dst,
							    (isc_uint32_t)zone16);
					dst->type.in6.s6_addr[2] = 0;
					dst->type.in6.s6_addr[3] = 0;
#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
				} else if (ifname != NULL) {
					unsigned int zone;

					/*
					 * sin6_scope_id is still not provided,
					 * but the corresponding interface name
					 * is know.  Use the interface ID as
					 * the link ID.
					 */
					zone = if_nametoindex(ifname);
					if (zone != 0) {
						isc_netaddr_setzone(dst,
								    (isc_uint32_t)zone);
					}
#endif
				}
			}
		}
#endif
		break;
	default:
		INSIST(0);
		break;
	}
}