Don't use pcap_open_live
Instead, only activate the pcap handle once all relevant options have been set. Also, increate the timeout length. This *might* fix issues where users were reporting their routers not responding[1] on Windows or macOS, whereas everything worked on Linux (such as #111). [1] "No response after 60 seconds. Bailing out."
This commit is contained in:
parent
c92753e1a8
commit
f6990ac433
2 changed files with 95 additions and 29 deletions
1
Makefile
1
Makefile
|
@ -3,6 +3,7 @@ PKG_CONFIG ?= pkg-config
|
|||
PREFIX ?= /usr/local
|
||||
VERSION := $(shell if [ -d .git ] && which git 2>&1 > /dev/null; then git describe --always | tail -c +2; else echo $$STANDALONE_VERSION; fi)
|
||||
CFLAGS += -Wall -g -DNMRPFLASH_VERSION=\"$(VERSION)\"
|
||||
LDFLAGS += -ldl
|
||||
SUFFIX ?=
|
||||
MACOS_SDK ?= macosx11.1
|
||||
|
||||
|
|
123
ethsock.c
123
ethsock.c
|
@ -44,6 +44,7 @@
|
|||
#include <linux/if_packet.h>
|
||||
#include <netlink/route/addr.h>
|
||||
#include <netlink/route/neighbour.h>
|
||||
#include <dlfcn.h>
|
||||
#else
|
||||
#define NMRPFLASH_AF_PACKET AF_LINK
|
||||
#include <net/if_types.h>
|
||||
|
@ -92,6 +93,41 @@ static int x_pcap_findalldevs(pcap_if_t **devs)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int (*f_pcap_set_immediate_mode)(pcap_t*, int) = NULL;
|
||||
|
||||
static int x_pcap_set_immediate_mode(pcap_t *p, int immediate_mode)
|
||||
{
|
||||
if (!f_pcap_set_immediate_mode) {
|
||||
f_pcap_set_immediate_mode = dlsym(NULL, "pcap_set_immediate_mode");
|
||||
}
|
||||
|
||||
if (verbosity > 2) {
|
||||
fprintf(stderr, "pcap_set_immediate_mode = %p\n", f_pcap_set_immediate_mode);
|
||||
}
|
||||
|
||||
if (f_pcap_set_immediate_mode) {
|
||||
return f_pcap_set_immediate_mode(p, immediate_mode);
|
||||
} else {
|
||||
// silently ignore
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NMRPFLASH_BSD
|
||||
static int bsd_set_immediate_mode(pcap_t *p, int immediate_mode)
|
||||
{
|
||||
// if we have "pcap_set_immediate_mode", then there's no need to call this function. the
|
||||
// reason for having both, is that this function must be called *after* activation, whereas
|
||||
// pcap_set_immediate_mode must be called *before* activation!
|
||||
|
||||
if (f_pcap_set_immediate_mode) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ioctl(pcap_fileno(p), BIOCIMMEDIATE, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool intf_get_pcap_flags(const char *intf, bpf_u_int32 *flags)
|
||||
{
|
||||
pcap_if_t *devs, *dev;
|
||||
|
@ -608,7 +644,6 @@ struct ethsock *ethsock_create(const char *intf, uint16_t protocol)
|
|||
struct ethsock *sock;
|
||||
bool is_bridge = false;
|
||||
int err;
|
||||
int promisc;
|
||||
|
||||
#ifdef NMRPFLASH_WINDOWS
|
||||
intf = intf_name_to_wpcap(intf);
|
||||
|
@ -624,28 +659,56 @@ struct ethsock *ethsock_create(const char *intf, uint16_t protocol)
|
|||
}
|
||||
|
||||
buf[0] = '\0';
|
||||
|
||||
sock->intf = intf;
|
||||
promisc = true;
|
||||
|
||||
do {
|
||||
sock->pcap = pcap_open_live(sock->intf, BUFSIZ, promisc, 1, buf);
|
||||
if (!sock->pcap) {
|
||||
if (!promisc) {
|
||||
fprintf(stderr, "Error: %s.\n", buf);
|
||||
goto cleanup;
|
||||
} else {
|
||||
fprintf(stderr, "Warning: failed to enable promiscous mode.\n");
|
||||
promisc = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} while (!sock->pcap);
|
||||
sock->pcap = pcap_create(sock->intf, buf);
|
||||
if (!sock->pcap) {
|
||||
fprintf(stderr, "pcap_create: %s\n", buf);
|
||||
}
|
||||
|
||||
if (*buf) {
|
||||
fprintf(stderr, "Warning: %s.\n", buf);
|
||||
}
|
||||
|
||||
err = pcap_set_snaplen(sock->pcap, BUFSIZ);
|
||||
if (err) {
|
||||
pcap_perror(sock->pcap, "pcap_set_snaplen");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
err = pcap_set_promisc(sock->pcap, 1);
|
||||
if (err) {
|
||||
pcap_perror(sock->pcap, "pcap_set_promisc");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
err = pcap_set_timeout(sock->pcap, 200);
|
||||
if (err) {
|
||||
pcap_perror(sock->pcap, "pcap_set_timeout");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
err = x_pcap_set_immediate_mode(sock->pcap, 1);
|
||||
if (err) {
|
||||
pcap_perror(sock->pcap, "pcap_set_immediate_mode");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
#ifdef NMRPFLASH_WINDOWS
|
||||
err = pcap_setmintocopy(sock->pcap, 0);
|
||||
if (err) {
|
||||
pcap_perror(sock->pcap, "pcap_setmintocopy");
|
||||
goto cleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
err = pcap_activate(sock->pcap);
|
||||
if (err < 0) {
|
||||
pcap_perror(sock->pcap, "pcap_activate");
|
||||
goto cleanup;
|
||||
} else if (err > 0) {
|
||||
fprintf(stderr, "Warning: %s.\n", pcap_geterr(sock->pcap));
|
||||
}
|
||||
|
||||
if (pcap_datalink(sock->pcap) != DLT_EN10MB) {
|
||||
fprintf(stderr, "%s is not an ethernet interface.\n",
|
||||
intf);
|
||||
|
@ -662,25 +725,27 @@ struct ethsock *ethsock_create(const char *intf, uint16_t protocol)
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
#ifndef NMRPFLASH_WINDOWS
|
||||
sock->fd = pcap_get_selectable_fd(sock->pcap);
|
||||
if (sock->fd == -1) {
|
||||
pcap_perror(sock->pcap, "pcap_get_selectable_fd");
|
||||
goto cleanup;
|
||||
}
|
||||
#else
|
||||
#ifdef NMRPFLASH_WINDOWS
|
||||
sock->handle = pcap_getevent(sock->pcap);
|
||||
if (!sock->handle) {
|
||||
pcap_perror(sock->pcap, "pcap_getevent");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
err = pcap_setmintocopy(sock->pcap, 1);
|
||||
if (err) {
|
||||
pcap_perror(sock->pcap, "pcap_setmintocopy");
|
||||
#else
|
||||
sock->fd = pcap_get_selectable_fd(sock->pcap);
|
||||
if (sock->fd == -1) {
|
||||
pcap_perror(sock->pcap, "pcap_get_selectable_fd");
|
||||
goto cleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NMRPFLASH_BSD
|
||||
err = bsd_set_immediate_mode(sock->pcap, 1);
|
||||
if (err) {
|
||||
fprintf(stderr, "Warning: setting immediate mode failed: %s.\n", strerror(errno));
|
||||
goto cleanup;
|
||||
}
|
||||
#endif // NMRPFLASH_BSD
|
||||
#endif // NMRPFLASH_WINDOWS
|
||||
|
||||
snprintf(buf, sizeof(buf), "ether proto 0x%04x and not ether src %s",
|
||||
protocol, mac_to_str(sock->hwaddr));
|
||||
|
|
Loading…
Add table
Reference in a new issue