def main(argv): global program_name program_name = os.path.basename(argv[0]) ebuf = ct.create_string_buffer(pcap.PCAP_ERRBUF_SIZE) pd = pcap.open_live(b"lo0", 65535, 0, 1000, ebuf) if not pd: pd = pcap.open_live(b"lo", 65535, 0, 1000, ebuf) if not pd: error("Neither lo0 nor lo could be opened: {!s}", ebuf.value.decode("utf-8", "ignore")) status = pcap.activate(pd) if status != pcap.PCAP_ERROR_ACTIVATED: if status == 0: error("pcap.activate() of opened pcap_t succeeded") elif status == pcap.PCAP_ERROR: error( "pcap.activate() of opened pcap_t failed with {!s}, " "not PCAP_ERROR_ACTIVATED", pcap.geterr(pd).decode("utf-8", "ignore")) else: error( "pcap.activate() of opened pcap_t failed with {!s}, " "not PCAP_ERROR_ACTIVATED", statustostr(status).decode("utf-8", "ignore")) return 0
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 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): 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