def _capture_all( device_names: typing.List[str], filter_expression: str ) -> typing.List[typing.Tuple[str, object, LinkLayerPacket.Decoder]]: """ Begin capture on all devices in promiscuous mode. We can't use "any" because libpcap does not support promiscuous mode with it, as stated in the docs and here: https://github.com/the-tcpdump-group/libpcap/blob/bcca74d2713dc9c0a27992102c469f77bdd8dd1f/pcap-linux.c#L2522. It shouldn't be a problem because we have our filter expression that is expected to be highly efficient. Devices whose ifaces are down or that are not usable for other valid reasons will be silently filtered out here. """ import libpcap as pcap codecs = LinkLayerPacket.get_codecs() caps: typing.List[typing.Tuple[str, object, LinkLayerPacket.Decoder]] = [] try: for name in device_names: pd = _capture_single_device(name, filter_expression, list(codecs.keys())) if pd is None: _logger.info("Could not set up capture on %r", name) continue data_link_type = pcap.datalink(pd) try: _, dec = codecs[data_link_type] except LookupError: # This is where we filter out devices that certainly have no relevance, like CAN adapters. pcap.close(pd) _logger.info( "Device %r will not be used for packet capture because its data link layer type=%r " "is not supported by this library. Either the device is irrelevant, " "or the library needs to be extended to support this link layer protocol.", name, data_link_type, ) else: caps.append((name, pd, dec)) except Exception: for _, c, _ in caps: pcap.close(c) raise _logger.info( "Capture sessions with filter %r have been set up on: %s", filter_expression, list(n for n, _, _ in caps) ) return caps
def _capture_single_device( device: str, filter_expression: str, data_link_hints: typing.Sequence[int] ) -> typing.Optional[object]: """ Returns None if the interface managed by this device is not up or if it cannot be captured from for other reasons. On GNU/Linux, some virtual devices (like netfilter devices) can only be accessed by a superuser. The function will configure libpcap to use the first supported data link type from the list. If none of the specified data link types are supported, a log message is emitted but no error is raised. The available link types are listed in https://www.tcpdump.org/linktypes.html. """ import libpcap as pcap def status_to_str(error_code: int) -> str: """ Some libpcap-compatible libraries (e.g., WinPCap) do not have this function, so we have to define a fallback. """ try: return str(pcap.statustostr(error_code).decode()) except AttributeError: # pragma: no cover return f"[error {error_code}]" # This is helpful: https://github.com/karpierz/libpcap/blob/master/tests/capturetest.py err_buf = ctypes.create_string_buffer(pcap.PCAP_ERRBUF_SIZE) pd = pcap.create(device.encode(), err_buf) if pd is None: raise LinkLayerCaptureError(f"Could not instantiate pcap_t for {device!r}: {err_buf.value.decode()}") try: # Non-fatal errors are intentionally logged at a low severity level to not disturb the user unnecessarily. err = pcap.set_snaplen(pd, _SNAPSHOT_LENGTH) if err != 0: _logger.info("Could not set snapshot length for %r: %r", device, status_to_str(err)) err = pcap.set_timeout(pd, int(_BUFFER_TIMEOUT * 1e3)) if err != 0: _logger.info("Could not set timeout for %r: %r", device, status_to_str(err)) err = pcap.set_promisc(pd, 1) if err != 0: _logger.info("Could not enable promiscuous mode for %r: %r", device, status_to_str(err)) err = pcap.activate(pd) if err in (pcap.PCAP_ERROR_PERM_DENIED, pcap.PCAP_ERROR_PROMISC_PERM_DENIED): raise PermissionError(f"Capture is not permitted on {device!r}: {status_to_str(err)}") if err == pcap.PCAP_ERROR_IFACE_NOT_UP: _logger.debug("Device %r is not capturable because the iface is not up. %s", device, status_to_str(err)) pcap.close(pd) return None if err < 0: _logger.info( "Could not activate capture on %r: %s; %s", device, status_to_str(err), pcap.geterr(pd).decode() ) pcap.close(pd) return None if err > 0: _logger.info( "Capture on %r started successfully, but libpcap reported a warning: %s", device, status_to_str(err) ) # https://www.tcpdump.org/manpages/pcap_set_datalink.3pcap.html for dlt in data_link_hints: err = pcap.set_datalink(pd, dlt) if err == 0: _logger.debug("Device %r is configured to use the data link type %r", device, dlt) break else: _logger.debug( "Device %r supports none of the following data link types: %r. Last error was: %s", device, list(data_link_hints), pcap.geterr(pd).decode(), ) # https://www.tcpdump.org/manpages/pcap_compile.3pcap.html code = pcap.bpf_program() # This memory needs to be freed when closed. Fix it later. err = pcap.compile(pd, ctypes.byref(code), filter_expression.encode(), 1, pcap.PCAP_NETMASK_UNKNOWN) if err != 0: raise LinkLayerCaptureError( f"Could not compile filter expression {filter_expression!r}: {status_to_str(err)}; " f"{pcap.geterr(pd).decode()}" ) err = pcap.setfilter(pd, ctypes.byref(code)) if err != 0: raise LinkLayerCaptureError(f"Could not install filter: {status_to_str(err)}; {pcap.geterr(pd).decode()}") except Exception: pcap.close(pd) raise return typing.cast(object, pd)
def _thread_worker(self, name: str, pd: object, decoder: LinkLayerPacket.Decoder) -> None: import libpcap as pcap assert isinstance(pd, ctypes.POINTER(pcap.pcap_t)) try: _logger.debug("%r: Worker thread for %r is started: %s", self, name, threading.current_thread()) # noinspection PyTypeChecker @pcap.pcap_handler # type: ignore def proxy(_: object, header: ctypes.Structure, packet: typing.Any) -> None: # Parse the header, extract the timestamp and the packet length. header = header.contents ts_ns = (header.ts.tv_sec * 1_000_000 + header.ts.tv_usec) * 1000 ts = Timestamp(system_ns=ts_ns, monotonic_ns=time.monotonic_ns()) length, real_length = header.caplen, header.len _logger.debug("%r: CAPTURED PACKET ts=%s dev=%r len=%d bytes", self, ts, name, length) if real_length != length: # In theory, this should never occur because we use a huge capture buffer. # On Windows, however, when using Npcap v0.96, the captured length is (always?) reported to be # 32 bytes shorter than the real length, despite the fact that the packet is not truncated. _logger.debug( "%r: Length mismatch in a packet captured from %r: real %r bytes, captured %r bytes", self, name, real_length, length, ) # Create a copy of the payload. This is required per the libpcap API contract -- it says that the # memory is invalidated upon return from the callback. packet = memoryview(ctypes.cast(packet, ctypes.POINTER(ctypes.c_ubyte * length))[0]).tobytes() llp = decoder(memoryview(packet)) if llp is None: if _logger.isEnabledFor(logging.INFO): _logger.info( "%r: Link-layer packet of %d bytes captured from %r at %s could not be parsed. " "The header is: %s", self, len(packet), name, ts, packet[:32].hex(), ) else: self._callback(LinkLayerCapture(timestamp=ts, packet=llp, device_name=name)) packets_per_batch = 100 while self._keep_going: err = pcap.dispatch(pd, packets_per_batch, proxy, ctypes.POINTER(ctypes.c_ubyte)()) if err < 0: # Negative values represent errors, otherwise it's the number of packets processed. if self._keep_going: _logger.critical( "%r: Worker thread for %r has failed with error %s; %s", self, name, err, pcap.geterr(pd).decode(), ) else: _logger.debug( "%r: Error %r in worker thread for %r ignored because it is commanded to stop", self, err, name, ) break except Exception as ex: _logger.exception("%r: Unhandled exception in worker thread for %r; stopping: %r", self, name, ex) finally: # BEWARE: pcap_close() is not idempotent! Second close causes a heap corruption. *sigh* pcap.close(pd) _logger.debug("%r: Worker thread for %r is being terminated", self, name)
def main(argv): global program_name program_name = os.path.basename(argv[0]) try: opts, args = getopt.getopt(argv[1:], "i:Ips:aB:") except getopt.GetoptError: usage() device = None dorfmon = False dopromisc = False snaplen = MAXIMUM_SNAPLEN bufsize = 0 useactivate = False for opt, optarg in opts: if opt == '-i': device = optarg.encode("utf-8") elif opt == '-I': dorfmon = True useactivate = True # required for rfmon elif opt == '-p': dopromisc = True elif opt == '-s': try: long_snaplen = int(optarg) except: error("invalid snaplen {}", optarg) if not (0 <= long_snaplen <= MAXIMUM_SNAPLEN): error("invalid snaplen {}", optarg) elif long_snaplen == 0: # <AK> fix, was: snaplen == 0: snaplen = MAXIMUM_SNAPLEN else: snaplen = long_snaplen elif opt == '-B': try: bufsize = int(optarg) * 1024 except: error("invalid packet buffer size {}", optarg) if bufsize <= 0: error("invalid packet buffer size {}", optarg) useactivate = True # required for bufsize elif opt == '-a': useactivate = True else: usage() status = 0 ebuf = ct.create_string_buffer(pcap.PCAP_ERRBUF_SIZE) if device is None: devlist = ct.POINTER(pcap.pcap_if_t)() if pcap.findalldevs(ct.byref(devlist), ebuf) == -1: error("{!s}", ebuf.value.decode("utf-8", "ignore")) if not devlist: error("no interfaces available for capture") device = devlist[0].name pcap.freealldevs(devlist) if useactivate: pd = pcap.create(device, ebuf) if not pd: error("{!s}: pcap.create failed: {!s}", device.decode("utf-8"), ebuf.value.decode("utf-8", "ignore")) status = pcap.set_snaplen(pd, snaplen) if status != 0: error("{!s}: pcap.set_snaplen failed: {!s}", device.decode("utf-8"), statustostr(status).decode("utf-8", "ignore")) if dopromisc: status = pcap.set_promisc(pd, 1) if status != 0: error("{!s}: pcap.set_promisc failed: {!s}", device.decode("utf-8"), statustostr(status).decode("utf-8", "ignore")) if dorfmon: try: status = pcap.set_rfmon(pd, 1) except AttributeError: error("pcap.set_rfmon is not available on this platform") if status != 0: error("{!s}: pcap.set_rfmon failed: {!s}", device.decode("utf-8"), statustostr(status).decode("utf-8", "ignore")) status = pcap.set_timeout(pd, 1000) if status != 0: error("{!s}: pcap.set_timeout failed: {!s}", device.decode("utf-8"), statustostr(status).decode("utf-8", "ignore")) if bufsize != 0: status = pcap.set_buffer_size(pd, bufsize) if status != 0: error("{!s}: pcap.set_buffer_size failed: {!s}", device.decode("utf-8"), statustostr(status).decode("utf-8", "ignore")) status = pcap.activate(pd) if status < 0: # pcap.activate() failed. error("{!s}: {!s}\n({!s})", device.decode("utf-8"), statustostr(status).decode("utf-8", "ignore"), pcap.geterr(pd).decode("utf-8", "ignore")) elif status > 0: # pcap.activate() succeeded, but it's warning us # of a problem it had. warning("{!s}: {!s}\n({!s})", device.decode("utf-8"), statustostr(status).decode("utf-8", "ignore"), pcap.geterr(pd).decode("utf-8", "ignore")) else: print("{!s} opened successfully".format(device.decode("utf-8"))) pcap.close(pd) else: ebuf.value = b"" pd = pcap.open_live(device, 65535, 0, 1000, ebuf) if not pd: error("{!s}", ebuf.value.decode("utf-8", "ignore")) elif ebuf.value: warning("{!s}", ebuf.value.decode("utf-8", "ignore")) else: print("{!s} opened successfully".format(device.decode("utf-8"))) pcap.close(pd) return 1 if status < 0 else 0
def main(argv=sys.argv): global program_name program_name = os.path.basename(sys.argv[0]) try: opts, args = getopt.getopt(argv[1:], "i:sptn") except getopt.GetoptError: usage() device = None doselect = False dopoll = False mechanism = None dotimeout = False dononblock = False for opt, optarg in opts: if opt == '-i': device = optarg.encode("utf-8") elif opt == '-s': doselect = True mechanism = "select() and pcap_dispatch()" elif opt == '-p': dopoll = True mechanism = "poll() and pcap_dispatch()" elif opt == '-t': dotimeout = True elif opt == '-n': dononblock = True else: usage() expression = args if doselect and dopoll: print("selpolltest: choose select (-s) or poll (-p), but not both", file=sys.stderr) return 1 if dotimeout and not doselect and not dopoll: print("selpolltest: timeout (-t) requires select (-s) or poll (-p)", file=sys.stderr) return 1 ebuf = ct.create_string_buffer(pcap.PCAP_ERRBUF_SIZE) if device is None: devlist = ct.POINTER(pcap.pcap_if_t)() if pcap.findalldevs(ct.byref(devlist), ebuf) == -1: error("{!s}", ebuf.value.decode("utf-8", "ignore")) if not devlist: error("no interfaces available for capture") device = devlist[0].name pcap.freealldevs(devlist) ebuf.value = b"" pd = pcap.open_live(device, 65535, 0, 1000, ebuf) if not pd: error("{!s}", ebuf.value.decode("utf-8", "ignore")) elif ebuf.value: warning("{!s}", ebuf.value.decode("utf-8", "ignore")) localnet = pcap.bpf_u_int32() netmask = pcap.bpf_u_int32() if pcap.lookupnet(device, ct.byref(localnet), ct.byref(netmask), ebuf) < 0: localnet = pcap.bpf_u_int32(0) netmask = pcap.bpf_u_int32(0) warning("{!s}", ebuf.value.decode("utf-8", "ignore")) fcode = pcap.bpf_program() cmdbuf = " ".join(expression).encode("utf-8") if pcap.compile(pd, ct.byref(fcode), cmdbuf, 1, netmask) < 0: error("{!s}", pcap.geterr(pd).decode("utf-8", "ignore")) if pcap.setfilter(pd, ct.byref(fcode)) < 0: error("{!s}", pcap.geterr(pd).decode("utf-8", "ignore")) if doselect or dopoll: # We need either an FD on which to do select()/poll() # or, if there isn't one, a timeout to use in select()/ # poll(). try: selectable_fd = pcap.get_selectable_fd(pd) except AttributeError: error("pcap.get_selectable_fd is not available on this platform") if selectable_fd == -1: print("Listening on {!s}, using {}, with a timeout".format( device.decode("utf-8"), mechanism)) try: required_timeout = pcap.get_required_select_timeout(pd) except AttributeError: error("pcap.get_required_select_timeout is not available " "on this platform") if not required_timeout: error("select()/poll() isn't supported on {!s}, " "even with a timeout", device.decode("utf-8")) required_timeout = required_timeout[0] # As we won't be notified by select() or poll() # that a read can be done, we'll have to periodically # try reading from the device every time the required # timeout expires, and we don't want those attempts # to block if nothing has arrived in that interval, # so we want to force non-blocking mode. dononblock = True else: print("Listening on {!s}, using {}".format( device.decode("utf-8"), mechanism)) required_timeout = None else: print("Listening on {!s}, using pcap_dispatch()".format( device.decode("utf-8"))) if dononblock: if pcap.setnonblock(pd, 1, ebuf) == -1: error("pcap.setnonblock failed: {!s}", ebuf.value.decode("utf-8", "ignore")) status = 0 if doselect: while True: try: if dotimeout: seltimeout = (0 + (required_timeout.tv_usec if required_timeout is not None and required_timeout.tv_usec < 1000 else 1000) / 1000000.0) rfds, wfds, efds = select.select([selectable_fd], [], [selectable_fd], seltimeout) elif required_timeout is not None: seltimeout = (required_timeout.tv_sec + required_timeout.tv_usec / 1000000.0) rfds, wfds, efds = select.select([selectable_fd], [], [selectable_fd], seltimeout) else: rfds, wfds, efds = select.select([selectable_fd], [], [selectable_fd]) except select.error as exc: print("Select returns error ({})".format(exc.args[1])) else: if selectable_fd == -1: if status != 0: print("Select returned a descriptor") else: print("Select timed out: " if not rfds and not wfds and not efds else "Select returned a descriptor: ", end="") print("readable, " if selectable_fd in rfds else "not readable, ", end="") print("exceptional condition" if selectable_fd in efds else "no exceptional condition", end="") print() packet_count = ct.c_int(0) status = pcap.dispatch(pd, -1, countme, ct.cast(ct.pointer(packet_count), ct.POINTER(ct.c_ubyte))) if status < 0: break # Don't report this if we're using a # required timeout and we got no packets, # because that could be a very short timeout, # and we don't want to spam the user with # a ton of "no packets" reports. if (status != 0 or packet_count.value != 0 or required_timeout is not None): print("{:d} packets seen, {:d} packets counted after " "select returns".format(status, packet_count.value)) elif dopoll: while True: poller = select.poll() poller.register(selectable_fd, select.POLLIN) if dotimeout: polltimeout = 1 elif (required_timeout is not None and required_timeout.tv_usec >= 1000): polltimeout = required_timeout.tv_usec // 1000 else: polltimeout = None try: events = poller.poll(polltimeout) except select.error as exc: print("Poll returns error ({})".format(exc.args[1])) else: if selectable_fd == -1: if status != 0: print("Poll returned a descriptor") else: if not events: print("Poll timed out") else: event = events[0][1] print("Poll returned a descriptor: ", end="") print("readable, " if event & select.POLLIN else "not readable, ", end="") print("exceptional condition, " if event & select.POLLERR else "no exceptional condition, ", end="") print("disconnect, " if event & select.POLLHUP else "no disconnect, ", end="") print("invalid" if event & select.POLLNVAL else "not invalid", end="") print() packet_count = ct.c_int(0) status = pcap.dispatch(pd, -1, countme, ct.cast(ct.pointer(packet_count), ct.POINTER(ct.c_ubyte))) if status < 0: break # Don't report this if we're using a # required timeout and we got no packets, # because that could be a very short timeout, # and we don't want to spam the user with # a ton of "no packets" reports. if (status != 0 or packet_count.value != 0 or required_timeout is not None): print("{:d} packets seen, {:d} packets counted after " "poll returns".format(status, packet_count.value)) else: while True: packet_count = ct.c_int(0) status = pcap.dispatch(pd, -1, countme, ct.cast(ct.pointer(packet_count), ct.POINTER(ct.c_ubyte))) if status < 0: break print("{:d} packets seen, {:d} packets counted after " "pcap.dispatch returns".format(status, packet_count.value)) if status == -2: # We got interrupted, so perhaps we didn't manage to finish a # line we were printing. Print an extra newline, just in case. print() sys.stdout.flush() if status == -1: # Error. Report it. print("{}: pcap.loop: {!s}".format(program_name, pcap.geterr(pd).decode("utf-8", "ignore")), file=sys.stderr) pcap.freecode(ct.byref(fcode)) pcap.close(pd) return 1 if status == -1 else 0
def main(argv): global program_name program_name = os.path.basename(sys.argv[0]) try: opts, args = getopt.getopt(argv[1:], "i:mnt:") except getopt.GetoptError: usage() device = None immediate = False nonblock = 0 timeout = 1000 for opt, optarg in opts: if opt == '-i': device = optarg.encode("utf-8") elif opt == '-m': immediate = True elif opt == '-n': nonblock = 1 elif opt == '-t': try: timeout = int(optarg) except: error('Timeout value "{}" is not a number', optarg) if timeout < 0: error("Timeout value {:d} is negative", timeout) if timeout > INT_MAX: error("Timeout value {:d} is too large (> {:d})", timeout, INT_MAX) else: usage() expression = args ebuf = ct.create_string_buffer(pcap.PCAP_ERRBUF_SIZE) if device is None: devlist = ct.POINTER(pcap.pcap_if_t)() if pcap.findalldevs(ct.byref(devlist), ebuf) == -1: error("{!s}", ebuf.value.decode("utf-8", "ignore")) if not devlist: error("no interfaces available for capture") device = devlist[0].name pcap.freealldevs(devlist) ebuf.value = b"" pd = pcap.create(device, ebuf) if not pd: error("{!s}", ebuf.value.decode("utf-8", "ignore")) status = pcap.set_snaplen(pd, 65535) if status != 0: error("{!s}: pcap.set_snaplen failed: {!s}", device.decode("utf-8"), statustostr(status).decode("utf-8", "ignore")); if immediate: try: status = pcap.set_immediate_mode(pd, 1) except AttributeError: error("pcap.set_immediate_mode is not available on this platform") if status != 0: error("{!s}: pcap.set_immediate_mode failed: {!s}", device.decode("utf-8"), statustostr(status).decode("utf-8", "ignore")); status = pcap.set_timeout(pd, timeout) if status != 0: error("{!s}: pcap.set_timeout failed: {!s}", device.decode("utf-8"), statustostr(status).decode("utf-8", "ignore")); status = pcap.activate(pd) if status < 0: # pcap.activate() failed. error("{!s}: {!s}\n({!s})", device.decode("utf-8"), statustostr(status).decode("utf-8", "ignore"), pcap.geterr(pd).decode("utf-8", "ignore")) elif status > 0: # pcap.activate() succeeded, but it's warning us # of a problem it had. warning("{!s}: {!s}\n({!s})", device.decode("utf-8"), statustostr(status).decode("utf-8", "ignore"), pcap.geterr(pd).decode("utf-8", "ignore")) localnet = pcap.bpf_u_int32() netmask = pcap.bpf_u_int32() if pcap.lookupnet(device, ct.byref(localnet), ct.byref(netmask), ebuf) < 0: localnet = pcap.bpf_u_int32(0) netmask = pcap.bpf_u_int32(0) warning("{!s}", ebuf.value.decode("utf-8", "ignore")) fcode = pcap.bpf_program() cmdbuf = " ".join(expression).encode("utf-8") if pcap.compile(pd, ct.byref(fcode), cmdbuf, 1, netmask) < 0: error("{!s}", pcap.geterr(pd).decode("utf-8", "ignore")) if pcap.setfilter(pd, ct.byref(fcode)) < 0: error("{!s}", pcap.geterr(pd).decode("utf-8", "ignore")) if pcap.setnonblock(pd, nonblock, ebuf) == -1: error("pcap.setnonblock failed: {!s}", ebuf.value.decode("utf-8", "ignore")) print("Listening on {!s}".format(device.decode("utf-8"))) while True: packet_count = ct.c_int(0) status = pcap.dispatch(pd, -1, countme, ct.cast(ct.pointer(packet_count), ct.POINTER(ct.c_ubyte))) if status < 0: break if status != 0: print("{:d} packets seen, {:d} packets counted after " "pcap.dispatch returns".format(status, packet_count.value)) if status == -2: # We got interrupted, so perhaps we didn't manage to finish a # line we were printing. Print an extra newline, just in case. print() sys.stdout.flush() if status == -1: # Error. Report it. print("{}: pcap.loop: {!s}".format(program_name, pcap.geterr(pd).decode("utf-8", "ignore")), file=sys.stderr) pcap.freecode(ct.byref(fcode)) pcap.close(pd) return 1 if status == -1 else 0
def main(argv=sys.argv): global program_name program_name = os.path.basename(argv[0]) try: opts, args = getopt.getopt(argv[1:], "dF:gm:Os:") except getopt.GetoptError: usage() if is_windows and hasattr(pcap, "wsockinit") and pcap.wsockinit() != 0: return 1 have_fcode = False dflag = 1 if defined("BDEBUG"): gflag = 0 infile = None netmask = pcap.PCAP_NETMASK_UNKNOWN Oflag = 1 snaplen = MAXIMUM_SNAPLEN for opt, optarg in opts: if opt == '-d': dflag += 1 elif opt == 'g': if defined("BDEBUG"): gflag += 1 else: error( "libpcap and filtertest not built with optimizer debugging enabled" ) elif opt == '-F': infile = optarg elif opt == '-O': Oflag = 0 elif opt == '-m': # !!! # try: # addr = socket.inet_pton(socket.AF_INET, optarg) # except socket.error: # if r == 0: # error("invalid netmask {}", optarg) # elif r == -1: # error("invalid netmask {}: {}", optarg, pcap_strerror(errno)) # else: # elif r == 1: # addr = bpf_u_int32(addr) # netmask = addr pass elif opt == '-s': try: long_snaplen = int(optarg) except: error("invalid snaplen {}", optarg) if not (0 <= long_snaplen <= MAXIMUM_SNAPLEN): error("invalid snaplen {}", optarg) elif long_snaplen == 0: # <AK> fix, was: snaplen == 0: snaplen = MAXIMUM_SNAPLEN else: snaplen = long_snaplen else: usage() if not args: usage() dlt_name = args[0] expression = args[1:] dlt = pcap.datalink_name_to_val(dlt_name.encode("utf-8")) if dlt < 0: try: dlt = int(dlt_name) except: error("invalid data link type {!s}", dlt_name) if infile: cmdbuf = read_infile(infile) else: # concatenating arguments with spaces. cmdbuf = " ".join(expression).encode("utf-8") pd = pcap.open_dead(dlt, snaplen) if not pd: error("Can't open fake pcap_t") fcode = pcap.bpf_program() if pcap.compile(pd, ct.byref(fcode), cmdbuf, Oflag, netmask) < 0: error("{!s}", pcap.geterr(pd).decode("utf-8", "ignore")) have_fcode = True if not pcap.bpf_validate(fcode.bf_insns, fcode.bf_len): warning("Filter doesn't pass validation") if defined("BDEBUG"): if cmdbuf: # replace line feed with space mcodes = cmdbuf.decode("utf-8", "ignore") mcodes = mcodes.replace('\r', ' ').replace('\n', ' ') # only show machine code if BDEBUG defined, since dflag > 3 print("machine codes for filter: {}".format(mcodes)) else: print("machine codes for empty filter:") pcap.bpf_dump(ct.byref(fcode), dflag) del cmdbuf if have_fcode: pcap.freecode(ct.byref(fcode)) pcap.close(pd) return 0