Repository: secdev/scapy

Issue:
Exception raised with bad BPF filter
The following command raises an exception:
```
sniff(offline=IP()/UDP(), filter="bad filter", quiet=True)
```

The `tcpdump()` must detect the error from the `tcpdump` command `(tcpdump: syntax error in filter expression: syntax error`).


Discussion:

Resolving patch:
diff --git a/scapy/sendrecv.py b/scapy/sendrecv.py
--- a/scapy/sendrecv.py
+++ b/scapy/sendrecv.py
@@ -855,12 +855,12 @@ def _run(self,
                     all(isinstance(elt, str) for elt in offline):
                 sniff_sockets.update((PcapReader(
                     fname if flt is None else
-                    tcpdump(fname, args=["-w", "-", flt], getfd=True)
+                    tcpdump(fname, args=["-w", "-"], flt=flt, getfd=True)
                 ), fname) for fname in offline)
             elif isinstance(offline, dict):
                 sniff_sockets.update((PcapReader(
                     fname if flt is None else
-                    tcpdump(fname, args=["-w", "-", flt], getfd=True)
+                    tcpdump(fname, args=["-w", "-"], flt=flt, getfd=True)
                 ), label) for fname, label in six.iteritems(offline))
             else:
                 # Write Scapy Packet objects to a pcap file
@@ -878,7 +878,8 @@ def _write_to_pcap(packets_list):
                 sniff_sockets[PcapReader(
                     offline if flt is None else
                     tcpdump(offline,
-                            args=["-w", "-", flt],
+                            args=["-w", "-"],
+                            flt=flt,
                             getfd=True,
                             quiet=quiet)
                 )] = offline
diff --git a/scapy/utils.py b/scapy/utils.py
--- a/scapy/utils.py
+++ b/scapy/utils.py
@@ -971,6 +971,10 @@ def __call__(cls, filename):
         """
         i = cls.__new__(cls, cls.__name__, cls.__bases__, cls.__dict__)
         filename, fdesc, magic = cls.open(filename)
+        if not magic:
+            raise Scapy_Exception(
+                "No data could be read!"
+            )
         try:
             i.__init__(filename, fdesc, magic)
         except Scapy_Exception:
@@ -1626,7 +1630,7 @@ def _guess_linktype_value(name):
 
 
 @conf.commands.register
-def tcpdump(pktlist=None, dump=False, getfd=False, args=None,
+def tcpdump(pktlist=None, dump=False, getfd=False, args=None, flt=None,
             prog=None, getproc=False, quiet=False, use_tempfile=None,
             read_stdin_opts=None, linktype=None, wait=True,
             _suppress=False):
@@ -1654,7 +1658,7 @@ def tcpdump(pktlist=None, dump=False, getfd=False, args=None,
         Packet instances. Can also be a filename (as a string), an open
         file-like object that must be a file format readable by
         tshark (Pcap, PcapNg, etc.) or None (to sniff)
-
+    :param flt: a filter to use with tcpdump
     :param dump:    when set to True, returns a string instead of displaying it.
     :param getfd:   when set to True, returns a file-like object to read data
         from tcpdump or tshark from.
@@ -1756,6 +1760,12 @@ def tcpdump(pktlist=None, dump=False, getfd=False, args=None,
         # Make a copy of args
         args = list(args)
 
+    if flt is not None:
+        # Check the validity of the filter
+        from scapy.arch.common import compile_filter
+        compile_filter(flt)
+        args.append(flt)
+
     stdout = subprocess.PIPE if dump or getfd else None
     stderr = open(os.devnull) if quiet else None
     proc = None


Test patch:
diff --git a/test/regression.uts b/test/regression.uts
--- a/test/regression.uts
+++ b/test/regression.uts
@@ -7180,6 +7180,16 @@ assert(all(UDP in p for p in l))
 l = sniff(offline=IP()/UDP(sport=(10000, 10001)), filter="tcp")
 assert len(l) == 0
 
+= Check offline sniff() with Packets, tcpdump and a bad filter
+~ tcpdump
+
+try:
+    sniff(offline=IP()/UDP(), filter="bad filter")
+except Scapy_Exception:
+    pass
+else:
+    assert False
+
 = Check offline sniff with lfilter
 assert len(sniff(offline=[IP()/UDP(), IP()/TCP()], lfilter=lambda x: TCP in x)) == 1