|
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