xref: /freebsd/tests/sys/netpfil/common/sniffer.py (revision d7c9de2d)
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		if self._defrag:
60d7c9de2dSKajetan Staszkiewicz			# With fragment reassembly we can't stop the sniffer after catching
61d7c9de2dSKajetan Staszkiewicz			# the good packets, as those have not been reassembled. We must
62d7c9de2dSKajetan Staszkiewicz			#  wait for sniffer to finish and check returned packets instead.
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)
67d7c9de2dSKajetan Staszkiewicz		else:
6895312530SKristof Provost			self.packets = sp.sniff(iface=self._recvif,
6967557372SKristof Provost				stop_filter=self._checkPacket, timeout=self._timeout,
7067557372SKristof Provost				started_callback=self._startedCb)
71