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