• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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