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