]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/network.c
Fix some more IPv6 issues.
[thirdparty/cups.git] / scheduler / network.c
CommitLineData
2123c23a 1/*
c9d3f842 2 * "$Id$"
2123c23a 3 *
4 * Network interface functions for the Common UNIX Printing System
5 * (CUPS) scheduler.
6 *
c9d3f842 7 * Copyright 1997-2005 by Easy Software Products, all rights reserved.
2123c23a 8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Easy Software Products and are protected by Federal
11 * copyright law. Distribution and use rights are outlined in the file
12 * "LICENSE" which should have been included with this file. If this
13 * file is missing or damaged please contact Easy Software Products
14 * at:
15 *
16 * Attn: CUPS Licensing Information
17 * Easy Software Products
18 * 44141 Airport View Drive, Suite 204
8650fcf2 19 * Hollywood, Maryland 20636 USA
2123c23a 20 *
edfd3c3d 21 * Voice: (301) 373-9600
2123c23a 22 * EMail: cups-info@cups.org
23 * WWW: http://www.cups.org
f3e786fc 24 *
25 * Contents:
26 *
27 * cupsdNetIFFind() - Find a network interface.
28 * cupsdNetIFFree() - Free the current network interface list.
29 * cupsdNetIFUpdate() - Update the network interface list as needed...
30 * getifaddrs() - Get a list of network interfaces on the system.
31 * freeifaddrs() - Free an interface list...
2123c23a 32 */
33
34/*
35 * Include necessary headers.
36 */
37
38#include "cupsd.h"
39
e23104b4 40#include <net/if.h>
41
2123c23a 42#ifdef HAVE_GETIFADDRS
43/*
44 * Use native getifaddrs() function...
45 */
46# include <ifaddrs.h>
47#else
48/*
49 * Use getifaddrs() emulation...
50 */
51
2123c23a 52# include <sys/ioctl.h>
53# ifdef HAVE_SYS_SOCKIO_H
54# include <sys/sockio.h>
55# endif
56
57# ifdef ifa_dstaddr
58# undef ifa_dstaddr
59# endif /* ifa_dstaddr */
60# ifndef ifr_netmask
61# define ifr_netmask ifr_addr
62# endif /* !ifr_netmask */
63
f3e786fc 64struct ifaddrs /**** Interface Structure ****/
2123c23a 65{
66 struct ifaddrs *ifa_next; /* Next interface in list */
67 char *ifa_name; /* Name of interface */
68 unsigned int ifa_flags; /* Flags (up, point-to-point, etc.) */
69 struct sockaddr *ifa_addr, /* Network address */
70 *ifa_netmask, /* Address mask */
71 *ifa_dstaddr; /* Broadcast or destination address */
72 void *ifa_data; /* Interface statistics */
73};
74
75int getifaddrs(struct ifaddrs **addrs);
76void freeifaddrs(struct ifaddrs *addrs);
77#endif /* HAVE_GETIFADDRS */
78
79
80/*
f3e786fc 81 * 'cupsdNetIFFind()' - Find a network interface.
2123c23a 82 */
83
f3e786fc 84cupsd_netif_t * /* O - Network interface data */
85cupsdNetIFFind(const char *name) /* I - Name of interface */
2123c23a 86{
f3e786fc 87 cupsd_netif_t *temp; /* Current network interface */
2123c23a 88
89
90 /*
91 * Update the interface list as needed...
92 */
93
589eb420 94 cupsdNetIFUpdate();
2123c23a 95
96 /*
97 * Search for the named interface...
98 */
99
100 for (temp = NetIFList; temp != NULL; temp = temp->next)
f3e786fc 101 if (!strcasecmp(name, temp->name))
2123c23a 102 return (temp);
103
104 return (NULL);
105}
106
107
108/*
589eb420 109 * 'cupsdNetIFFree()' - Free the current network interface list.
2123c23a 110 */
111
112void
589eb420 113cupsdNetIFFree(void)
2123c23a 114{
f3e786fc 115 cupsd_netif_t *next; /* Next interface in list */
2123c23a 116
117
118 /*
119 * Loop through the interface list and free all the records...
120 */
121
122 while (NetIFList != NULL)
123 {
124 next = NetIFList->next;
125
126 free(NetIFList);
127
128 NetIFList = next;
129 }
130}
131
132
133/*
589eb420 134 * 'cupsdNetIFUpdate()' - Update the network interface list as needed...
2123c23a 135 */
136
137void
589eb420 138cupsdNetIFUpdate(void)
2123c23a 139{
f3e786fc 140 int i, /* Looping var */
141 match; /* Matching address? */
589eb420 142 cupsd_listener_t *lis; /* Listen address */
f3e786fc 143 cupsd_netif_t *temp; /* Current interface */
144 struct ifaddrs *addrs, /* Interface address list */
145 *addr; /* Current interface address */
086c584d 146 http_addrlist_t *saddr; /* Current server address */
2123c23a 147
148
149 /*
150 * Update the network interface list no more often than once a
151 * minute...
152 */
153
154 if ((time(NULL) - NetIFTime) < 60)
155 return;
156
5fe35f41 157 NetIFTime = time(NULL);
158
2123c23a 159 /*
160 * Free the old interfaces...
161 */
162
589eb420 163 cupsdNetIFFree();
2123c23a 164
165 /*
166 * Grab a new list of interfaces...
167 */
168
169 if (getifaddrs(&addrs) < 0)
170 return;
171
172 for (addr = addrs; addr != NULL; addr = addr->ifa_next)
173 {
174 /*
20264b99 175 * See if this interface address is IPv4 or IPv6...
2123c23a 176 */
177
20264b99 178 if (addr->ifa_addr == NULL ||
a09840c5 179 (addr->ifa_addr->sa_family != AF_INET
180#ifdef AF_INET6
181 && addr->ifa_addr->sa_family != AF_INET6
182#endif
183 ) ||
2123c23a 184 addr->ifa_netmask == NULL || addr->ifa_name == NULL)
185 continue;
186
187 /*
20264b99 188 * OK, we have an IPv4/6 address, so create a new list node...
2123c23a 189 */
190
589eb420 191 if ((temp = calloc(1, sizeof(cupsd_netif_t))) == NULL)
2123c23a 192 break;
193
194 temp->next = NetIFList;
195 NetIFList = temp;
196
197 /*
198 * Then copy all of the information...
199 */
200
def978d5 201 strlcpy(temp->name, addr->ifa_name, sizeof(temp->name));
2123c23a 202
20264b99 203 if (addr->ifa_addr->sa_family == AF_INET)
204 {
205 /*
206 * Copy IPv4 addresses...
207 */
208
209 memcpy(&(temp->address), addr->ifa_addr, sizeof(struct sockaddr_in));
210 memcpy(&(temp->mask), addr->ifa_netmask, sizeof(struct sockaddr_in));
211
212 if (addr->ifa_dstaddr)
f3e786fc 213 memcpy(&(temp->broadcast), addr->ifa_dstaddr,
214 sizeof(struct sockaddr_in));
20264b99 215 }
a09840c5 216#ifdef AF_INET6
20264b99 217 else
218 {
219 /*
220 * Copy IPv6 addresses...
221 */
222
223 memcpy(&(temp->address), addr->ifa_addr, sizeof(struct sockaddr_in6));
224 memcpy(&(temp->mask), addr->ifa_netmask, sizeof(struct sockaddr_in6));
225
226 if (addr->ifa_dstaddr)
f3e786fc 227 memcpy(&(temp->broadcast), addr->ifa_dstaddr,
228 sizeof(struct sockaddr_in6));
20264b99 229 }
a09840c5 230#endif /* AF_INET6 */
2123c23a 231
d7a9de63 232 if (!(addr->ifa_flags & IFF_POINTOPOINT) &&
233 !httpAddrLocalhost(&(temp->address)))
2123c23a 234 temp->is_local = 1;
235
edd6ee99 236 /*
237 * Determine which port to use when advertising printers...
238 */
239
240 for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
241 {
242 match = 0;
243
244 if (httpAddrAny(&(lis->address)))
245 match = 1;
246 else if (addr->ifa_addr->sa_family == AF_INET &&
247 lis->address.addr.sa_family == AF_INET &&
248 (lis->address.ipv4.sin_addr.s_addr &
249 temp->mask.ipv4.sin_addr.s_addr) ==
250 temp->address.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 (lis->address.ipv6.sin6_addr.s6_addr[1] &
259 temp->mask.ipv6.sin6_addr.s6_addr[1]) ==
260 temp->address.ipv6.sin6_addr.s6_addr[1] &&
261 (lis->address.ipv6.sin6_addr.s6_addr[2] &
262 temp->mask.ipv6.sin6_addr.s6_addr[2]) ==
263 temp->address.ipv6.sin6_addr.s6_addr[2] &&
264 (lis->address.ipv6.sin6_addr.s6_addr[3] &
265 temp->mask.ipv6.sin6_addr.s6_addr[3]) ==
266 temp->address.ipv6.sin6_addr.s6_addr[3])
267 match = 1;
268#endif /* AF_INET6 */
269
270 if (match)
271 {
272 if (lis->address.addr.sa_family == AF_INET)
273 temp->port = ntohs(lis->address.ipv4.sin_port);
274#ifdef AF_INET6
275 else if (lis->address.addr.sa_family == AF_INET6)
276 temp->port = ntohs(lis->address.ipv6.sin6_port);
277#endif /* AF_INET6 */
278 break;
279 }
280 }
281
2123c23a 282 /*
283 * Finally, try looking up the hostname for the address as needed...
284 */
285
286 if (HostNameLookups)
d7a9de63 287 httpAddrLookup(&(temp->address), temp->hostname, sizeof(temp->hostname));
2123c23a 288 else
a7811b07 289 {
290 /*
291 * Map the default server address and localhost to the server name
292 * and localhost, respectively; for all other addresses, use the
293 * dotted notation...
294 */
295
296 if (httpAddrLocalhost(&(temp->address)))
297 strcpy(temp->hostname, "localhost");
a7811b07 298 else
086c584d 299 {
300 for (saddr = ServerAddrs; saddr; saddr = saddr->next)
301 if (httpAddrEqual(&(temp->address), &(saddr->addr)))
302 break;
303
304 if (saddr)
305 strlcpy(temp->hostname, ServerName, sizeof(temp->hostname));
306 else
307 httpAddrString(&(temp->address), temp->hostname,
308 sizeof(temp->hostname));
309 }
a7811b07 310 }
40e67cda 311
312 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: \"%s\" = %s...",
313 temp->name, temp->hostname);
2123c23a 314 }
315
316 freeifaddrs(addrs);
317}
318
319
320#ifndef HAVE_GETIFADDRS
321/*
322 * 'getifaddrs()' - Get a list of network interfaces on the system.
323 */
324
325int /* O - 0 on success, -1 on error */
326getifaddrs(struct ifaddrs **addrs) /* O - List of interfaces */
327{
328 int sock; /* Socket */
329 char buffer[65536], /* Buffer for address info */
330 *bufptr, /* Pointer into buffer */
331 *bufend; /* End of buffer */
332 struct ifconf conf; /* Interface configurations */
333 struct sockaddr addr; /* Address data */
334 struct ifreq *ifp; /* Interface data */
335 int ifpsize; /* Size of interface data */
336 struct ifaddrs *temp; /* Pointer to current interface */
337 struct ifreq request; /* Interface request */
338
339
340 /*
341 * Start with an empty list...
342 */
343
344 if (addrs == NULL)
345 return (-1);
346
347 *addrs = NULL;
348
349 /*
350 * Create a UDP socket to get the interface data...
351 */
352
353 memset (&addr, 0, sizeof(addr));
354 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
355 return (-1);
356
357 /*
358 * Try to get the list of interfaces...
359 */
360
361 conf.ifc_len = sizeof(buffer);
362 conf.ifc_buf = buffer;
363
364 if (ioctl(sock, SIOCGIFCONF, &conf) < 0)
365 {
366 /*
367 * Couldn't get the list of interfaces...
368 */
369
370 close(sock);
371 return (-1);
372 }
373
374 /*
375 * OK, got the list of interfaces, now lets step through the
376 * buffer to pull them out...
377 */
378
379# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
380# define sockaddr_len(a) ((a)->sa_len)
381# else
382# define sockaddr_len(a) (sizeof(struct sockaddr))
383# endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
384
385 for (bufptr = buffer, bufend = buffer + conf.ifc_len;
386 bufptr < bufend;
387 bufptr += ifpsize)
388 {
389 /*
390 * Get the current interface information...
391 */
392
393 ifp = (struct ifreq *)bufptr;
394 ifpsize = sizeof(ifp->ifr_name) + sockaddr_len(&(ifp->ifr_addr));
395
396 if (ifpsize < sizeof(struct ifreq))
397 ifpsize = sizeof(struct ifreq);
398
399 memset(&request, 0, sizeof(request));
400 memcpy(request.ifr_name, ifp->ifr_name, sizeof(ifp->ifr_name));
401
402 /*
403 * Check the status of the interface...
404 */
405
406 if (ioctl(sock, SIOCGIFFLAGS, &request) < 0)
407 continue;
408
409 /*
410 * Allocate memory for a single interface record...
411 */
412
413 if ((temp = calloc(1, sizeof(struct ifaddrs))) == NULL)
414 {
415 /*
416 * Unable to allocate memory...
417 */
418
419 close(sock);
420 return (-1);
421 }
422
423 /*
424 * Add this record to the front of the list and copy the name, flags,
425 * and network address...
426 */
427
428 temp->ifa_next = *addrs;
429 *addrs = temp;
430 temp->ifa_name = strdup(ifp->ifr_name);
431 temp->ifa_flags = request.ifr_flags;
432 if ((temp->ifa_addr = calloc(1, sockaddr_len(&(ifp->ifr_addr)))) != NULL)
433 memcpy(temp->ifa_addr, &(ifp->ifr_addr), sockaddr_len(&(ifp->ifr_addr)));
434
435 /*
436 * Try to get the netmask for the interface...
437 */
438
439 if (!ioctl(sock, SIOCGIFNETMASK, &request))
440 {
441 /*
442 * Got it, make a copy...
443 */
444
445 if ((temp->ifa_netmask = calloc(1, sizeof(request.ifr_netmask))) != NULL)
446 memcpy(temp->ifa_netmask, &(request.ifr_netmask),
447 sizeof(request.ifr_netmask));
448 }
449
450 /*
451 * Then get the broadcast or point-to-point (destination) address,
452 * if applicable...
453 */
454
455 if (temp->ifa_flags & IFF_BROADCAST)
456 {
457 /*
458 * Have a broadcast address, so get it!
459 */
460
461 if (!ioctl(sock, SIOCGIFBRDADDR, &request))
462 {
463 /*
464 * Got it, make a copy...
465 */
466
467 if ((temp->ifa_dstaddr = calloc(1, sizeof(request.ifr_broadaddr))) != NULL)
468 memcpy(temp->ifa_dstaddr, &(request.ifr_broadaddr),
469 sizeof(request.ifr_broadaddr));
470 }
471 }
472 else if (temp->ifa_flags & IFF_POINTOPOINT)
473 {
474 /*
475 * Point-to-point interface; grab the remote address...
476 */
477
478 if (!ioctl(sock, SIOCGIFDSTADDR, &request))
479 {
480 temp->ifa_dstaddr = malloc(sizeof(request.ifr_dstaddr));
481 memcpy(temp->ifa_dstaddr, &(request.ifr_dstaddr),
482 sizeof(request.ifr_dstaddr));
483 }
484 }
485 }
486
487 /*
488 * OK, we're done with the socket, close it and return 0...
489 */
490
491 close(sock);
492
493 return (0);
494}
495
496
497/*
498 * 'freeifaddrs()' - Free an interface list...
499 */
500
501void
502freeifaddrs(struct ifaddrs *addrs) /* I - Interface list to free */
503{
504 struct ifaddrs *next; /* Next interface in list */
505
506
507 while (addrs != NULL)
508 {
509 /*
510 * Make a copy of the next interface pointer...
511 */
512
513 next = addrs->ifa_next;
514
515 /*
516 * Free data values as needed...
517 */
518
519 if (addrs->ifa_name)
520 {
521 free(addrs->ifa_name);
522 addrs->ifa_name = NULL;
523 }
524
525 if (addrs->ifa_addr)
526 {
527 free(addrs->ifa_addr);
528 addrs->ifa_addr = NULL;
529 }
530
531 if (addrs->ifa_netmask)
532 {
533 free(addrs->ifa_netmask);
534 addrs->ifa_netmask = NULL;
535 }
536
537 if (addrs->ifa_dstaddr)
538 {
539 free(addrs->ifa_dstaddr);
540 addrs->ifa_dstaddr = NULL;
541 }
542
543 /*
544 * Free this node and continue to the next...
545 */
546
547 free(addrs);
548
549 addrs = next;
550 }
551}
2123c23a 552#endif /* !HAVE_GETIFADDRS */
553
554
555/*
c9d3f842 556 * End of "$Id$".
2123c23a 557 */