Skip to content

Commit ffb13dc

Browse files
committed
Fix interface existence check on Linux before privileged operations
When attempting to open a non-existent network interface on Linux, libpcap would return PCAP_ERROR_PERM_DENIED instead of the correct PCAP_ERROR_NO_SUCH_DEVICE. This occurred because the privileged socket(PF_PACKET, SOCK_RAW, 0) call in setup_socket() would fail with permission errors before interface validation could occur. This fix adds an interface existence check using an unprivileged AF_INET socket and SIOCGIFINDEX ioctl before attempting to create the privileged packet socket. Non-existent interfaces now correctly return PCAP_ERROR_NO_SUCH_DEVICE. This resolves the issue where applications like tcpdump would report "Permission denied" instead of "No such device exists" for non-existent interfaces, breaking their fallback logic from interface names to indices. Note: BSD/macOS platforms have the same underlying issue where BPF device access fails with permission errors before interface validation. This should be addressed in a separate commit. Fixes: libpcap issue #1538 Related: tcpdump issue #1334 Signed-off-by: Afshin Paydar <afshin.paydar@deriv.com>
1 parent 19fd783 commit ffb13dc

File tree

1 file changed

+62
-6
lines changed

1 file changed

+62
-6
lines changed

pcap-linux.c

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ static const struct timeval netdown_timeout = {
345345
static int iface_get_id(int fd, const char *device, char *ebuf);
346346
static int iface_get_mtu(int fd, const char *device, char *ebuf);
347347
static int iface_get_arptype(int fd, const char *device, char *ebuf);
348+
static int iface_exists(const char *device, char *ebuf);
348349
static int iface_bind(int fd, int ifindex, char *ebuf, int protocol);
349350
static int enter_rfmon_mode(pcap_t *handle, int sock_fd,
350351
const char *device);
@@ -2426,6 +2427,17 @@ setup_socket(pcap_t *handle, int is_any_device)
24262427
int err = 0;
24272428
struct packet_mreq mr;
24282429

2430+
/*
2431+
* Check if the interface exists before attempting to open
2432+
* the privileged packet socket, so we can return the correct
2433+
* error for non-existent interfaces.
2434+
*/
2435+
if (!is_any_device) {
2436+
status = iface_exists(device, handle->errbuf);
2437+
if (status != 0)
2438+
return status;
2439+
}
2440+
24292441
/*
24302442
* Open a socket with protocol family packet. If cooked is true,
24312443
* we open a SOCK_DGRAM socket for the cooked interface, otherwise
@@ -4812,6 +4824,50 @@ pcap_setfilter_linux(pcap_t *handle, struct bpf_program *filter)
48124824
return 0;
48134825
}
48144826

4827+
/*
4828+
* Check if the given interface exists. Return 0 on success,
4829+
* PCAP_ERROR_NO_SUCH_DEVICE if the interface doesn't exist,
4830+
* or PCAP_ERROR on other failures.
4831+
*/
4832+
static int
4833+
iface_exists(const char *device, char *ebuf)
4834+
{
4835+
int fd;
4836+
struct ifreq ifr;
4837+
4838+
if (strlen(device) >= sizeof(ifr.ifr_name)) {
4839+
ebuf[0] = '\0';
4840+
return PCAP_ERROR_NO_SUCH_DEVICE;
4841+
}
4842+
4843+
fd = socket(AF_INET, SOCK_DGRAM, 0);
4844+
if (fd < 0) {
4845+
pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
4846+
errno, "socket");
4847+
return PCAP_ERROR;
4848+
}
4849+
4850+
memset(&ifr, 0, sizeof(ifr));
4851+
pcapint_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
4852+
4853+
if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
4854+
int save_errno = errno;
4855+
close(fd);
4856+
4857+
if (save_errno == ENODEV) {
4858+
ebuf[0] = '\0';
4859+
return PCAP_ERROR_NO_SUCH_DEVICE;
4860+
} else {
4861+
pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
4862+
save_errno, "SIOCGIFINDEX on %s", device);
4863+
return PCAP_ERROR;
4864+
}
4865+
}
4866+
4867+
close(fd);
4868+
return 0;
4869+
}
4870+
48154871
/*
48164872
* Return the index of the given device name. Fill ebuf and return
48174873
* -1 on failure.
@@ -5164,13 +5220,13 @@ iface_get_ts_types(const char *device, pcap_t *handle, char *ebuf)
51645220

51655221
case ENODEV:
51665222
/*
5167-
* OK, no such device.
5168-
* The user will find that out when they try to
5169-
* activate the device; just return an empty
5170-
* list of time stamp types.
5223+
* No such device.
5224+
*
5225+
* There's nothing more to say, so clear the
5226+
* error message.
51715227
*/
5172-
handle->tstamp_type_list = NULL;
5173-
return 0;
5228+
ebuf[0] = '\0';
5229+
return PCAP_ERROR_NO_SUCH_DEVICE;
51745230

51755231
default:
51765232
/*

0 commit comments

Comments
 (0)