karpierz / libpcap

Python binding for the libpcap C library.
BSD 3-Clause "New" or "Revised" License
54 stars 14 forks source link

Some examples from Linux #8

Closed gil-obradors closed 3 years ago

gil-obradors commented 3 years ago

Hi!

I'm trying to play with libpcap on Ubuntu 20, with tcpdump.

I have no experience with CFUNC and C Python bindings... Can you give me a trick why I can't discover devices ?

import libpcap
libpcap.config(LIBPCAP="tcpdump")

libpcap.findalldevs()

Output

libpcap.findalldevs()
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: required argument 'alldevsp' missing

The binding direct to C function is

findalldevs   = CFUNC(ct.c_int,
                      ct.POINTER(ct.POINTER(pcap_if_t)),
                      ct.c_char_p)(
                      ("pcap_findalldevs", dll), (
                      (1, "alldevsp"),
                      (1, "errbuf"),))

why is falling? I have tried this... but nothing...

a = POINTER(POINTER(libpcap.pcap_if_t))
b = c_char_p()
>>>libpcap.findalldevs(a,b)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
ctypes.ArgumentError: argument 1: <class 'TypeError'>: expected LP_LP_pcap_if instance instead of _ctypes.PyCPointerType

I can offer a doc page with examples for future users on Linux, but I need to understand the bindings...

Many thanks for the work!

gil-obradors commented 3 years ago

Found it!

https://github.com/karpierz/libpcap/blob/e64a39fd3b0b85df649c90773cf197668c9a1d26/tests/capturetest.py#L88

I start to understand...

But may be must be more easy for final user? I come from pcap that isn't maintained and there exists some helper functions for that, for example:

https://github.com/pynetwork/pypcap/blob/a10cce7f4034e128ee257bf8f429e0ddc37cf54b/pcap.pyx#L510

Is the same method of bindings from pcap and pypcap?

karpierz commented 3 years ago

;>I come from pcap that isn't maintained Take a look at: https://pypi.org/project/pcap-ct/ https://github.com/karpierz/pcap-ct libpcap is strictly lowest level (C level) package. It is a base for higher level pcap-ct (100% compatible with https://github.com/pynetwork/pypcap - de facto a fork of it, but based on libpcap/ctypes instead of Cython based bibding.) pypcap/pcap-ct is much more pythonic and much more easier to use than raw libpcap.

gil-obradors commented 3 years ago

Ok! Thank you very much for your guidance!

kistlin commented 1 year ago

This is an example to use on Linux to dump traffic to a file. Maybe it helps others to speed up their development. Change maybe the interface_name or filter_string and you should end up with a capture file output.pcap. It will only work if there is traffic. Else it will stay in dispatch. The C interfacing might not be used as efficiently as it could be, but it should convey the idea.

import ctypes
import sys

import libpcap

pcap_filename = "output.pcap"
interface_name = "eth0"
filter_string = "src 192.168.1.1"
snaplen = 65536
promisc = 0
to_ms = 100

libpcap.config(LIBPCAP="tcpdump")

# encode the interface name on which to capture
interface = ctypes.c_char_p(interface_name.encode(encoding="utf-8"))
buffer_error = ctypes.create_string_buffer(libpcap.PCAP_ERRBUF_SIZE)
capture = libpcap.open_live(interface, snaplen, promisc, to_ms, buffer_error)
if not capture:
    print(buffer_error.value.decode(encoding="utf-8"))
    sys.exit(-1)

# get network interface information (xxx.xxx.xxx.xxx/xx)
netp = libpcap.bpf_u_int32()
maskp = libpcap.bpf_u_int32()
success = not libpcap.lookupnet(interface, netp, maskp, buffer_error)
if not success:
    print(buffer_error.value.decode(encoding="utf-8"))
    sys.exit(-1)

# setup the message filter
bpf_program = libpcap.bpf_program()
filter_string = ctypes.c_char_p(filter_string.encode("utf-8"))
success = not libpcap.compile(capture, bpf_program, filter_string, 1, maskp)
if not success:
    print(f"Compiling \"{filter_string.value.decode('utf-8')}\" failed")
    sys.exit(-1)

# set the filter
success = not libpcap.setfilter(capture, bpf_program)
if not success:
    print(f"libpcap.setfilter failed")
    sys.exit(-1)

# setup pcap dump file
file_name = ctypes.c_char_p(str(pcap_filename).encode("utf-8"))
dumper = libpcap.dump_open(capture, file_name)
if not dumper:
    error = libpcap.geterr(capture).decode("utf-8")
    print(f"dump_open on \"{file_name.value.decode('utf-8')}\" failed with \"{error}\"")

user = ctypes.c_ubyte(0)

packet_count_all = 0
packet_count_until_stop = 10

# on packet received callback
@ctypes.CFUNCTYPE(None, ctypes.POINTER(ctypes.c_ubyte), ctypes.POINTER(libpcap.pkthdr), ctypes.POINTER(ctypes.c_ubyte))
def callback(user, packet_header, payload):
    libpcap.dump(ctypes.cast(dumper, ctypes.POINTER(ctypes.c_ubyte)), packet_header, payload)

while True:
    packet_count = libpcap.dispatch(capture, -1, callback, user)
    packet_count_all += packet_count
    print(f"Processed {packet_count} packets, overall {packet_count_all}")
    if packet_count_all >= packet_count_until_stop:
        break

libpcap.dump_close(dumper)
libpcap.close(capture)