#include "cupsd.h"
#include <net/if.h>
#ifdef HAVE_GETIFADDRS
# include <ifaddrs.h>
#else
# include <sys/ioctl.h>
# ifdef HAVE_SYS_SOCKIO_H
# include <sys/sockio.h>
# endif
# ifdef ifa_dstaddr
# undef ifa_dstaddr
# endif
# ifndef ifr_netmask
# define ifr_netmask ifr_addr
# endif
struct ifaddrs
{
struct ifaddrs *ifa_next;
char *ifa_name;
unsigned int ifa_flags;
struct sockaddr *ifa_addr,
*ifa_netmask,
*ifa_dstaddr;
void *ifa_data;
};
int getifaddrs(struct ifaddrs **addrs);
void freeifaddrs(struct ifaddrs *addrs);
#endif
cups_netif_t *
NetIFFind(const char *name)
{
cups_netif_t *temp;
NetIFUpdate(FALSE);
for (temp = NetIFList; temp != NULL; temp = temp->next)
if (strcasecmp(name, temp->name) == 0)
return (temp);
return (NULL);
}
void
NetIFFree(void)
{
cups_netif_t *next;
while (NetIFList != NULL)
{
next = NetIFList->next;
if (NetIFList->hostname)
free(NetIFList->hostname);
free(NetIFList);
NetIFList = next;
}
}
void
NetIFUpdate(int force)
{
int i;
listener_t *lis;
cups_netif_t *temp;
struct ifaddrs *addrs,
*addr;
struct hostent *host;
if (!force && (time(NULL) - NetIFTime) < 60)
return;
NetIFTime = time(NULL);
NetIFFree();
if (getifaddrs(&addrs) < 0)
return;
for (addr = addrs; addr != NULL; addr = addr->ifa_next)
{
if (addr->ifa_addr == NULL || addr->ifa_addr->sa_family != AF_INET ||
addr->ifa_netmask == NULL || addr->ifa_name == NULL)
continue;
if ((temp = calloc(1, sizeof(cups_netif_t))) == NULL)
break;
temp->next = NetIFList;
NetIFList = temp;
strlcpy(temp->name, addr->ifa_name, sizeof(temp->name));
memcpy(&(temp->address), addr->ifa_addr, sizeof(temp->address));
memcpy(&(temp->mask), addr->ifa_netmask, sizeof(temp->mask));
if (addr->ifa_dstaddr)
memcpy(&(temp->broadcast), addr->ifa_dstaddr, sizeof(temp->broadcast));
if (!(addr->ifa_flags & IFF_POINTOPOINT) &&
ntohl(temp->address.sin_addr.s_addr) != 0x7f000001)
temp->is_local = 1;
for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
if (lis->address.sin_addr.s_addr == 0x00000000 ||
(lis->address.sin_addr.s_addr & temp->mask.sin_addr.s_addr) ==
temp->address.sin_addr.s_addr)
{
temp->port = ntohs(lis->address.sin_port);
break;
}
if (HostNameLookups)
{
#ifndef __sgi
host = gethostbyaddr((char *)&(temp->address.sin_addr),
sizeof(struct in_addr), AF_INET);
#else
host = gethostbyaddr(&(temp->address.sin_addr),
sizeof(struct in_addr), AF_INET);
#endif
}
else
host = NULL;
if (host != NULL)
SetString(&temp->hostname, host->h_name);
else if (ntohl(temp->address.sin_addr.s_addr) == 0x7f000001)
SetString(&temp->hostname, "localhost");
else if (temp->address.sin_addr.s_addr == ServerAddr.sin_addr.s_addr)
SetString(&temp->hostname, ServerName);
else
{
unsigned ip = ntohl(temp->address.sin_addr.s_addr);
SetStringf(&temp->hostname, "%d.%d.%d.%d",
(ip >> 24) & 255, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255);
}
}
freeifaddrs(addrs);
}
#ifndef HAVE_GETIFADDRS
int
getifaddrs(struct ifaddrs **addrs)
{
int sock;
char buffer[65536],
*bufptr,
*bufend;
struct ifconf conf;
struct sockaddr addr;
struct ifreq *ifp;
int ifpsize;
struct ifaddrs *temp;
struct ifreq request;
if (addrs == NULL)
return (-1);
*addrs = NULL;
memset (&addr, 0, sizeof(addr));
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
return (-1);
conf.ifc_len = sizeof(buffer);
conf.ifc_buf = buffer;
if (ioctl(sock, SIOCGIFCONF, &conf) < 0)
{
close(sock);
return (-1);
}
# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
# define sockaddr_len(a) ((a)->sa_len)
# else
# define sockaddr_len(a) (sizeof(struct sockaddr))
# endif
for (bufptr = buffer, bufend = buffer + conf.ifc_len;
bufptr < bufend;
bufptr += ifpsize)
{
ifp = (struct ifreq *)bufptr;
ifpsize = sizeof(ifp->ifr_name) + sockaddr_len(&(ifp->ifr_addr));
if (ifpsize < sizeof(struct ifreq))
ifpsize = sizeof(struct ifreq);
memset(&request, 0, sizeof(request));
memcpy(request.ifr_name, ifp->ifr_name, sizeof(ifp->ifr_name));
if (ioctl(sock, SIOCGIFFLAGS, &request) < 0)
continue;
if ((temp = calloc(1, sizeof(struct ifaddrs))) == NULL)
{
close(sock);
return (-1);
}
temp->ifa_next = *addrs;
*addrs = temp;
temp->ifa_name = strdup(ifp->ifr_name);
temp->ifa_flags = request.ifr_flags;
if ((temp->ifa_addr = calloc(1, sockaddr_len(&(ifp->ifr_addr)))) != NULL)
memcpy(temp->ifa_addr, &(ifp->ifr_addr), sockaddr_len(&(ifp->ifr_addr)));
if (!ioctl(sock, SIOCGIFNETMASK, &request))
{
if ((temp->ifa_netmask = calloc(1, sizeof(request.ifr_netmask))) != NULL)
memcpy(temp->ifa_netmask, &(request.ifr_netmask),
sizeof(request.ifr_netmask));
}
if (temp->ifa_flags & IFF_BROADCAST)
{
if (!ioctl(sock, SIOCGIFBRDADDR, &request))
{
if ((temp->ifa_dstaddr = calloc(1, sizeof(request.ifr_broadaddr))) != NULL)
memcpy(temp->ifa_dstaddr, &(request.ifr_broadaddr),
sizeof(request.ifr_broadaddr));
}
}
else if (temp->ifa_flags & IFF_POINTOPOINT)
{
if (!ioctl(sock, SIOCGIFDSTADDR, &request))
{
temp->ifa_dstaddr = malloc(sizeof(request.ifr_dstaddr));
memcpy(temp->ifa_dstaddr, &(request.ifr_dstaddr),
sizeof(request.ifr_dstaddr));
}
}
}
close(sock);
return (0);
}
void
freeifaddrs(struct ifaddrs *addrs)
{
struct ifaddrs *next;
while (addrs != NULL)
{
next = addrs->ifa_next;
if (addrs->ifa_name)
{
free(addrs->ifa_name);
addrs->ifa_name = NULL;
}
if (addrs->ifa_addr)
{
free(addrs->ifa_addr);
addrs->ifa_addr = NULL;
}
if (addrs->ifa_netmask)
{
free(addrs->ifa_netmask);
addrs->ifa_netmask = NULL;
}
if (addrs->ifa_dstaddr)
{
free(addrs->ifa_dstaddr);
addrs->ifa_dstaddr = NULL;
}
free(addrs);
addrs = next;
}
}
#endif