+#ifdef HAVE_GETADDRINFO
+/*********************************************************************
+ *
+ * Function : sockaddr_storage_to_ip
+ *
+ * Description : Access internal structure of sockaddr_storage
+ *
+ * Parameters :
+ * 1 : addr = socket address
+ * 2 : ip = IP address as array of octets in network order
+ * (it points into addr)
+ * 3 : len = length of IP address in octets
+ * 4 : port = port number in network order;
+ *
+ * Returns : 0 = no errror; -1 otherwise.
+ *
+ *********************************************************************/
+int sockaddr_storage_to_ip(const struct sockaddr_storage *addr, uint8_t **ip,
+ unsigned int *len, in_port_t **port)
+{
+ if (NULL == addr)
+ {
+ return(-1);
+ }
+
+ switch (addr->ss_family)
+ {
+ case AF_INET:
+ if (NULL != len)
+ {
+ *len = 4;
+ }
+ if (NULL != ip)
+ {
+ *ip = (uint8_t *)
+ &(((struct sockaddr_in *)addr)->sin_addr.s_addr);
+ }
+ if (NULL != port)
+ {
+ *port = &((struct sockaddr_in *)addr)->sin_port;
+ }
+ break;
+
+ case AF_INET6:
+ if (NULL != len)
+ {
+ *len = 16;
+ }
+ if (NULL != ip)
+ {
+ *ip = ((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr;
+ }
+ if (NULL != port)
+ {
+ *port = &((struct sockaddr_in6 *)addr)->sin6_port;
+ }
+ break;
+
+ default:
+ /* Unsupported address family */
+ return(-1);
+ }
+
+ return(0);
+}
+
+
+/*********************************************************************
+ *
+ * Function : match_sockaddr
+ *
+ * Description : Check whether address matches network (IP address and port)
+ *
+ * Parameters :
+ * 1 : network = socket address of subnework
+ * 2 : netmask = network mask as socket address
+ * 3 : address = checked socket address against given network
+ *
+ * Returns : 0 = doesn't match; 1 = does match
+ *
+ *********************************************************************/
+int match_sockaddr(const struct sockaddr_storage *network,
+ const struct sockaddr_storage *netmask,
+ const struct sockaddr_storage *address)
+{
+ uint8_t *network_addr, *netmask_addr, *address_addr;
+ unsigned int addr_len;
+ in_port_t *network_port, *netmask_port, *address_port;
+ int i;
+
+ if (network->ss_family != netmask->ss_family)
+ {
+ /* This should never happen */
+ log_error(LOG_LEVEL_ERROR,
+ "Internal error at %s:%llu: network and netmask differ in family",
+ __FILE__, __LINE__);
+ return 0;
+ }
+
+ sockaddr_storage_to_ip(network, &network_addr, &addr_len, &network_port);
+ sockaddr_storage_to_ip(netmask, &netmask_addr, NULL, &netmask_port);
+ sockaddr_storage_to_ip(address, &address_addr, NULL, &address_port);
+
+ /* Check for family */
+ if ((network->ss_family == AF_INET) && (address->ss_family == AF_INET6)
+ && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)address_addr))
+ {
+ /* Map AF_INET6 V4MAPPED address into AF_INET */
+ address_addr += 12;
+ addr_len = 4;
+ }
+ else if ((network->ss_family == AF_INET6) && (address->ss_family == AF_INET)
+ && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)network_addr))
+ {
+ /* Map AF_INET6 V4MAPPED network into AF_INET */
+ network_addr += 12;
+ netmask_addr += 12;
+ addr_len = 4;
+ }
+ else if (network->ss_family != address->ss_family)
+ {
+ return 0;
+ }
+
+ /* XXX: Port check is signaled in netmask */
+ if (*netmask_port && *network_port != *address_port)
+ {
+ return 0;
+ }
+
+ /* TODO: Optimize by checking by words insted of octets */
+ for (i = 0; (i < addr_len) && netmask_addr[i]; i++)
+ {
+ if ((network_addr[i] & netmask_addr[i]) !=
+ (address_addr[i] & netmask_addr[i]))
+ {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+#endif /* def HAVE_GETADDRINFO */
+
+