Skip to content

Commit 03f4176

Browse files
authored
Merge pull request #1740 from gpotter2/af-inconsistent
Fix inconsistencies between attach_filter
2 parents ae3e206 + 1906566 commit 03f4176

File tree

6 files changed

+59
-58
lines changed

6 files changed

+59
-58
lines changed

scapy/arch/bpf/core.py

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from scapy.config import conf
99
from scapy.error import Scapy_Exception, warning
1010
from scapy.data import ARPHDR_LOOPBACK, ARPHDR_ETHER
11-
from scapy.arch.common import get_if, get_bpf_pointer
11+
from scapy.arch.common import get_if, compile_filter
1212
from scapy.consts import LOOPBACK_NAME
1313

1414
from scapy.arch.bpf.consts import BIOCSETF, SIOCGIFFLAGS, BIOCSETIF
@@ -98,23 +98,9 @@ def get_dev_bpf():
9898
raise Scapy_Exception("No /dev/bpf handle is available !")
9999

100100

101-
def attach_filter(fd, iface, bpf_filter_string):
101+
def attach_filter(fd, bpf_filter, iface):
102102
"""Attach a BPF filter to the BPF file descriptor"""
103-
104-
# Retrieve the BPF byte code in decimal
105-
cmd_fmt = "%s -p -i %s -ddd -s 1600 '%s'"
106-
command = cmd_fmt % (conf.prog.tcpdump, iface, bpf_filter_string)
107-
try:
108-
f = os.popen(command)
109-
except OSError as msg:
110-
raise Scapy_Exception("Failed to execute tcpdump: (%s)" % msg)
111-
112-
# Convert the byte code to a BPF program structure
113-
lines = f.readlines()
114-
if lines == []:
115-
raise Scapy_Exception("Got an empty BPF filter from tcpdump !")
116-
117-
bp = get_bpf_pointer(lines)
103+
bp = compile_filter(bpf_filter, iface)
118104
# Assign the BPF program to the interface
119105
ret = LIBC.ioctl(c_int(fd), BIOCSETF, cast(pointer(bp), c_char_p))
120106
if ret < 0:

scapy/arch/bpf/supersocket.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ def __init__(self, iface=None, type=ETH_P_ALL, promisc=None, filter=None,
110110
else:
111111
filter = "not (%s)" % conf.except_filter
112112
if filter is not None:
113-
attach_filter(self.ins, self.iface, filter)
113+
attach_filter(self.ins, filter, self.iface)
114114

115115
# Set the guessed packet class
116116
self.guessed_cls = self.guess_cls()

scapy/arch/common.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,30 @@
1010
# Important Note: This file is not needed on Windows, and mustn't be loaded
1111

1212
import socket
13+
import subprocess
1314
from fcntl import ioctl
1415
import os
1516
import struct
1617
import ctypes
1718
from ctypes import POINTER, Structure
1819
from ctypes import c_uint, c_uint32, c_ushort, c_ubyte
1920
from scapy.config import conf
21+
from scapy.data import MTU
22+
from scapy.error import Scapy_Exception
2023
import scapy.modules.six as six
2124

25+
# BOOT
26+
27+
28+
def _check_tcpdump():
29+
with open(os.devnull, 'wb') as devnull:
30+
proc = subprocess.Popen([conf.prog.tcpdump, "--version"],
31+
stdout=devnull, stderr=subprocess.STDOUT)
32+
return proc.wait() == 0
33+
34+
35+
TCPDUMP = _check_tcpdump()
36+
2237
# UTILS
2338

2439

@@ -95,3 +110,32 @@ def get_bpf_pointer(tcpdump_lines):
95110

96111
# Create the BPF program
97112
return bpf_program(size, bip)
113+
114+
115+
def compile_filter(bpf_filter, iface=None):
116+
"""Asks Tcpdump to parse the filter, then build the matching
117+
BPF bytecode using get_bpf_pointer.
118+
"""
119+
if not TCPDUMP:
120+
raise Scapy_Exception("tcpdump is not available. Cannot use filter !")
121+
try:
122+
process = subprocess.Popen([
123+
conf.prog.tcpdump,
124+
"-p",
125+
"-i", (conf.iface if iface is None else iface),
126+
"-ddd",
127+
"-s", str(MTU),
128+
bpf_filter],
129+
stdout=subprocess.PIPE,
130+
stderr=subprocess.PIPE
131+
)
132+
except OSError as ex:
133+
raise Scapy_Exception("Failed to attach filter: %s" % ex)
134+
lines, err = process.communicate()
135+
ret = process.returncode
136+
if ret:
137+
raise Scapy_Exception(
138+
"Failed to attach filter: tcpdump returned: %s" % err
139+
)
140+
lines = lines.strip().split(b"\n")
141+
return get_bpf_pointer(lines)

scapy/arch/linux.py

Lines changed: 7 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@
2929
from scapy.config import conf
3030
from scapy.data import MTU, ETH_P_ALL
3131
from scapy.supersocket import SuperSocket
32-
from scapy.error import warning, Scapy_Exception, log_interactive, \
33-
log_loading, ScapyInvalidPlatformException
34-
from scapy.arch.common import get_if, get_bpf_pointer
32+
from scapy.error import warning, Scapy_Exception, \
33+
ScapyInvalidPlatformException
34+
from scapy.arch.common import get_if, compile_filter
3535
import scapy.modules.six as six
3636
from scapy.modules.six.moves import range
3737

@@ -92,15 +92,6 @@
9292
# Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space
9393

9494

95-
with os.popen("%s -V 2> /dev/null" % conf.prog.tcpdump) as _f:
96-
if _f.close() >> 8 == 0x7f:
97-
log_loading.warning("Failed to execute tcpdump. Check it is installed and in the PATH") # noqa: E501
98-
TCPDUMP = 0
99-
else:
100-
TCPDUMP = 1
101-
del(_f)
102-
103-
10495
def get_if_raw_hwaddr(iff):
10596
return struct.unpack("16xh6s8x", get_if(iff, SIOCGIFHWADDR))
10697

@@ -139,36 +130,15 @@ def get_working_if():
139130
return LOOPBACK_NAME
140131

141132

142-
def attach_filter(s, bpf_filter, iface):
133+
def attach_filter(sock, bpf_filter, iface):
143134
# XXX We generate the filter on the interface conf.iface
144135
# because tcpdump open the "any" interface and ppp interfaces
145136
# in cooked mode. As we use them in raw mode, the filter will not
146137
# work... one solution could be to use "any" interface and translate
147138
# the filter from cooked mode to raw mode
148139
# mode
149-
if not TCPDUMP:
150-
return
151-
try:
152-
f = os.popen("%s -p -i %s -ddd -s %d '%s'" % (
153-
conf.prog.tcpdump,
154-
conf.iface if iface is None else iface,
155-
MTU,
156-
bpf_filter,
157-
))
158-
except OSError:
159-
log_interactive.warning("Failed to attach filter.",
160-
exc_info=True)
161-
return
162-
lines = f.readlines()
163-
ret = f.close()
164-
if ret:
165-
log_interactive.warning(
166-
"Failed to attach filter: tcpdump returned %d", ret
167-
)
168-
return
169-
170-
bp = get_bpf_pointer(lines)
171-
s.setsockopt(socket.SOL_SOCKET, SO_ATTACH_FILTER, bp)
140+
bp = compile_filter(bpf_filter, iface)
141+
sock.setsockopt(socket.SOL_SOCKET, SO_ATTACH_FILTER, bp)
172142

173143

174144
def set_promisc(s, iff, val=1):
@@ -468,6 +438,7 @@ def __init__(self, iface=None, type=ETH_P_ALL, promisc=None, filter=None,
468438
nofilter=0, monitor=None):
469439
self.iface = conf.iface if iface is None else iface
470440
self.type = type
441+
self.promisc = conf.sniff_promisc if promisc is None else promisc
471442
if monitor is not None:
472443
if not set_iface_monitor(iface, monitor):
473444
warning("Could not change interface mode !")
@@ -481,7 +452,6 @@ def __init__(self, iface=None, type=ETH_P_ALL, promisc=None, filter=None,
481452
filter = "not (%s)" % conf.except_filter
482453
if filter is not None:
483454
attach_filter(self.ins, filter, iface)
484-
self.promisc = conf.sniff_promisc if promisc is None else promisc
485455
if self.promisc:
486456
set_promisc(self.ins, self.iface)
487457
self.ins.bind((self.iface, type))

scapy/extlib.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ def _test_pyx():
4141
"""Returns if PyX is correctly installed or not"""
4242
try:
4343
with open(os.devnull, 'wb') as devnull:
44-
r = subprocess.check_call(["pdflatex", "--version"], stdout=devnull, stderr=subprocess.STDOUT) # noqa: E501
45-
except Exception:
44+
r = subprocess.check_call(["pdflatex", "--version"],
45+
stdout=devnull, stderr=subprocess.STDOUT)
46+
except subprocess.CalledProcessError:
4647
return False
4748
else:
4849
return r == 0

test/bpf.uts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ fd, _ = get_dev_bpf()
3535
~ needs_root
3636

3737
from scapy.arch.bpf.supersocket import attach_filter
38-
attach_filter(fd, conf.iface, "arp or icmp")
38+
attach_filter(fd, "arp or icmp", conf.iface)
3939

4040

4141
= Get network interfaces list

0 commit comments

Comments
 (0)