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