#include <cups/http-private.h>
#include "cupsd.h"
static void cupsdNetIFFree(void);
static int compare_netif(cupsd_netif_t *a, cupsd_netif_t *b);
cupsd_netif_t *
cupsdNetIFFind(const char *name)
{
cupsd_netif_t key;
if (NetIFUpdate)
cupsdNetIFUpdate();
strlcpy(key.name, name, sizeof(key.name));
return ((cupsd_netif_t *)cupsArrayFind(NetIFList, &key));
}
static void
cupsdNetIFFree(void)
{
cupsd_netif_t *current;
for (current = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
current;
current = (cupsd_netif_t *)cupsArrayNext(NetIFList))
{
cupsArrayRemove(NetIFList, current);
free(current);
}
}
void
cupsdNetIFUpdate(void)
{
int match;
cupsd_listener_t *lis;
cupsd_netif_t *temp;
struct ifaddrs *addrs,
*addr;
char hostname[1024];
size_t hostlen;
if (!NetIFUpdate)
return;
NetIFUpdate = 0;
cupsdNetIFFree();
if (!NetIFList)
NetIFList = cupsArrayNew((cups_array_func_t)compare_netif, NULL);
if (!NetIFList)
return;
if (getifaddrs(&addrs) < 0)
{
cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: Unable to get interface list - %s", strerror(errno));
return;
}
for (addr = addrs; addr != NULL; addr = addr->ifa_next)
{
if (addr->ifa_addr == NULL ||
(addr->ifa_addr->sa_family != AF_INET
#ifdef AF_INET6
&& addr->ifa_addr->sa_family != AF_INET6
#endif
) ||
addr->ifa_netmask == NULL || addr->ifa_name == NULL)
{
cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: Ignoring \"%s\".", addr->ifa_name);
continue;
}
if (HostNameLookups)
httpAddrLookup((http_addr_t *)(addr->ifa_addr), hostname,
sizeof(hostname));
else
{
if (httpAddrLocalhost((http_addr_t *)(addr->ifa_addr)))
strlcpy(hostname, "localhost", sizeof(hostname));
else
httpAddrString((http_addr_t *)(addr->ifa_addr), hostname,
sizeof(hostname));
}
hostlen = strlen(hostname);
if ((temp = calloc(1, sizeof(cupsd_netif_t) + hostlen)) == NULL)
{
cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: Unable to allocate memory for interface.");
break;
}
strlcpy(temp->name, addr->ifa_name, sizeof(temp->name));
temp->hostlen = hostlen;
memcpy(temp->hostname, hostname, hostlen + 1);
if (addr->ifa_addr->sa_family == AF_INET)
{
memcpy(&(temp->address), addr->ifa_addr, sizeof(struct sockaddr_in));
memcpy(&(temp->mask), addr->ifa_netmask, sizeof(struct sockaddr_in));
if (addr->ifa_dstaddr)
memcpy(&(temp->broadcast), addr->ifa_dstaddr,
sizeof(struct sockaddr_in));
}
#ifdef AF_INET6
else
{
memcpy(&(temp->address), addr->ifa_addr, sizeof(struct sockaddr_in6));
memcpy(&(temp->mask), addr->ifa_netmask, sizeof(struct sockaddr_in6));
if (addr->ifa_dstaddr)
memcpy(&(temp->broadcast), addr->ifa_dstaddr,
sizeof(struct sockaddr_in6));
}
#endif
if (!(addr->ifa_flags & IFF_POINTOPOINT) &&
!httpAddrLocalhost(&(temp->address)))
temp->is_local = 1;
for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
lis;
lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
{
match = 0;
if (httpAddrAny(&(lis->address)))
match = 1;
else if (addr->ifa_addr->sa_family == AF_INET &&
lis->address.addr.sa_family == AF_INET &&
(lis->address.ipv4.sin_addr.s_addr &
temp->mask.ipv4.sin_addr.s_addr) ==
(temp->address.ipv4.sin_addr.s_addr &
temp->mask.ipv4.sin_addr.s_addr))
match = 1;
#ifdef AF_INET6
else if (addr->ifa_addr->sa_family == AF_INET6 &&
lis->address.addr.sa_family == AF_INET6 &&
(lis->address.ipv6.sin6_addr.s6_addr[0] &
temp->mask.ipv6.sin6_addr.s6_addr[0]) ==
(temp->address.ipv6.sin6_addr.s6_addr[0] &
temp->mask.ipv6.sin6_addr.s6_addr[0]) &&
(lis->address.ipv6.sin6_addr.s6_addr[1] &
temp->mask.ipv6.sin6_addr.s6_addr[1]) ==
(temp->address.ipv6.sin6_addr.s6_addr[1] &
temp->mask.ipv6.sin6_addr.s6_addr[1]) &&
(lis->address.ipv6.sin6_addr.s6_addr[2] &
temp->mask.ipv6.sin6_addr.s6_addr[2]) ==
(temp->address.ipv6.sin6_addr.s6_addr[2] &
temp->mask.ipv6.sin6_addr.s6_addr[2]) &&
(lis->address.ipv6.sin6_addr.s6_addr[3] &
temp->mask.ipv6.sin6_addr.s6_addr[3]) ==
(temp->address.ipv6.sin6_addr.s6_addr[3] &
temp->mask.ipv6.sin6_addr.s6_addr[3]))
match = 1;
#endif
if (match)
{
temp->port = httpAddrPort(&(lis->address));
break;
}
}
cupsArrayAdd(NetIFList, temp);
cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: \"%s\" = %s:%d",
temp->name, temp->hostname, temp->port);
}
freeifaddrs(addrs);
}
static int
compare_netif(cupsd_netif_t *a,
cupsd_netif_t *b)
{
return (strcmp(a->name, b->name));
}