Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pcap-linux.c - if kernel filter cannot be set, BPF filter setup will fail with "Machine is not on the network" #549

Closed
traviswparker opened this issue Jan 10, 2017 · 4 comments

Comments

@traviswparker
Copy link

If we can't set a kernel filter and there is no existing kernel filter, attempting to detach the filter with SO_DETACH_FILTER will return ENONET, based on this code from net/core/sock.c:

403                 case SO_DETACH_FILTER:
404                         spin_lock_bh(&sk->lock.slock);
405                         filter = sk->filter;
406                         if (filter) {
407                                 sk->filter = NULL;
408                                 spin_unlock_bh(&sk->lock.slock);
409                                 sk_filter_release(sk, filter);
410                                 break;
411                         }
412                         spin_unlock_bh(&sk->lock.slock);
413                         ret = -ENONET;

in libpcap/pcap-linux.c @ 2727:

	if (handlep->filter_in_userland) {
		if (reset_kernel_filter(handle) == -1) {
			pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
			    "can't remove kernel filter: %s",
			    pcap_strerror(errno));
			err = -2;	/* fatal error */
		}
       }

....

  static int
  reset_kernel_filter(pcap_t *handle)
  {
	/*
	 * setsockopt() barfs unless it get a dummy parameter.
	 * valgrind whines unless the value is initialized,
	 * as it has no idea that setsockopt() ignores its
	 * parameter.
	 */
	int dummy = 0;

	return setsockopt(handle->fd, SOL_SOCKET, SO_DETACH_FILTER,
				   &dummy, sizeof(dummy));
  }

This will cause reset_kernel_filter to return -1 and setting the BPF to fail. The failure when running tcpdump is:

Warning: Kernel filter failed: Cannot allocate memory
tcpdump: can't remove kernel filter: Machine is not on the network

ENONET should be ignored when resetting a possibly nonexistant kernel filter:

if (reset_kernel_filter(handle) == -1 && errno != ENONET) {
  ...handle actual failure... 
}
@guyharris
Copy link
Member

guyharris commented Jan 10, 2017

based on this code from net/core/sock.c

Presumably either this is an old version of the kernel code, where somebody incorrectly typed ENONET rather than ENOENT (later fixed), or you incorrectly typed ENONET rather than ENOENT.

guyharris added a commit that referenced this issue Jan 10, 2017
It means "there was no filter on the socket"; as the goal of this
routine is to remove whatever filter is on the socket, it means that the
goal has been achieved by virtue of there not having been a filter there
in the first place, so just return 0, meaning "success".

See GitHub issue #549.
@traviswparker
Copy link
Author

You're right, I was looking at some old kernel sources, but I can confirm errno is ENONET in 2.6.x.

So you might want to ignore ENOENT and ENONET.

@guyharris
Copy link
Member

Amazingly, that was from an old version of the kernel code, where somebody incorrectly typed ENONET rather than ENOENT. That typo dates back at least to 2.4.20, and was probably not fixed until 2.6.24 (it's fixed in 2.6.24.2; I didn't check whether it was fixed in 2.6.24 or not).

In change c62ae94 I've changed it to ignore ENONET as well as ENOENT.

@guyharris
Copy link
Member

Probably fixed in the process of moving the filter-detach code to sk_detach_filter().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants