From: David Ward Date: Tue, 20 Dec 2011 20:49:14 +0000 (-0500) Subject: Improve 'inbound'/'outbound' capture filters under Linux. X-Git-Tag: libpcap-1.3-bp~10^2^2 X-Git-Url: https://git.tcpdump.org/libpcap/commitdiff_plain/ce60a2e924abc1d5fce8909c0741264ac6a945a2 Improve 'inbound'/'outbound' capture filters under Linux. Fix kernel filtering with Linux cooked captures. Filter other data link types under Linux by reading sll_pkttype in the ancillary data. All traffic sent by remote hosts is passed by the 'inbound' filter. --- diff --git a/gencode.c b/gencode.c index 7c8501a6..be8176b6 100644 --- a/gencode.c +++ b/gencode.c @@ -84,6 +84,10 @@ static const char rcsid[] _U_ = #include "pcap/sll.h" #include "pcap/ipnet.h" #include "arcnet.h" +#if defined(PF_PACKET) && defined(SO_ATTACH_FILTER) +#include +#include +#endif #ifdef HAVE_NET_PFVAR_H #include #include @@ -7481,9 +7485,13 @@ gen_multicast(proto) } /* - * generate command for inbound/outbound. It's here so we can - * make it link-type specific. 'dir' = 0 implies "inbound", - * = 1 implies "outbound". + * Filter on inbound (dir == 0) or outbound (dir == 1) traffic. + * Outbound traffic is sent by this machine, while inbound traffic is + * sent by a remote machine (and may include packets destined for a + * unicast or multicast link-layer address we are not subscribing to). + * These are the same definitions implemented by pcap_setdirection(). + * Capturing only unicast traffic destined for this host is probably + * better accomplished using a higher-layer filter. */ struct block * gen_inbound(dir) @@ -7513,23 +7521,11 @@ gen_inbound(dir) break; case DLT_LINUX_SLL: - if (dir) { - /* - * Match packets sent by this machine. - */ - b0 = gen_cmp(OR_LINK, 0, BPF_H, LINUX_SLL_OUTGOING); - } else { - /* - * Match packets sent to this machine. - * (No broadcast or multicast packets, or - * packets sent to some other machine and - * received promiscuously.) - * - * XXX - packets sent to other machines probably - * shouldn't be matched, but what about broadcast - * or multicast packets we received? - */ - b0 = gen_cmp(OR_LINK, 0, BPF_H, LINUX_SLL_HOST); + /* match outgoing packets */ + b0 = gen_cmp(OR_LINK, 0, BPF_H, LINUX_SLL_OUTGOING); + if (!dir) { + /* to filter on inbound traffic, invert the match */ + gen_not(b0); } break; @@ -7585,10 +7581,20 @@ gen_inbound(dir) break; default: +#if defined(PF_PACKET) && defined(SO_ATTACH_FILTER) + /* match outgoing packets */ + b0 = gen_cmp(OR_LINK, SKF_AD_OFF + SKF_AD_PKTTYPE, BPF_H, + PACKET_OUTGOING); + if (!dir) { + /* to filter on inbound traffic, invert the match */ + gen_not(b0); + } +#else /* defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */ bpf_error("inbound/outbound not supported on linktype %d", linktype); b0 = NULL; /* NOTREACHED */ +#endif /* defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */ } return (b0); } diff --git a/pcap-linux.c b/pcap-linux.c index d4f50b7d..c722badf 100644 --- a/pcap-linux.c +++ b/pcap-linux.c @@ -5403,13 +5403,19 @@ fix_offset(struct bpf_insn *p) * header. */ p->k -= SLL_HDR_LEN; + } else if (p->k == 0) { + /* + * It's the packet type field; map it to the special magic + * kernel offset for that field. + */ + p->k = SKF_AD_OFF + SKF_AD_PKTTYPE; } else if (p->k == 14) { /* * It's the protocol field; map it to the special magic * kernel offset for that field. */ p->k = SKF_AD_OFF + SKF_AD_PROTOCOL; - } else { + } else if ((bpf_int32)(p->k) > 0) { /* * It's within the header, but it's not one of those * fields; we can't do that in the kernel, so punt