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