1/* 2 * "$Id: network.c 11528 2014-01-14 20:24:03Z msweet $" 3 * 4 * Network interface functions for the CUPS scheduler. 5 * 6 * Copyright 2007-2012 by Apple Inc. 7 * Copyright 1997-2006 by Easy Software Products, all rights reserved. 8 * 9 * These coded instructions, statements, and computer programs are the 10 * property of Apple Inc. and are protected by Federal copyright 11 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 12 * "LICENSE" which should have been included with this file. If this 13 * file is missing or damaged, see the license at "http://www.cups.org/". 14 * 15 * Contents: 16 * 17 * cupsdNetIFFind() - Find a network interface. 18 * cupsdNetIFFree() - Free the current network interface list. 19 * cupsdNetIFUpdate() - Update the network interface list as needed... 20 * compare_netif() - Compare two network interfaces. 21 */ 22 23/* 24 * Include necessary headers. 25 */ 26 27#include <cups/http-private.h> 28#include "cupsd.h" 29 30 31/* 32 * Local functions... 33 */ 34 35static void cupsdNetIFFree(void); 36static int compare_netif(cupsd_netif_t *a, cupsd_netif_t *b); 37 38 39/* 40 * 'cupsdNetIFFind()' - Find a network interface. 41 */ 42 43cupsd_netif_t * /* O - Network interface data */ 44cupsdNetIFFind(const char *name) /* I - Name of interface */ 45{ 46 cupsd_netif_t key; /* Search key */ 47 48 49 /* 50 * Update the interface list as needed... 51 */ 52 53 if (NetIFUpdate) 54 cupsdNetIFUpdate(); 55 56 /* 57 * Search for the named interface... 58 */ 59 60 strlcpy(key.name, name, sizeof(key.name)); 61 62 return ((cupsd_netif_t *)cupsArrayFind(NetIFList, &key)); 63} 64 65 66/* 67 * 'cupsdNetIFFree()' - Free the current network interface list. 68 */ 69 70static void 71cupsdNetIFFree(void) 72{ 73 cupsd_netif_t *current; /* Current interface in array */ 74 75 76 /* 77 * Loop through the interface list and free all the records... 78 */ 79 80 for (current = (cupsd_netif_t *)cupsArrayFirst(NetIFList); 81 current; 82 current = (cupsd_netif_t *)cupsArrayNext(NetIFList)) 83 { 84 cupsArrayRemove(NetIFList, current); 85 free(current); 86 } 87} 88 89 90/* 91 * 'cupsdNetIFUpdate()' - Update the network interface list as needed... 92 */ 93 94void 95cupsdNetIFUpdate(void) 96{ 97 int match; /* Matching address? */ 98 cupsd_listener_t *lis; /* Listen address */ 99 cupsd_netif_t *temp; /* New interface */ 100 struct ifaddrs *addrs, /* Interface address list */ 101 *addr; /* Current interface address */ 102 char hostname[1024]; /* Hostname for address */ 103 size_t hostlen; /* Length of hostname */ 104 105 106 /* 107 * Only update the list if we need to... 108 */ 109 110 if (!NetIFUpdate) 111 return; 112 113 NetIFUpdate = 0; 114 115 /* 116 * Free the old interfaces... 117 */ 118 119 cupsdNetIFFree(); 120 121 /* 122 * Make sure we have an array... 123 */ 124 125 if (!NetIFList) 126 NetIFList = cupsArrayNew((cups_array_func_t)compare_netif, NULL); 127 128 if (!NetIFList) 129 return; 130 131 /* 132 * Grab a new list of interfaces... 133 */ 134 135 if (getifaddrs(&addrs) < 0) 136 { 137 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: Unable to get interface list - %s", strerror(errno)); 138 return; 139 } 140 141 for (addr = addrs; addr != NULL; addr = addr->ifa_next) 142 { 143 /* 144 * See if this interface address is IPv4 or IPv6... 145 */ 146 147 if (addr->ifa_addr == NULL || 148 (addr->ifa_addr->sa_family != AF_INET 149#ifdef AF_INET6 150 && addr->ifa_addr->sa_family != AF_INET6 151#endif 152 ) || 153 addr->ifa_netmask == NULL || addr->ifa_name == NULL) 154 { 155 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: Ignoring \"%s\".", addr->ifa_name); 156 continue; 157 } 158 159 /* 160 * Try looking up the hostname for the address as needed... 161 */ 162 163 if (HostNameLookups) 164 httpAddrLookup((http_addr_t *)(addr->ifa_addr), hostname, 165 sizeof(hostname)); 166 else 167 { 168 /* 169 * Map the default server address and localhost to the server name 170 * and localhost, respectively; for all other addresses, use the 171 * numeric address... 172 */ 173 174 if (httpAddrLocalhost((http_addr_t *)(addr->ifa_addr))) 175 strlcpy(hostname, "localhost", sizeof(hostname)); 176 else 177 httpAddrString((http_addr_t *)(addr->ifa_addr), hostname, 178 sizeof(hostname)); 179 } 180 181 /* 182 * Create a new address element... 183 */ 184 185 hostlen = strlen(hostname); 186 if ((temp = calloc(1, sizeof(cupsd_netif_t) + hostlen)) == NULL) 187 { 188 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: Unable to allocate memory for interface."); 189 break; 190 } 191 192 /* 193 * Copy all of the information... 194 */ 195 196 strlcpy(temp->name, addr->ifa_name, sizeof(temp->name)); 197 temp->hostlen = hostlen; 198 memcpy(temp->hostname, hostname, hostlen + 1); 199 200 if (addr->ifa_addr->sa_family == AF_INET) 201 { 202 /* 203 * Copy IPv4 addresses... 204 */ 205 206 memcpy(&(temp->address), addr->ifa_addr, sizeof(struct sockaddr_in)); 207 memcpy(&(temp->mask), addr->ifa_netmask, sizeof(struct sockaddr_in)); 208 209 if (addr->ifa_dstaddr) 210 memcpy(&(temp->broadcast), addr->ifa_dstaddr, 211 sizeof(struct sockaddr_in)); 212 } 213#ifdef AF_INET6 214 else 215 { 216 /* 217 * Copy IPv6 addresses... 218 */ 219 220 memcpy(&(temp->address), addr->ifa_addr, sizeof(struct sockaddr_in6)); 221 memcpy(&(temp->mask), addr->ifa_netmask, sizeof(struct sockaddr_in6)); 222 223 if (addr->ifa_dstaddr) 224 memcpy(&(temp->broadcast), addr->ifa_dstaddr, 225 sizeof(struct sockaddr_in6)); 226 } 227#endif /* AF_INET6 */ 228 229 if (!(addr->ifa_flags & IFF_POINTOPOINT) && 230 !httpAddrLocalhost(&(temp->address))) 231 temp->is_local = 1; 232 233 /* 234 * Determine which port to use when advertising printers... 235 */ 236 237 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); 238 lis; 239 lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) 240 { 241 match = 0; 242 243 if (httpAddrAny(&(lis->address))) 244 match = 1; 245 else if (addr->ifa_addr->sa_family == AF_INET && 246 lis->address.addr.sa_family == AF_INET && 247 (lis->address.ipv4.sin_addr.s_addr & 248 temp->mask.ipv4.sin_addr.s_addr) == 249 (temp->address.ipv4.sin_addr.s_addr & 250 temp->mask.ipv4.sin_addr.s_addr)) 251 match = 1; 252#ifdef AF_INET6 253 else if (addr->ifa_addr->sa_family == AF_INET6 && 254 lis->address.addr.sa_family == AF_INET6 && 255 (lis->address.ipv6.sin6_addr.s6_addr[0] & 256 temp->mask.ipv6.sin6_addr.s6_addr[0]) == 257 (temp->address.ipv6.sin6_addr.s6_addr[0] & 258 temp->mask.ipv6.sin6_addr.s6_addr[0]) && 259 (lis->address.ipv6.sin6_addr.s6_addr[1] & 260 temp->mask.ipv6.sin6_addr.s6_addr[1]) == 261 (temp->address.ipv6.sin6_addr.s6_addr[1] & 262 temp->mask.ipv6.sin6_addr.s6_addr[1]) && 263 (lis->address.ipv6.sin6_addr.s6_addr[2] & 264 temp->mask.ipv6.sin6_addr.s6_addr[2]) == 265 (temp->address.ipv6.sin6_addr.s6_addr[2] & 266 temp->mask.ipv6.sin6_addr.s6_addr[2]) && 267 (lis->address.ipv6.sin6_addr.s6_addr[3] & 268 temp->mask.ipv6.sin6_addr.s6_addr[3]) == 269 (temp->address.ipv6.sin6_addr.s6_addr[3] & 270 temp->mask.ipv6.sin6_addr.s6_addr[3])) 271 match = 1; 272#endif /* AF_INET6 */ 273 274 if (match) 275 { 276 temp->port = httpAddrPort(&(lis->address)); 277 break; 278 } 279 } 280 281 /* 282 * Add it to the array... 283 */ 284 285 cupsArrayAdd(NetIFList, temp); 286 287 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: \"%s\" = %s:%d", 288 temp->name, temp->hostname, temp->port); 289 } 290 291 freeifaddrs(addrs); 292} 293 294 295/* 296 * 'compare_netif()' - Compare two network interfaces. 297 */ 298 299static int /* O - Result of comparison */ 300compare_netif(cupsd_netif_t *a, /* I - First network interface */ 301 cupsd_netif_t *b) /* I - Second network interface */ 302{ 303 return (strcmp(a->name, b->name)); 304} 305 306 307/* 308 * End of "$Id: network.c 11528 2014-01-14 20:24:03Z msweet $". 309 */ 310