mirror of https://gitee.com/openkylin/cups.git
294 lines
6.9 KiB
C
294 lines
6.9 KiB
C
/*
|
||
* 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));
|
||
}
|