You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

294 lines
6.9 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/*
* 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));
}