Пример #1
0
/**
 * Check whether hosts are "equivalent", modulo conversion to IPv4 for IPv6.
 *
 * @attention
 * This routine CANNOT be used directly or indirectly as a comparison function
 * for hash tables because it's not possible to have two items being "equal"
 * that do not hash to the same value!  For hash tables, use host_addr_equal()
 * which tests true equality.
 */
bool
host_addr_equiv(const host_addr_t a, const host_addr_t b)
{
	if (a.net == b.net) {
		switch (a.net) {
		case NET_TYPE_IPV4:
			return host_addr_ipv4(a) == host_addr_ipv4(b);
		case NET_TYPE_IPV6:
			if (0 != memcmp(a.addr.ipv6, b.addr.ipv6, sizeof a.addr.ipv6)) {
				host_addr_t a_ipv4, b_ipv4;

				return host_addr_convert(a, &a_ipv4, NET_TYPE_IPV4) &&
					host_addr_convert(b, &b_ipv4, NET_TYPE_IPV4) &&
					host_addr_ipv4(a_ipv4) == host_addr_ipv4(b_ipv4);
			}
			return TRUE;

		case NET_TYPE_LOCAL:
		case NET_TYPE_NONE:
			return TRUE;
		}
		g_assert_not_reached();
	} else {
		host_addr_t to;

		return host_addr_convert(a, &to, b.net) && host_addr_equiv(to, b);
	}
	return FALSE;
}
Пример #2
0
/**
 * Check whether host can be reached from the Internet.
 * We rule out IPs of private networks, plus some other invalid combinations.
 */
bool
host_addr_is_routable(const host_addr_t addr)
{
	host_addr_t ha;

	if (!is_host_addr(addr) || is_private_addr(addr))
		return FALSE;

	if (!host_addr_convert(addr, &ha, NET_TYPE_IPV4))
		ha = addr;

	switch (host_addr_net(ha)) {
	case NET_TYPE_IPV4:
		return ipv4_addr_is_routable(host_addr_ipv4(ha));

	case NET_TYPE_IPV6:
		return 	!host_addr_matches(ha, ipv6_unspecified, 8) &&
				!host_addr_matches(ha, ipv6_multicast, 8) &&
				!host_addr_matches(ha, ipv6_site_local, 10) &&
				!host_addr_matches(ha, ipv6_link_local, 10) &&
				!(
						host_addr_is_tunneled(ha) &&
						!ipv4_addr_is_routable(host_addr_tunnel_client_ipv4(ha))
				);

	case NET_TYPE_LOCAL:
	case NET_TYPE_NONE:
		return FALSE;
	}

	g_assert_not_reached();
	return FALSE;
}
Пример #3
0
/**
 * Retrieve value associated with an IP address, i.e. that of the range
 * containing it.
 *
 * @param db	the IP range database
 * @param ha	the IP address to lookup
 *
 * @return The data associated with the IP address or 0 if not found.
 */
uint16
iprange_get_addr(const struct iprange_db *idb, const host_addr_t ha)
{
	host_addr_t to;

	if (
		host_addr_convert(ha, &to, NET_TYPE_IPV4) ||
		host_addr_tunnel_client(ha, &to)
	) {
		return iprange_get(idb, host_addr_ipv4(to));
	} else if (host_addr_is_ipv6(ha)) {
		return iprange_get6(idb, host_addr_ipv6(&ha));
	}
	return 0;
}
Пример #4
0
/**
 * Checks for RFC1918 private addresses but also IPv6 link-local and site-local
 * addresses.
 *
 * @return TRUE if is a private address.
 */
bool
is_private_addr(const host_addr_t addr)
{
	host_addr_t addr_ipv4;

	if (host_addr_convert(addr, &addr_ipv4, NET_TYPE_IPV4)) {
		uint32 ip = host_addr_ipv4(addr_ipv4);

		/* 10.0.0.0 -- (10/8 prefix) */
		if ((ip & 0xff000000) == 0xa000000)
			return TRUE;

		/* 172.16.0.0 -- (172.16/12 prefix) */
		if ((ip & 0xfff00000) == 0xac100000)
			return TRUE;

		/* 169.254.0.0 -- (169.254/16 prefix) -- since Jan 2001 */
		if ((ip & 0xffff0000) == 0xa9fe0000)
			return TRUE;

		/* 192.168.0.0 -- (192.168/16 prefix) */
		if ((ip & 0xffff0000) == 0xc0a80000)
			return TRUE;
	} else {

		switch (host_addr_net(addr)) {
		case NET_TYPE_IPV4:
			g_assert_not_reached();
		case NET_TYPE_IPV6:
			return	host_addr_equal(addr, ipv6_loopback) ||
					host_addr_matches(addr, ipv6_link_local, 10) ||
					host_addr_matches(addr, ipv6_site_local, 10);
		case NET_TYPE_LOCAL:
			return TRUE;
		case NET_TYPE_NONE:
			break;
		}
	}
	return FALSE;
}
Пример #5
0
/**
 * Alternate hashing of host_addr_t.
 */
unsigned
host_addr_hash2(host_addr_t ha)
{
	switch (ha.net) {
	case NET_TYPE_IPV6:
		{
			host_addr_t ha_ipv4;

			if (!host_addr_convert(ha, &ha_ipv4, NET_TYPE_IPV4))
				return binary_hash2(&ha.addr.ipv6[0], sizeof ha.addr.ipv6);
			ha = ha_ipv4;
		}
		/* FALL THROUGH */
	case NET_TYPE_IPV4:
		return ha.net ^ integer_hash2(host_addr_ipv4(ha));
	case NET_TYPE_LOCAL:
	case NET_TYPE_NONE:
		return ha.net;
	}
	g_assert_not_reached();
	return (unsigned) -1;
}
Пример #6
0
/**
 * Checks whether the given address is 127.0.0.1 or ::1.
 */
bool
host_addr_is_loopback(const host_addr_t addr)
{
	host_addr_t ha;
	
	if (!host_addr_convert(addr, &ha, NET_TYPE_IPV4))
		ha = addr;
	
	switch (host_addr_net(ha)) {
	case NET_TYPE_IPV4:
		return host_addr_ipv4(ha) == 0x7f000001; /* 127.0.0.1 in host endian */

	case NET_TYPE_IPV6:
		return host_addr_equal(ha, ipv6_loopback);

	case NET_TYPE_LOCAL:
	case NET_TYPE_NONE:
		break;
	}

	g_assert_not_reached();
	return FALSE;
}
Пример #7
0
/**
 * Hashing of host_addr_t + port.
 */
unsigned
host_addr_port_hash(host_addr_t ha, uint16 port)
{
	switch (ha.net) {
	case NET_TYPE_IPV6:
		{
			host_addr_t ha_ipv4;

			if (!host_addr_convert(ha, &ha_ipv4, NET_TYPE_IPV4))
				return binary_hash(&ha.addr.ipv6[0], sizeof ha.addr.ipv6);
			ha = ha_ipv4;
		}
		/* FALL THROUGH */
	case NET_TYPE_IPV4:
		return hashing_mix32(
			ha.net + integer_hash_fast(host_addr_ipv4(ha)) + u16_hash(port));
	case NET_TYPE_LOCAL:
	case NET_TYPE_NONE:
		return hashing_mix32(ha.net + u16_hash(port));
	}
	g_assert_not_reached();
	return (unsigned) -1;
}
Пример #8
0
/**
 * Mask out given address, clearing the trailing v4 or v6 bits, depending
 * on the address type.
 *
 * @param addr		the address to mask out
 * @param v4		amount of trailing bits to mask out for IPv4 address
 * @param v6		amount of trailing bits to mask out for IPv6 address
 *
 * @return masked out address, possibly converted from IPv6 to IPv4.
 */
host_addr_t
host_addr_mask_net(host_addr_t addr, int v4, int v6)
{
	host_addr_t masked = addr;

	g_assert(v4 >= 0 && v4 <= 32);
	g_assert(v6 >= 0 && v6 <= 128);

	if (host_addr_can_convert(addr, NET_TYPE_IPV4))
		(void) host_addr_convert(addr, &masked, NET_TYPE_IPV4);

	switch (host_addr_net(addr)) {
	case NET_TYPE_IPV4:
		if (32 == v4)
			masked.addr.ipv4 = 0;
		else
			masked.addr.ipv4 &= ~((1U << v4) - 1);
		break;
	case NET_TYPE_IPV6:
		{
			int bytes = v6 / 8;			/* Amount of trailing bytes to clear */
			int bits = v6 % 8;			/* Trailing bits in upper byte */
			int i;

			for (i = 0; i < bytes; i++) {
				masked.addr.ipv6[15 - i] = 0;
			}
			masked.addr.ipv6[15 - bytes] &= ~((1U << bits) - 1);
		}
		break;
	case NET_TYPE_LOCAL:
	case NET_TYPE_NONE:
		break;
	}

	return masked;
}
Пример #9
0
/**
 * Resolves an IP address to a hostname per DNS.
 *
 * @param ha	The host address to resolve.
 * @return		On success, the hostname is returned. Otherwise, NULL is
 *				returned. The resulting string points to a static buffer.
 */
const char *
host_addr_to_name(host_addr_t addr)
{
	socket_addr_t sa;

	if (host_addr_can_convert(addr, NET_TYPE_IPV4)) {
		(void) host_addr_convert(addr, &addr, NET_TYPE_IPV4);
	}
	if (0 == socket_addr_set(&sa, addr, 0)) {
		return NULL;
	}

#ifdef HAS_GETNAMEINFO
	{
		static char host[1025];
		int error;

		error = getnameinfo(socket_addr_get_const_sockaddr(&sa),
					socket_addr_get_len(&sa), host, sizeof host, NULL, 0, 0);
		if (error) {
			char buf[HOST_ADDR_BUFLEN];

			host_addr_to_string_buf(addr, buf, sizeof buf);
			g_message("getnameinfo() failed for \"%s\": %s",
				buf, gai_strerror(error));
			return NULL;
		}
		return host;
	}
#else	/* !HAS_GETNAMEINFO */
	{
		const struct hostent *he;
		socklen_t len = 0;
		const char *ptr = NULL;

		switch (host_addr_net(addr)) {
		case NET_TYPE_IPV4:
			ptr = cast_to_gchar_ptr(&sa.inet4.sin_addr);
			len = sizeof sa.inet4.sin_addr;
			break;
		case NET_TYPE_IPV6:
#ifdef HAS_IPV6
			ptr = cast_to_gchar_ptr(&sa.inet6.sin6_addr);
			len = sizeof sa.inet6.sin6_addr;
			break;
#endif /* HAS_IPV6 */
		case NET_TYPE_LOCAL:
		case NET_TYPE_NONE:
			return NULL;
		}
		g_return_val_if_fail(ptr, NULL);
		g_return_val_if_fail(0 != len, NULL);

		he = gethostbyaddr(ptr, len, socket_addr_get_family(&sa));
		if (!he) {
			char buf[HOST_ADDR_BUFLEN];

			host_addr_to_string_buf(addr, buf, sizeof buf);
			gethostbyname_error(buf);
			return NULL;
		}
		return he->h_name;
	}
#endif	/* HAS_GETNAMEINFO */
}