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
 | 
					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)
 | 
					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)\"
 | 
					CFLAGS += -Wall -g -DNMRPFLASH_VERSION=\"$(VERSION)\"
 | 
				
			||||||
 | 
					LDFLAGS += -ldl
 | 
				
			||||||
SUFFIX ?=
 | 
					SUFFIX ?=
 | 
				
			||||||
MACOS_SDK ?= macosx11.1
 | 
					MACOS_SDK ?= macosx11.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										123
									
								
								ethsock.c
									
										
									
									
									
								
							
							
						
						
									
										123
									
								
								ethsock.c
									
										
									
									
									
								
							| 
						 | 
					@ -44,6 +44,7 @@
 | 
				
			||||||
#include <linux/if_packet.h>
 | 
					#include <linux/if_packet.h>
 | 
				
			||||||
#include <netlink/route/addr.h>
 | 
					#include <netlink/route/addr.h>
 | 
				
			||||||
#include <netlink/route/neighbour.h>
 | 
					#include <netlink/route/neighbour.h>
 | 
				
			||||||
 | 
					#include <dlfcn.h>
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#define NMRPFLASH_AF_PACKET AF_LINK
 | 
					#define NMRPFLASH_AF_PACKET AF_LINK
 | 
				
			||||||
#include <net/if_types.h>
 | 
					#include <net/if_types.h>
 | 
				
			||||||
| 
						 | 
					@ -92,6 +93,41 @@ static int x_pcap_findalldevs(pcap_if_t **devs)
 | 
				
			||||||
	return 0;
 | 
						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)
 | 
					static bool intf_get_pcap_flags(const char *intf, bpf_u_int32 *flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	pcap_if_t *devs, *dev;
 | 
						pcap_if_t *devs, *dev;
 | 
				
			||||||
| 
						 | 
					@ -608,7 +644,6 @@ struct ethsock *ethsock_create(const char *intf, uint16_t protocol)
 | 
				
			||||||
	struct ethsock *sock;
 | 
						struct ethsock *sock;
 | 
				
			||||||
	bool is_bridge = false;
 | 
						bool is_bridge = false;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	int promisc;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef NMRPFLASH_WINDOWS
 | 
					#ifdef NMRPFLASH_WINDOWS
 | 
				
			||||||
	intf = intf_name_to_wpcap(intf);
 | 
						intf = intf_name_to_wpcap(intf);
 | 
				
			||||||
| 
						 | 
					@ -624,28 +659,56 @@ struct ethsock *ethsock_create(const char *intf, uint16_t protocol)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buf[0] = '\0';
 | 
						buf[0] = '\0';
 | 
				
			||||||
 | 
					 | 
				
			||||||
	sock->intf = intf;
 | 
						sock->intf = intf;
 | 
				
			||||||
	promisc = true;
 | 
						sock->pcap = pcap_create(sock->intf, buf);
 | 
				
			||||||
 | 
						if (!sock->pcap) {
 | 
				
			||||||
	do {
 | 
							fprintf(stderr, "pcap_create: %s\n", buf);
 | 
				
			||||||
		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);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (*buf) {
 | 
						if (*buf) {
 | 
				
			||||||
		fprintf(stderr, "Warning: %s.\n", 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) {
 | 
						if (pcap_datalink(sock->pcap) != DLT_EN10MB) {
 | 
				
			||||||
		fprintf(stderr, "%s is not an ethernet interface.\n",
 | 
							fprintf(stderr, "%s is not an ethernet interface.\n",
 | 
				
			||||||
				intf);
 | 
									intf);
 | 
				
			||||||
| 
						 | 
					@ -662,25 +725,27 @@ struct ethsock *ethsock_create(const char *intf, uint16_t protocol)
 | 
				
			||||||
		goto cleanup;
 | 
							goto cleanup;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef NMRPFLASH_WINDOWS
 | 
					#ifdef 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
 | 
					 | 
				
			||||||
	sock->handle = pcap_getevent(sock->pcap);
 | 
						sock->handle = pcap_getevent(sock->pcap);
 | 
				
			||||||
	if (!sock->handle) {
 | 
						if (!sock->handle) {
 | 
				
			||||||
		pcap_perror(sock->pcap, "pcap_getevent");
 | 
							pcap_perror(sock->pcap, "pcap_getevent");
 | 
				
			||||||
		goto cleanup;
 | 
							goto cleanup;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
	err = pcap_setmintocopy(sock->pcap, 1);
 | 
						sock->fd = pcap_get_selectable_fd(sock->pcap);
 | 
				
			||||||
	if (err) {
 | 
						if (sock->fd == -1) {
 | 
				
			||||||
		pcap_perror(sock->pcap, "pcap_setmintocopy");
 | 
							pcap_perror(sock->pcap, "pcap_get_selectable_fd");
 | 
				
			||||||
		goto cleanup;
 | 
							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",
 | 
						snprintf(buf, sizeof(buf), "ether proto 0x%04x and not ether src %s",
 | 
				
			||||||
			protocol, mac_to_str(sock->hwaddr));
 | 
								protocol, mac_to_str(sock->hwaddr));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue