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