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