|
41 | 41 | #ifdef HAVE_SYS_IOCCOM_H |
42 | 42 | #include <sys/ioccom.h> |
43 | 43 | #endif |
| 44 | + |
| 45 | +/* |
| 46 | + * On some platforms, <sys/sockio.h> is needed for SIOCGIF* macros. |
| 47 | + * Include it conditionally based on what the build system detects. |
| 48 | + */ |
| 49 | +#if defined(HAVE_SOLARIS) || defined(__HAIKU__) |
| 50 | +#include <sys/sockio.h> |
| 51 | +#endif |
| 52 | + |
44 | 53 | #include <sys/utsname.h> |
45 | 54 |
|
46 | 55 | #if defined(__FreeBSD__) && defined(SIOCIFCREATE2) |
@@ -626,6 +635,58 @@ bpf_open(char *errbuf) |
626 | 635 | #define BPF_BIND_SUCCEEDED 0 |
627 | 636 | #define BPF_BIND_BUFFER_TOO_BIG 1 |
628 | 637 |
|
| 638 | +/* |
| 639 | + * Check if an interface exists without requiring special privileges. |
| 640 | + * Returns 0 if the interface exists, PCAP_ERROR_NO_SUCH_DEVICE if it doesn't, |
| 641 | + * or another negative error code on other failures. |
| 642 | + */ |
| 643 | +static int |
| 644 | +check_interface_exists(const char *name, char *errbuf) |
| 645 | +{ |
| 646 | +#ifndef _WIN32 |
| 647 | + int fd; |
| 648 | + struct ifreq ifr; |
| 649 | + |
| 650 | + if (strlen(name) >= sizeof(ifr.ifr_name)) { |
| 651 | + /* The name is too long, so it can't possibly exist. */ |
| 652 | + errbuf[0] = '\0'; |
| 653 | + return PCAP_ERROR_NO_SUCH_DEVICE; |
| 654 | + } |
| 655 | + |
| 656 | + fd = socket(AF_INET, SOCK_DGRAM, 0); |
| 657 | + if (fd < 0) { |
| 658 | + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, |
| 659 | + errno, "socket"); |
| 660 | + return PCAP_ERROR; |
| 661 | + } |
| 662 | + |
| 663 | + memset(&ifr, 0, sizeof(ifr)); |
| 664 | + pcapint_strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); |
| 665 | + |
| 666 | + if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { |
| 667 | + int save_errno = errno; |
| 668 | + close(fd); |
| 669 | + |
| 670 | + if (save_errno == ENXIO || save_errno == ENODEV) { |
| 671 | + /* Interface doesn't exist */ |
| 672 | + errbuf[0] = '\0'; |
| 673 | + return PCAP_ERROR_NO_SUCH_DEVICE; |
| 674 | + } else { |
| 675 | + /* Some other error occurred */ |
| 676 | + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, |
| 677 | + save_errno, "SIOCGIFFLAGS on %s", name); |
| 678 | + return PCAP_ERROR; |
| 679 | + } |
| 680 | + } |
| 681 | + |
| 682 | + close(fd); |
| 683 | + return 0; |
| 684 | +#else |
| 685 | + /* On Windows, skip the check for now */ |
| 686 | + return 0; |
| 687 | +#endif |
| 688 | +} |
| 689 | + |
629 | 690 | static int |
630 | 691 | bpf_bind(int fd, const char *name, char *errbuf) |
631 | 692 | { |
@@ -1923,6 +1984,16 @@ pcap_activate_bpf(pcap_t *p) |
1923 | 1984 | int flags = MAP_ANON; |
1924 | 1985 | #endif |
1925 | 1986 |
|
| 1987 | + /* |
| 1988 | + * Check if the interface exists before trying to open BPF device. |
| 1989 | + * This avoids reporting permission errors when the real issue is |
| 1990 | + * that the interface doesn't exist. |
| 1991 | + */ |
| 1992 | + status = check_interface_exists(p->opt.device, p->errbuf); |
| 1993 | + if (status != 0) { |
| 1994 | + goto bad; |
| 1995 | + } |
| 1996 | + |
1926 | 1997 | fd = bpf_open(p->errbuf); |
1927 | 1998 | if (fd < 0) { |
1928 | 1999 | status = fd; |
|
0 commit comments