|
|
/*
|
|
|
* Network interface functions for the CUPS scheduler.
|
|
|
*
|
|
|
* Copyright © 2007-2018 by Apple Inc.
|
|
|
* Copyright © 1997-2006 by Easy Software Products, all rights reserved.
|
|
|
*
|
|
|
* Licensed under Apache License v2.0. See the file "LICENSE" for more
|
|
|
* information.
|
|
|
*/
|
|
|
|
|
|
/*
|
|
|
* Include necessary headers.
|
|
|
*/
|
|
|
|
|
|
#include <cups/http-private.h>
|
|
|
#include "cupsd.h"
|
|
|
#include <cups/getifaddrs-internal.h>
|
|
|
|
|
|
|
|
|
/*
|
|
|
* Local functions...
|
|
|
*/
|
|
|
|
|
|
static void cupsdNetIFFree(void);
|
|
|
static int compare_netif(cupsd_netif_t *a, cupsd_netif_t *b);
|
|
|
|
|
|
|
|
|
/*
|
|
|
* 'cupsdNetIFFind()' - Find a network interface.
|
|
|
*/
|
|
|
|
|
|
cupsd_netif_t * /* O - Network interface data */
|
|
|
cupsdNetIFFind(const char *name) /* I - Name of interface */
|
|
|
{
|
|
|
cupsd_netif_t key; /* Search key */
|
|
|
|
|
|
|
|
|
/*
|
|
|
* Update the interface list as needed...
|
|
|
*/
|
|
|
|
|
|
if (NetIFUpdate)
|
|
|
cupsdNetIFUpdate();
|
|
|
|
|
|
/*
|
|
|
* Search for the named interface...
|
|
|
*/
|
|
|
|
|
|
strlcpy(key.name, name, sizeof(key.name));
|
|
|
|
|
|
return ((cupsd_netif_t *)cupsArrayFind(NetIFList, &key));
|
|
|
}
|
|
|
|
|
|
|
|
|
/*
|
|
|
* 'cupsdNetIFFree()' - Free the current network interface list.
|
|
|
*/
|
|
|
|
|
|
static void
|
|
|
cupsdNetIFFree(void)
|
|
|
{
|
|
|
cupsd_netif_t *current; /* Current interface in array */
|
|
|
|
|
|
|
|
|
/*
|
|
|
* Loop through the interface list and free all the records...
|
|
|
*/
|
|
|
|
|
|
for (current = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
|
|
|
current;
|
|
|
current = (cupsd_netif_t *)cupsArrayNext(NetIFList))
|
|
|
{
|
|
|
cupsArrayRemove(NetIFList, current);
|
|
|
free(current);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
/*
|
|
|
* 'cupsdNetIFUpdate()' - Update the network interface list as needed...
|
|
|
*/
|
|
|
|
|
|
void
|
|
|
cupsdNetIFUpdate(void)
|
|
|
{
|
|
|
int match; /* Matching address? */
|
|
|
cupsd_listener_t *lis; /* Listen address */
|
|
|
cupsd_netif_t *temp; /* New interface */
|
|
|
struct ifaddrs *addrs, /* Interface address list */
|
|
|
*addr; /* Current interface address */
|
|
|
char hostname[1024]; /* Hostname for address */
|
|
|
size_t hostlen; /* Length of hostname */
|
|
|
|
|
|
|
|
|
/*
|
|
|
* Only update the list if we need to...
|
|
|
*/
|
|
|
|
|
|
if (!NetIFUpdate)
|
|
|
return;
|
|
|
|
|
|
NetIFUpdate = 0;
|
|
|
|
|
|
/*
|
|
|
* Free the old interfaces...
|
|
|
*/
|
|
|
|
|
|
cupsdNetIFFree();
|
|
|
|
|
|
/*
|
|
|
* Make sure we have an array...
|
|
|
*/
|
|
|
|
|
|
if (!NetIFList)
|
|
|
NetIFList = cupsArrayNew((cups_array_func_t)compare_netif, NULL);
|
|
|
|
|
|
if (!NetIFList)
|
|
|
return;
|
|
|
|
|
|
/*
|
|
|
* Grab a new list of interfaces...
|
|
|
*/
|
|
|
|
|
|
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)
|
|
|
{
|
|
|
/*
|
|
|
* See if this interface address is IPv4 or IPv6...
|
|
|
*/
|
|
|
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* Try looking up the hostname for the address as needed...
|
|
|
*/
|
|
|
|
|
|
if (HostNameLookups)
|
|
|
httpAddrLookup((http_addr_t *)(addr->ifa_addr), hostname,
|
|
|
sizeof(hostname));
|
|
|
else
|
|
|
{
|
|
|
/*
|
|
|
* Map the default server address and localhost to the server name
|
|
|
* and localhost, respectively; for all other addresses, use the
|
|
|
* numeric address...
|
|
|
*/
|
|
|
|
|
|
if (httpAddrLocalhost((http_addr_t *)(addr->ifa_addr)))
|
|
|
strlcpy(hostname, "localhost", sizeof(hostname));
|
|
|
else
|
|
|
httpAddrString((http_addr_t *)(addr->ifa_addr), hostname,
|
|
|
sizeof(hostname));
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* Create a new address element...
|
|
|
*/
|
|
|
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* Copy all of the information...
|
|
|
*/
|
|
|
|
|
|
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)
|
|
|
{
|
|
|
/*
|
|
|
* Copy IPv4 addresses...
|
|
|
*/
|
|
|
|
|
|
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
|
|
|
{
|
|
|
/*
|
|
|
* Copy IPv6 addresses...
|
|
|
*/
|
|
|
|
|
|
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 /* AF_INET6 */
|
|
|
|
|
|
if (!(addr->ifa_flags & IFF_POINTOPOINT) &&
|
|
|
!httpAddrLocalhost(&(temp->address)))
|
|
|
temp->is_local = 1;
|
|
|
|
|
|
/*
|
|
|
* Determine which port to use when advertising printers...
|
|
|
*/
|
|
|
|
|
|
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 /* AF_INET6 */
|
|
|
|
|
|
if (match)
|
|
|
{
|
|
|
temp->port = httpAddrPort(&(lis->address));
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* Add it to the array...
|
|
|
*/
|
|
|
|
|
|
cupsArrayAdd(NetIFList, temp);
|
|
|
|
|
|
cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: \"%s\" = %s:%d",
|
|
|
temp->name, temp->hostname, temp->port);
|
|
|
}
|
|
|
|
|
|
freeifaddrs(addrs);
|
|
|
}
|
|
|
|
|
|
|
|
|
/*
|
|
|
* 'compare_netif()' - Compare two network interfaces.
|
|
|
*/
|
|
|
|
|
|
static int /* O - Result of comparison */
|
|
|
compare_netif(cupsd_netif_t *a, /* I - First network interface */
|
|
|
cupsd_netif_t *b) /* I - Second network interface */
|
|
|
{
|
|
|
return (strcmp(a->name, b->name));
|
|
|
}
|