/** * Tries to convert the host address "from" to the network type "to_net" * and stores the converted address in "*to". If conversion is not possible, * FALSE is returned and "*to" is set to zero_host_addr. * * @param from The address to convert. * @param to Will hold the converted address. * @param to_net The network type to convert the address to. * * @return TRUE if the address could be converted, FALSE otherwise. */ bool host_addr_convert(const host_addr_t from, host_addr_t *to, enum net_type to_net) { if (from.net == to_net) { *to = from; return TRUE; } switch (to_net) { case NET_TYPE_IPV4: switch (from.net) { case NET_TYPE_IPV6: if (host_addr_can_convert(from, NET_TYPE_IPV4)) { *to = host_addr_peek_ipv4(&from.addr.ipv6[12]); return TRUE; } break; case NET_TYPE_LOCAL: case NET_TYPE_NONE: break; } break; case NET_TYPE_IPV6: switch (from.net) { case NET_TYPE_IPV4: to->net = to_net; memset(to->addr.ipv6, 0, 10); to->addr.ipv6[10] = 0xff; to->addr.ipv6[11] = 0xff; poke_be32(&to->addr.ipv6[12], host_addr_ipv4(from)); return TRUE; case NET_TYPE_NONE: break; } break; case NET_TYPE_LOCAL: case NET_TYPE_NONE: break; } *to = zero_host_addr; return FALSE; }
/** * 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; }
/** * 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 */ }