xref: /openbsd-src/lib/libpcap/fad-getad.c (revision be691f3bb6417f04a68938fadbcaee2d5795e764)
1 /* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
2 /*
3  * Copyright (c) 1994, 1995, 1996, 1997, 1998
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by the Computer Systems
17  *	Engineering Group at Lawrence Berkeley Laboratory.
18  * 4. Neither the name of the University nor of the Laboratory may be used
19  *    to endorse or promote products derived from this software without
20  *    specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 
39 #include <net/if.h>
40 
41 #include <ctype.h>
42 #include <errno.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <ifaddrs.h>
47 #include <limits.h>
48 
49 #include "pcap-int.h"
50 
51 static struct sockaddr *
52 dup_sockaddr(struct sockaddr *sa, size_t sa_length)
53 {
54 	struct sockaddr *newsa;
55 
56 	if ((newsa = malloc(sa_length)) == NULL)
57 		return (NULL);
58 	return (memcpy(newsa, sa, sa_length));
59 }
60 
61 static int
62 get_instance(const char *name)
63 {
64 	const char *cp, *endcp;
65 	int n;
66 
67 	if (strcmp(name, "any") == 0) {
68 		/*
69 		 * Give the "any" device an artificially high instance
70 		 * number, so it shows up after all other non-loopback
71 		 * interfaces.
72 		 */
73 		return INT_MAX;
74 	}
75 
76 	endcp = name + strlen(name);
77 	for (cp = name; cp < endcp && !isdigit((unsigned char)*cp); ++cp)
78 		continue;
79 
80 	if (isdigit((unsigned char)*cp))
81 		n = atoi(cp);
82 	else
83 		n = 0;
84 	return (n);
85 }
86 
87 static int
88 add_or_find_if(pcap_if_t **curdev_ret, pcap_if_t **alldevs, const char *name,
89     u_int flags, const char *description, char *errbuf)
90 {
91 	pcap_t *p;
92 	pcap_if_t *curdev, *prevdev, *nextdev;
93 	int this_instance;
94 	size_t len;
95 
96 	/*
97 	 * Can we open this interface for live capture?
98 	 *
99 	 * We do this check so that interfaces that are supplied
100 	 * by the interface enumeration mechanism we're using
101 	 * but that don't support packet capture aren't included
102 	 * in the list.  An example of this is loopback interfaces
103 	 * on Solaris; we don't just omit loopback interfaces
104 	 * becaue you *can* capture on loopback interfaces on some
105 	 * OSes.
106 	 */
107 	p = pcap_open_live(name, 68, 0, 0, errbuf);
108 	if (p == NULL) {
109 		/*
110 		 * No.  Don't bother including it.
111 		 * Don't treat this as an error, though.
112 		 */
113 		*curdev_ret = NULL;
114 		return (0);
115 	}
116 	pcap_close(p);
117 
118 	/*
119 	 * Is there already an entry in the list for this interface?
120 	 */
121 	for (curdev = *alldevs; curdev != NULL; curdev = curdev->next) {
122 		if (strcmp(name, curdev->name) == 0)
123 			break;	/* yes, we found it */
124 	}
125 	if (curdev == NULL) {
126 		/*
127 		 * No, we didn't find it.
128 		 * Allocate a new entry.
129 		 */
130 		curdev = calloc(1, sizeof(pcap_if_t));
131 		if (curdev == NULL) {
132 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
133 			    "calloc: %s", pcap_strerror(errno));
134 			goto fail;
135 		}
136 
137 		/*
138 		 * Fill in the entry.
139 		 */
140 		curdev->next = NULL;
141 		len = strlen(name) + 1;
142 		curdev->name = malloc(len);
143 		if (curdev->name == NULL) {
144 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
145 			    "malloc: %s", pcap_strerror(errno));
146 			goto fail;
147 		}
148 		strlcpy(curdev->name, name, len);
149 		if (description != NULL) {
150 			/*
151 			 * We have a description for this interface.
152 			 */
153 			len = strlen(description) + 1;
154 			curdev->description = malloc(len);
155 			if (curdev->description == NULL) {
156 				(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
157 				    "malloc: %s", pcap_strerror(errno));
158 				goto fail;
159 			}
160 			strlcpy(curdev->description, description, len);
161 		}
162 		curdev->addresses = NULL;	/* list starts out as empty */
163 		curdev->flags = 0;
164 		if (ISLOOPBACK(name, flags))
165 			curdev->flags |= PCAP_IF_LOOPBACK;
166 
167 		/*
168 		 * Add it to the list, in the appropriate location.
169 		 * First, get the instance number of this interface.
170 		 */
171 		this_instance = get_instance(name);
172 
173 		/*
174 		 * Now look for the last interface with an instance number
175 		 * less than or equal to the new interface's instance
176 		 * number - except that non-loopback interfaces are
177 		 * arbitrarily treated as having interface numbers less
178 		 * than those of loopback interfaces, so the loopback
179 		 * interfaces are put at the end of the list.
180 		 *
181 		 * We start with "prevdev" being NULL, meaning we're before
182 		 * the first element in the list.
183 		 */
184 		prevdev = NULL;
185 		for (;;) {
186 			/*
187 			 * Get the interface after this one.
188 			 */
189 			if (prevdev == NULL) {
190 				/*
191 				 * The next element is the first element.
192 				 */
193 				nextdev = *alldevs;
194 			} else
195 				nextdev = prevdev->next;
196 
197 			/*
198 			 * Are we at the end of the list?
199 			 */
200 			if (nextdev == NULL) {
201 				/*
202 				 * Yes - we have to put the new entry
203 				 * after "prevdev".
204 				 */
205 				break;
206 			}
207 
208 			/*
209 			 * Is the new interface a non-loopback interface
210 			 * and the next interface a loopback interface?
211 			 */
212 			if (!(curdev->flags & PCAP_IF_LOOPBACK) &&
213 			    (nextdev->flags & PCAP_IF_LOOPBACK)) {
214 				/*
215 				 * Yes, we should put the new entry
216 				 * before "nextdev", i.e. after "prevdev".
217 				 */
218 				break;
219 			}
220 
221 			/*
222 			 * Is the new interface's instance number less
223 			 * than the next interface's instance number,
224 			 * and is it the case that the new interface is a
225 			 * non-loopback interface or the next interface is
226 			 * a loopback interface?
227 			 *
228 			 * (The goal of both loopback tests is to make
229 			 * sure that we never put a loopback interface
230 			 * before any non-loopback interface and that we
231 			 * always put a non-loopback interface before all
232 			 * loopback interfaces.)
233 			 */
234 			if (this_instance < get_instance(nextdev->name) &&
235 			    (!(curdev->flags & PCAP_IF_LOOPBACK) ||
236 			       (nextdev->flags & PCAP_IF_LOOPBACK))) {
237 				/*
238 				 * Yes - we should put the new entry
239 				 * before "nextdev", i.e. after "prevdev".
240 				 */
241 				break;
242 			}
243 
244 			prevdev = nextdev;
245 		}
246 
247 		/*
248 		 * Insert before "nextdev".
249 		 */
250 		curdev->next = nextdev;
251 
252 		/*
253 		 * Insert after "prevdev" - unless "prevdev" is null,
254 		 * in which case this is the first interface.
255 		 */
256 		if (prevdev == NULL) {
257 			/*
258 			 * This is the first interface.  Pass back a
259 			 * pointer to it, and put "curdev" before
260 			 * "nextdev".
261 			 */
262 			*alldevs = curdev;
263 		} else
264 			prevdev->next = curdev;
265 	}
266 
267 	*curdev_ret = curdev;
268 	return (0);
269 
270 fail:
271 	if (curdev != NULL) {
272 		free(curdev->name);
273 		free(curdev->description);
274 		free(curdev);
275 	}
276 	return (-1);
277 }
278 
279 static int
280 add_addr_to_iflist(pcap_if_t **alldevs, const char *name, u_int flags,
281     struct sockaddr *addr, size_t addr_size,
282     struct sockaddr *netmask, size_t netmask_size,
283     struct sockaddr *broadaddr, size_t broadaddr_size,
284     struct sockaddr *dstaddr, size_t dstaddr_size,
285     char *errbuf)
286 {
287 	pcap_if_t *curdev;
288 	pcap_addr_t *curaddr, *prevaddr, *nextaddr;
289 
290 	if (add_or_find_if(&curdev, alldevs, name, flags, NULL, errbuf) == -1) {
291 		/*
292 		 * Error - give up.
293 		 */
294 		return (-1);
295 	}
296 	if (curdev == NULL) {
297 		/*
298 		 * Device wasn't added because it can't be opened.
299 		 * Not a fatal error.
300 		 */
301 		return (0);
302 	}
303 
304 	/*
305 	 * "curdev" is an entry for this interface; add an entry for this
306 	 * address to its list of addresses.
307 	 *
308 	 * Allocate the new entry and fill it in.
309 	 */
310 	curaddr = calloc(1, sizeof(pcap_addr_t));
311 	if (curaddr == NULL) {
312 		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
313 		    "calloc: %s", pcap_strerror(errno));
314 		goto fail;
315 	}
316 
317 	curaddr->next = NULL;
318 	if (addr != NULL) {
319 		curaddr->addr = dup_sockaddr(addr, addr_size);
320 		if (curaddr->addr == NULL) {
321 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
322 			    "malloc: %s", pcap_strerror(errno));
323 			goto fail;
324 		}
325 	}
326 
327 	if (netmask != NULL) {
328 		curaddr->netmask = dup_sockaddr(netmask, netmask_size);
329 		if (curaddr->netmask == NULL) {
330 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
331 			    "malloc: %s", pcap_strerror(errno));
332 			goto fail;
333 		}
334 	}
335 
336 	if (broadaddr != NULL) {
337 		curaddr->broadaddr = dup_sockaddr(broadaddr, broadaddr_size);
338 		if (curaddr->broadaddr == NULL) {
339 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
340 			    "malloc: %s", pcap_strerror(errno));
341 			goto fail;
342 		}
343 	}
344 
345 	if (dstaddr != NULL) {
346 		curaddr->dstaddr = dup_sockaddr(dstaddr, dstaddr_size);
347 		if (curaddr->dstaddr == NULL) {
348 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
349 			    "malloc: %s", pcap_strerror(errno));
350 			goto fail;
351 		}
352 	}
353 
354 	/*
355 	 * Find the end of the list of addresses.
356 	 */
357 	for (prevaddr = curdev->addresses; prevaddr != NULL;
358 	    prevaddr = nextaddr) {
359 		nextaddr = prevaddr->next;
360 		if (nextaddr == NULL) {
361 			/*
362 			 * This is the end of the list.
363 			 */
364 			break;
365 		}
366 	}
367 
368 	if (prevaddr == NULL) {
369 		/*
370 		 * The list was empty; this is the first member.
371 		 */
372 		curdev->addresses = curaddr;
373 	} else {
374 		/*
375 		 * "prevaddr" is the last member of the list; append
376 		 * this member to it.
377 		 */
378 		prevaddr->next = curaddr;
379 	}
380 
381 	return (0);
382 
383 fail:
384 	if (curaddr != NULL) {
385 		free(curaddr->addr);
386 		free(curaddr->netmask);
387 		free(curaddr->broadaddr);
388 		free(curaddr->dstaddr);
389 		free(curaddr);
390 	}
391 	return (-1);
392 }
393 
394 /*
395  * Get a list of all interfaces that are up and that we can open.
396  * Returns -1 on error, 0 otherwise.
397  * The list, as returned through "alldevsp", may be null if no interfaces
398  * were up and could be opened.
399  *
400  * This is the implementation used on platforms that have "getifaddrs()".
401  */
402 int
403 pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
404 {
405 	pcap_if_t *devlist = NULL;
406 	struct ifaddrs *ifap, *ifa;
407 	struct sockaddr *addr, *netmask, *broadaddr, *dstaddr;
408 	size_t addr_size, broadaddr_size, dstaddr_size;
409 	int ret = 0;
410 
411 	/*
412 	 * Get the list of interface addresses.
413 	 *
414 	 * Note: this won't return information about interfaces
415 	 * with no addresses; are there any such interfaces
416 	 * that would be capable of receiving packets?
417 	 * (Interfaces incapable of receiving packets aren't
418 	 * very interesting from libpcap's point of view.)
419 	 *
420 	 * LAN interfaces will probably have link-layer
421 	 * addresses; I don't know whether all implementations
422 	 * of "getifaddrs()" now, or in the future, will return
423 	 * those.
424 	 */
425 	if (getifaddrs(&ifap) != 0) {
426 		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
427 		    "getifaddrs: %s", pcap_strerror(errno));
428 		return (-1);
429 	}
430 	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
431 		/*
432 		 * Is this interface up?
433 		 */
434 		if (!(ifa->ifa_flags & IFF_UP)) {
435 			/*
436 			 * No, so don't add it to the list.
437 			 */
438 			continue;
439 		}
440 
441 		/*
442 		 * "ifa_addr" was apparently null on at least one
443 		 * interface on some system.
444 		 *
445 		 * "ifa_broadaddr" may be non-null even on
446 		 * non-broadcast interfaces, and was null on
447 		 * at least one OpenBSD 3.4 system on at least
448 		 * one interface with IFF_BROADCAST set.
449 		 *
450 		 * "ifa_dstaddr" was, on at least one FreeBSD 4.1
451 		 * system, non-null on a non-point-to-point
452 		 * interface.
453 		 *
454 		 * Therefore, we supply the address and netmask only
455 		 * if "ifa_addr" is non-null (if there's no address,
456 		 * there's obviously no netmask), and supply the
457 		 * broadcast and destination addresses if the appropriate
458 		 * flag is set *and* the appropriate "ifa_" entry doesn't
459 		 * evaluate to a null pointer.
460 		 */
461 		if (ifa->ifa_addr != NULL) {
462 			addr = ifa->ifa_addr;
463 			addr_size = SA_LEN(addr);
464 			netmask = ifa->ifa_netmask;
465 		} else {
466 			addr = NULL;
467 			addr_size = 0;
468 			netmask = NULL;
469 		}
470 		if (ifa->ifa_flags & IFF_BROADCAST &&
471 		    ifa->ifa_broadaddr != NULL) {
472 			broadaddr = ifa->ifa_broadaddr;
473 			broadaddr_size = SA_LEN(broadaddr);
474 		} else {
475 			broadaddr = NULL;
476 			broadaddr_size = 0;
477 		}
478 		if (ifa->ifa_flags & IFF_POINTOPOINT &&
479 		    ifa->ifa_dstaddr != NULL) {
480 			dstaddr = ifa->ifa_dstaddr;
481 			dstaddr_size = SA_LEN(ifa->ifa_dstaddr);
482 		} else {
483 			dstaddr = NULL;
484 			dstaddr_size = 0;
485 		}
486 
487 		/*
488 		 * Add information for this address to the list.
489 		 */
490 		if (add_addr_to_iflist(&devlist, ifa->ifa_name,
491 		    ifa->ifa_flags, addr, addr_size, netmask, addr_size,
492 		    broadaddr, broadaddr_size, dstaddr, dstaddr_size,
493 		    errbuf) < 0) {
494 			ret = -1;
495 			break;
496 		}
497 	}
498 
499 	freeifaddrs(ifap);
500 
501 	if (ret == -1) {
502 		/*
503 		 * We had an error; free the list we've been constructing.
504 		 */
505 		if (devlist != NULL) {
506 			pcap_freealldevs(devlist);
507 			devlist = NULL;
508 		}
509 	}
510 
511 	*alldevsp = devlist;
512 	return (ret);
513 }
514