| 
41 | 41 | #ifdef HAVE_SYS_IOCCOM_H  | 
42 | 42 | #include <sys/ioccom.h>  | 
43 | 43 | #endif  | 
 | 44 | + | 
 | 45 | +/*  | 
 | 46 | + * On most supported platforms <sys/ioctl.h> also defines the SIOCGIF* macros.  | 
 | 47 | + * However, on Haiku, illumos and Solaris the macros need <sys/sockio.h>,  | 
 | 48 | + * which does not exist in AIX 7, HP-UX 11, GNU/Hurd and Linux (both GNU and  | 
 | 49 | + * musl libc).  | 
 | 50 | + */  | 
 | 51 | +#if defined(HAVE_SOLARIS) || defined(__HAIKU__) || defined(__sun) || defined(__SVR4)  | 
 | 52 | +#include <sys/sockio.h>  | 
 | 53 | +#endif  | 
 | 54 | + | 
44 | 55 | #include <sys/utsname.h>  | 
45 | 56 | 
 
  | 
46 | 57 | #if defined(__FreeBSD__) && defined(SIOCIFCREATE2)  | 
@@ -626,6 +637,66 @@ bpf_open(char *errbuf)  | 
626 | 637 | #define BPF_BIND_SUCCEEDED	0  | 
627 | 638 | #define BPF_BIND_BUFFER_TOO_BIG	1  | 
628 | 639 | 
 
  | 
 | 640 | +/*  | 
 | 641 | + * Check if an interface exists without requiring special privileges.  | 
 | 642 | + * Returns 0 if the interface exists, PCAP_ERROR_NO_SUCH_DEVICE if it doesn't,  | 
 | 643 | + * or another negative error code on other failures.  | 
 | 644 | + */  | 
 | 645 | +static int  | 
 | 646 | +check_interface_exists(const char *name, char *errbuf)  | 
 | 647 | +{  | 
 | 648 | +#ifndef _WIN32  | 
 | 649 | +	int fd;  | 
 | 650 | +	struct ifreq ifr;  | 
 | 651 | + | 
 | 652 | +	if (strlen(name) >= sizeof(ifr.ifr_name)) {  | 
 | 653 | +		/* The name is too long, so it can't possibly exist. */  | 
 | 654 | +		errbuf[0] = '\0';  | 
 | 655 | +		return PCAP_ERROR_NO_SUCH_DEVICE;  | 
 | 656 | +	}  | 
 | 657 | + | 
 | 658 | +	fd = socket(AF_INET, SOCK_DGRAM, 0);  | 
 | 659 | +	if (fd < 0) {  | 
 | 660 | +		pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,  | 
 | 661 | +		    errno, "socket");  | 
 | 662 | +		return PCAP_ERROR;  | 
 | 663 | +	}  | 
 | 664 | + | 
 | 665 | +	memset(&ifr, 0, sizeof(ifr));  | 
 | 666 | +	pcapint_strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));  | 
 | 667 | + | 
 | 668 | +#ifdef SIOCGIFFLAGS  | 
 | 669 | +	if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {  | 
 | 670 | +		int save_errno = errno;  | 
 | 671 | +		close(fd);  | 
 | 672 | + | 
 | 673 | +		if (save_errno == ENXIO || save_errno == ENODEV) {  | 
 | 674 | +			/* Interface doesn't exist */  | 
 | 675 | +			errbuf[0] = '\0';  | 
 | 676 | +			return PCAP_ERROR_NO_SUCH_DEVICE;  | 
 | 677 | +		} else {  | 
 | 678 | +			/* Some other error occurred */  | 
 | 679 | +			pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,  | 
 | 680 | +			    save_errno, "SIOCGIFFLAGS on %s", name);  | 
 | 681 | +			return PCAP_ERROR;  | 
 | 682 | +		}  | 
 | 683 | +	}  | 
 | 684 | +#else  | 
 | 685 | +	/*  | 
 | 686 | +	 * SIOCGIFFLAGS not available on this platform.  | 
 | 687 | +	 * We can't reliably check interface existence without privileges,  | 
 | 688 | +	 * so we skip the check and let the BPF bind operation handle it.  | 
 | 689 | +	 */  | 
 | 690 | +#endif  | 
 | 691 | + | 
 | 692 | +	close(fd);  | 
 | 693 | +	return 0;  | 
 | 694 | +#else  | 
 | 695 | +	/* On Windows, skip the check for now */  | 
 | 696 | +	return 0;  | 
 | 697 | +#endif  | 
 | 698 | +}  | 
 | 699 | + | 
629 | 700 | static int  | 
630 | 701 | bpf_bind(int fd, const char *name, char *errbuf)  | 
631 | 702 | {  | 
@@ -1923,6 +1994,16 @@ pcap_activate_bpf(pcap_t *p)  | 
1923 | 1994 | 	int flags = MAP_ANON;  | 
1924 | 1995 | #endif  | 
1925 | 1996 | 
 
  | 
 | 1997 | +	/*  | 
 | 1998 | +	 * Check if the interface exists before trying to open BPF device.  | 
 | 1999 | +	 * This avoids reporting permission errors when the real issue is  | 
 | 2000 | +	 * that the interface doesn't exist.  | 
 | 2001 | +	 */  | 
 | 2002 | +	status = check_interface_exists(p->opt.device, p->errbuf);  | 
 | 2003 | +	if (status != 0) {  | 
 | 2004 | +		goto bad;  | 
 | 2005 | +	}  | 
 | 2006 | + | 
1926 | 2007 | 	fd = bpf_open(p->errbuf);  | 
1927 | 2008 | 	if (fd < 0) {  | 
1928 | 2009 | 		status = fd;  | 
 | 
0 commit comments