165d553b0SKristof Provost# 24d846d26SWarner Losh# SPDX-License-Identifier: BSD-2-Clause 365d553b0SKristof Provost# 465d553b0SKristof Provost# Copyright (c) 2017 Kristof Provost <kp@FreeBSD.org> 565d553b0SKristof Provost# 665d553b0SKristof Provost# Redistribution and use in source and binary forms, with or without 765d553b0SKristof Provost# modification, are permitted provided that the following conditions 865d553b0SKristof Provost# are met: 965d553b0SKristof Provost# 1. Redistributions of source code must retain the above copyright 1065d553b0SKristof Provost# notice, this list of conditions and the following disclaimer. 1165d553b0SKristof Provost# 2. Redistributions in binary form must reproduce the above copyright 1265d553b0SKristof Provost# notice, this list of conditions and the following disclaimer in the 1365d553b0SKristof Provost# documentation and/or other materials provided with the distribution. 1465d553b0SKristof Provost# 1565d553b0SKristof Provost# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1665d553b0SKristof Provost# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1765d553b0SKristof Provost# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1865d553b0SKristof Provost# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1965d553b0SKristof Provost# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2065d553b0SKristof Provost# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2165d553b0SKristof Provost# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2265d553b0SKristof Provost# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2365d553b0SKristof Provost# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2465d553b0SKristof Provost# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2565d553b0SKristof Provost# SUCH DAMAGE. 2665d553b0SKristof Provost# 2795312530SKristof Provost 2895312530SKristof Provostimport threading 2995312530SKristof Provostimport scapy.all as sp 303e87f800SKristof Provostimport sys 3195312530SKristof Provost 3295312530SKristof Provostclass Sniffer(threading.Thread): 33d7c9de2dSKajetan Staszkiewicz def __init__(self, args, check_function, recvif, timeout=3, defrag=False): 3495312530SKristof Provost threading.Thread.__init__(self) 3595312530SKristof Provost 3667557372SKristof Provost self._sem = threading.Semaphore(0) 3795312530SKristof Provost self._args = args 383e87f800SKristof Provost self._timeout = timeout 39cd579b6fSKristof Provost self._recvif = recvif 4095312530SKristof Provost self._check_function = check_function 41d7c9de2dSKajetan Staszkiewicz self._defrag = defrag 42a39dedebSKajetan Staszkiewicz self.correctPackets = 0 4395312530SKristof Provost 4495312530SKristof Provost self.start() 4567557372SKristof Provost if not self._sem.acquire(timeout=30): 4667557372SKristof Provost raise Exception("Failed to start sniffer") 4795312530SKristof Provost 4895312530SKristof Provost def _checkPacket(self, packet): 4995312530SKristof Provost ret = self._check_function(self._args, packet) 5095312530SKristof Provost if ret: 51a39dedebSKajetan Staszkiewicz self.correctPackets += 1 5295312530SKristof Provost return ret 5395312530SKristof Provost 5467557372SKristof Provost def _startedCb(self): 5567557372SKristof Provost self._sem.release() 5667557372SKristof Provost 5795312530SKristof Provost def run(self): 583e87f800SKristof Provost self.packets = [] 59d7c9de2dSKajetan Staszkiewicz # With fragment reassembly we can't stop the sniffer after catching 60d7c9de2dSKajetan Staszkiewicz # the good packets, as those have not been reassembled. We must 61d7c9de2dSKajetan Staszkiewicz # wait for sniffer to finish and check returned packets instead. 62*65074f6fSKajetan Staszkiewicz if self._defrag == 'IPv4': 63d7c9de2dSKajetan Staszkiewicz self.packets = sp.sniff(session=sp.IPSession, iface=self._recvif, 64d7c9de2dSKajetan Staszkiewicz timeout=self._timeout, started_callback=self._startedCb) 65d7c9de2dSKajetan Staszkiewicz for p in self.packets: 66d7c9de2dSKajetan Staszkiewicz self._checkPacket(p) 67*65074f6fSKajetan Staszkiewicz elif self._defrag == 'IPv6': 68*65074f6fSKajetan Staszkiewicz self.packets = sp.sniff(session=sp.DefaultSession, iface=self._recvif, 69*65074f6fSKajetan Staszkiewicz timeout=self._timeout, started_callback=self._startedCb) 70*65074f6fSKajetan Staszkiewicz for p in sp.defragment6(self.packets): 71*65074f6fSKajetan Staszkiewicz self._checkPacket(p) 72d7c9de2dSKajetan Staszkiewicz else: 7395312530SKristof Provost self.packets = sp.sniff(iface=self._recvif, 7467557372SKristof Provost stop_filter=self._checkPacket, timeout=self._timeout, 7567557372SKristof Provost started_callback=self._startedCb) 76