On 2026/05/08 19:58, Sebastian Reitenbach wrote:
> Hi,
>
> this links kismet against net/pcap, which eventually allows the
> kismetdb_to_pcap to succeed
> without a crasher because our pcap doesn't know all DLTs kismet expects it to
> know, ie. BTLE or
> Zigbee captured traffic. Pcap can then be read in in Wireshark for example.
>
> Other than that:
> * capture_nrf_52840_capture_nrf_52840_c similar patches
> * as capture_nrf_51822_capture_nrf_51822_c has, but I haven't yet got the
> nice!Nano I have to
> detect any Zigbee packages. Maybe antenna is just too bad, and neighbours
> devices too far away
> ;)
> * capture_ti_cc_2531_capture_ti_cc_2531_c makes my TI CC2531 with sniffer
> firmware work!
> already upstreamed.
> * log_tools_kismetdb_to_pcap_cc some additional debugging aid, already
> upstreamed
> * updated README, besides smaller additions, esp. mention nrf_52840 and
> ti_cc_2531
>
> patch attached, I'm especially looking for feedback on the linking against
> net/pcap.
>
>
>
> cheers,
> Sebastian
>
>
> --
> https://buzzdeee.reitenba.ch
: -WANTLIB += ${COMPILER_LIBCXX} c crypto m mosquitto pcap pcre2-8
: +WANTLIB += ${COMPILER_LIBCXX} c crypto m mosquitto pcre2-8
: WANTLIB += rtlsdr sqlite3 ssl usb-1.0 util websockets z
: +WANTLIB += lib/libpcap/pcap
:
: # C++20
: COMPILER= base-clang ports-gcc
: @@ -36,7 +37,12 @@
: LDFLAGS_ports-gcc= -latomic
: LDFLAGS= -L${X11BASE}/lib -L${LOCALBASE}/lib
${LDFLAGS_${CHOSEN_COMPILER}}
:
: +PCAP_CFLAGS != pkg-config --cflags libepcap
: +PCAP_LIBS != pkg-config --libs libepcap
don't use != unless *absolutely* unavoidable, every time the makefile
is parsed for whatever reason (even if it's just "make show=PKGNAMES" or
something) the command is run (and while pkgconf is much better than
old pkg-config, it's still not really cheap)...
: CONFIGURE_ENV= CPPFLAGS="-I${X11BASE}/include -I${LOCALBASE}/include" \
: + libepcap_CFLAGS="${PCAP_CFLAGS}" \
: + libepcap_LIBS="${PCAP_LIBS}" \
passing in from the makefile shouldn't be needed at all anyway as you
have already patched the autoconf file to do this.
if you _did_ need to pass in from the makefile, it would usually be
better to use e.g. libepcap_CFLAGS="`pkg-config --cflags libepcap`" etc,
so that the command is only run when shelling out to run configure
anyway.
: --- patches/patch-configure_ac 19 Jan 2026 13:00:38 -0000 1.1
: +++ patches/patch-configure_ac 8 May 2026 17:49:35 -0000
: @@ -1,6 +1,6 @@
: - don't force -O3
: - GCC's libatomic should not be pulled in just because it exists
: -- libstdc++ should n9t be explicitly linked (use "c++" as a linker instead)
: +- libstdc++ should not be explicitly linked (use "c++" as a linker instead)
:
: Index: configure.ac
: --- configure.ac.orig
: @@ -59,3 +59,32 @@
: AC_SUBST(CXXLIBS)
:
: # Does the compiler handle various std::foo namespaces properly?
: +@@ -1187,20 +1156,20 @@ AC_SUBST(LIBWSLIBS)
: + AC_SUBST(LIBWSCFLAGS)
: +
: + # Look for libpcap via pkg-config
: +-have_libpcap=no
: +-PKG_CHECK_MODULES([libpcap], [libpcap], [
: +- have_libpcap=yes
: +- AC_DEFINE(HAVE_LIBPCAP, 1, libpcap packet capture lib)
: ++have_libepcap=no
: ++PKG_CHECK_MODULES([libepcap], [libepcap], [
: ++ have_libepcap=yes
: ++ AC_DEFINE(HAVE_LIBPCAP, 1, libepcap packet capture lib)
: +
: +- PCAPLIBS=`pkg-config --libs libpcap`
: +- PCAPCFLAGS=`pkg-config --cflags libpcap`
: ++ PCAPLIBS=`pkg-config --libs libepcap`
: ++ PCAPCFLAGS=`pkg-config --cflags libepcap`
: + pcap=yes
: + ], [
: +- AC_MSG_WARN(No libpcap found in pkg-config, will check system paths.)
: ++ AC_MSG_WARN(No libepcap found in pkg-config, will check system paths.)
: + ])
: +
: + # Look for pcap using our legacy mode
: +-if test "$have_libpcap"x != "yesx"; then
: ++if test "$have_libepcap"x != "yesx"; then
: + AC_CHECK_LIB([pcap], [pcap_open_live],
: + AC_DEFINE(HAVE_LIBPCAP, 1, libpcap packet capture lib)
foundsyspcap=yes,
: + AC_MSG_ERROR(Libpcap required for proper operation))
I think you should *only* change the name of the pkg-config file being
checked for. Don't rename their "have_libpcap" variable or the prefix
used for other variables, that is:
| have_libpcap=no
| PKG_CHECK_MODULES([libpcap], [libpcap], [
^^^^^^^ here
^ not here, this is the prefix for autoconf variables
| have_libpcap=yes
| AC_DEFINE(HAVE_LIBPCAP, 1, libpcap packet capture lib)
| PCAPLIBS=`pkg-config --libs libpcap`
^^^^^^^ here
| PCAPCFLAGS=`pkg-config --cflags libpcap`
^^^^^^^ here
| pcap=yes
| ], [
| AC_MSG_WARN(No libpcap found in pkg-config, will check system paths.)
| ])
|
| # Look for pcap using our legacy mode
| if test "$have_libpcap"x != "yesx"; then
| AC_CHECK_LIB([pcap], [pcap_open_live],
| AC_DEFINE(HAVE_LIBPCAP, 1, libpcap packet capture lib)
foundsyspcap=yes,
| AC_MSG_ERROR(Libpcap required for proper operation))
(their autoconf checks are a bit strange, because they're asking
PKG_CHECK_MODULES to determine libs/cflags, then ignoring them and
asking pkg-config directly, but whatever...)
: Index: patches/patch-log_tools_kismetdb_to_pcap_cc
: ===================================================================
: RCS file: patches/patch-log_tools_kismetdb_to_pcap_cc
: diff -N patches/patch-log_tools_kismetdb_to_pcap_cc
: --- /dev/null 1 Jan 1970 00:00:00 -0000
: +++ patches/patch-log_tools_kismetdb_to_pcap_cc 8 May 2026 17:49:35
-0000
: @@ -0,0 +1,226 @@
: +Prevent crasher when hitting unknown DLT
any idea what's different compared to other OS? surely if there's a
problem it will affect them too?
: +Index: log_tools/kismetdb_to_pcap.cc
: +--- log_tools/kismetdb_to_pcap.cc.orig
: ++++ log_tools/kismetdb_to_pcap.cc
: +@@ -222,16 +222,31 @@ void write_pcap_packet(FILE *pcap_file, const std::str
: + hdr.incl_len = packet.size();
: + hdr.orig_len = packet.size();
: +
: +- if (fwrite(&hdr, sizeof(pcap_packet_hdr_t), 1, pcap_file) != 1)
: +- throw std::runtime_error(fmt::format("error writing pcap packet: {}
(errno {})",
: +- strerror(errno), errno));
: ++ // Skip empty packets to avoid write errors and malformed pcap blocks
: ++ if (packet.empty()) {
: ++ fmt::print(stderr, "DEBUG: Skipping empty pcap packet for TS
{}.{}\n",
: ++ ts_sec, ts_usec);
: ++ return;
: ++ }
: +
: +- if (fwrite(packet.data(), packet.size(), 1, pcap_file) != 1)
: +- throw std::runtime_error(fmt::format("error writing pcap packet: {}
(errno {})",
: +- strerror(errno), errno));
: ++ // Clear errno to avoid reporting stale "No such file" errors
: ++ errno = 0;
not sure that makes sense? -
: ++ if (fwrite(&hdr, sizeof(pcap_packet_hdr_t), 1, pcap_file) != 1) {
"fwrite() returns a value less than nmemb only if a write error has occurred"
so why is the errno zeroing needed?
: ++ int errsv = errno;
: ++ throw std::runtime_error(fmt::format("failed writing pcap HEADER:
{} (errno {})",
: ++ errsv ? strerror(errsv) : "Unknown/Buffered Error",
errsv));
: ++ }
or, if it is needed, why is it not done here?
: ++ if (fwrite(packet.data(), packet.size(), 1, pcap_file) != 1) {
: ++ int errsv = errno;
: ++ throw std::runtime_error(fmt::format("failed writing pcap DATA
(size {}): {} (errno {})",
: ++ packet.size(), errsv ? strerror(errsv) :
"Unknown/Buffered Error", errsv));
: ++ }
: + }
: +
: +
: ++
: + FILE *open_pcapng_file(const std::string& path, bool force) {
: + struct stat statbuf;
: + FILE *pcapng_file;
: +@@ -465,6 +480,13 @@ void write_pcapng_packet(FILE *pcapng_file, const std:
: + unsigned long ts_sec, unsigned long ts_usec, const std::string& tag,
: + unsigned int ngindex, double lat, double lon, double alt) {
: +
: ++ // Skip empty packets to avoid write errors and malformed pcapng blocks
: ++ if (packet.empty()) {
: ++ fmt::print(stderr, "DEBUG: Skipping empty pcapng packet at TS
{}.{}\n",
: ++ ts_sec, ts_usec);
: ++ return;
: ++ }
: ++
: + // Assemble the packet in the file in steps to avoid another memcpy
: + pcapng_epb_t epb;
: +
: +@@ -501,24 +523,34 @@ void write_pcapng_packet(FILE *pcapng_file, const std:
: + epb.captured_length = packet.size();
: + epb.original_length = packet.size();
: +
: +- if (fwrite(&epb, sizeof(pcapng_epb_t), 1, pcapng_file) != 1)
: +- throw std::runtime_error(fmt::format("error writing pcapng packet
header: {} (errno {})",
: +- strerror(errno), errno));
: ++ // Clear errno for clean reporting
: ++ errno = 0;
: +
: +- if (fwrite(packet.data(), packet.size(), 1, pcapng_file) != 1)
: +- throw std::runtime_error(fmt::format("error writing pcapng packet
content: {} (errno {})",
: +- strerror(errno), errno));
: ++ if (fwrite(&epb, sizeof(pcapng_epb_t), 1, pcapng_file) != 1) {
: ++ int errsv = errno;
: ++ throw std::runtime_error(fmt::format("failed writing pcapng EPB
HEADER: {} (errno {})",
: ++ errsv ? strerror(errsv) : "Unknown/Buffered Error",
errsv));
: ++ }
: +
: ++ if (fwrite(packet.data(), packet.size(), 1, pcapng_file) != 1) {
: ++ int errsv = errno;
: ++ throw std::runtime_error(fmt::format("failed writing pcapng DATA
(size {}): {} (errno {})",
: ++ packet.size(), errsv ? strerror(errsv) :
"Unknown/Buffered Error", errsv));
: ++ }
: ++
: + // Data has to be 32bit padded
: + uint32_t pad = 0;
: + size_t pad_sz = 0;
: +
: + pad_sz = PAD_TO_32BIT(packet.size()) - packet.size();
: +
: +- if (pad_sz > 0)
: +- if (fwrite(&pad, pad_sz, 1, pcapng_file) != 1)
: +- throw std::runtime_error(fmt::format("error writing pcapng
packet padding: {} (errno {})",
: +- strerror(errno), errno));
: ++ if (pad_sz > 0) {
: ++ if (fwrite(&pad, pad_sz, 1, pcapng_file) != 1) {
: ++ int errsv = errno;
: ++ throw std::runtime_error(fmt::format("failed writing pcapng
PADDING: {} (errno {})",
: ++ errsv ? strerror(errsv) : "Unknown/Buffered Error",
errsv));
: ++ }
: ++ }
: +
: + pcapng_option_t opt;
: +
: +@@ -526,20 +558,27 @@ void write_pcapng_packet(FILE *pcapng_file, const std:
: + opt.option_code = PCAPNG_OPT_COMMENT;
: + opt.option_length = tag.length();
: +
: +- if (fwrite(&opt, sizeof(pcapng_option_t), 1, pcapng_file) != 1)
: +- throw std::runtime_error(fmt::format("error writing pcapng
packet option: {} (errno {})",
: +- strerror(errno), errno));
: ++ if (fwrite(&opt, sizeof(pcapng_option_t), 1, pcapng_file) != 1){
: ++ int errsv = errno;
: ++ throw std::runtime_error(fmt::format("failed writing pcapng
OPTION HEADER: {} (errno {})",
: ++ errsv ? strerror(errsv) : "Unknown error", errsv));
: ++ }
: +
: +- if (fwrite(tag.c_str(), tag.length(), 1, pcapng_file) != 1)
: +- throw std::runtime_error(fmt::format("error writing pcapng
packet option: {} (errno {})",
: +- strerror(errno), errno));
: ++ if (fwrite(tag.c_str(), tag.length(), 1, pcapng_file) != 1) {
: ++ int errsv = errno;
: ++ throw std::runtime_error(fmt::format("failed writing pcapng
OPTION DATA (tag): {} (errno {})",
: ++ errsv ? strerror(errsv) : "Unknown error", errsv));
: ++ }
: +
: + pad_sz = PAD_TO_32BIT(tag.length()) - tag.length();
: +
: +- if (pad_sz > 0)
: +- if (fwrite(&pad, pad_sz, 1, pcapng_file) != 1)
: +- throw std::runtime_error(fmt::format("error writing pcapng
packet option: {} (errno {})",
: +- strerror(errno), errno));
: ++ if (pad_sz > 0) {
: ++ if (fwrite(&pad, pad_sz, 1, pcapng_file) != 1) {
: ++ int errsv = errno;
: ++ throw std::runtime_error(fmt::format("failed writing pcapng
OPTION PADDING: {} (errno {})",
: ++ errsv ? strerror(errsv) : "Unknown error", errsv));
: ++ }
: ++ }
: + }
: +
: + // If we have gps data, tag the packet with a kismet custom GPS entry
under the kismet PEN
: +@@ -590,42 +629,55 @@ void write_pcapng_packet(FILE *pcapng_file, const std:
: +
: + // Lon, lat, [alt]
: + u.u32 = double_to_fixed3_7(lon);
: +- if (fwrite(&u, sizeof(uint32_t), 1, pcapng_file) != 1)
: +- throw std::runtime_error(fmt::format("error writing packet gps:
{} (errno {})",
: +- strerror(errno), errno));
: ++ if (fwrite(&u, sizeof(uint32_t), 1, pcapng_file) != 1){
: ++ int errsv = errno;
: ++ throw std::runtime_error(fmt::format("failed writing pcapng GPS
LONGITUDE: {} (errno {})",
: ++ errsv ? strerror(errsv) : "Unknown/Buffered Error", errsv));
: ++ }
: +
: + u.u32 = double_to_fixed3_7(lat);
: +- if (fwrite(&u, sizeof(uint32_t), 1, pcapng_file) != 1)
: +- throw std::runtime_error(fmt::format("error writing packet gps:
{} (errno {})",
: +- strerror(errno), errno));
: ++ if (fwrite(&u, sizeof(uint32_t), 1, pcapng_file) != 1){
: ++ int errsv = errno;
: ++ throw std::runtime_error(fmt::format("failed writing pcapng GPS
LATITUDE: {} (errno {})",
: ++ errsv ? strerror(errsv) : "Unknown/Buffered Error", errsv));
: ++ }
: +
: + if (alt != 0) {
: + u.u32 = double_to_fixed6_4(alt);
: +- if (fwrite(&u, sizeof(uint32_t), 1, pcapng_file) != 1)
: +- throw std::runtime_error(fmt::format("error writing packet
gps: {} (errno {})",
: +- strerror(errno), errno));
: ++ if (fwrite(&u, sizeof(uint32_t), 1, pcapng_file) != 1) {
: ++ int errsv = errno;
: ++ throw std::runtime_error(fmt::format("failed writing pcapng
GPS ALTITUDE: {} (errno {})",
: ++ errsv ? strerror(errsv) : "Unknown/Buffered Error",
errsv));
: ++ }
: + }
: +
: + pad_sz = PAD_TO_32BIT(copt.option_length) - copt.option_length;
: +
: +- if (pad_sz > 0)
: +- if (fwrite(&pad, pad_sz, 1, pcapng_file) != 1)
: +- throw std::runtime_error(fmt::format("error writing pcapng
packet option: {} (errno {})",
: +- strerror(errno), errno));
: ++ if (pad_sz > 0) {
: ++ if (fwrite(&pad, pad_sz, 1, pcapng_file) != 1) {
: ++ int errsv = errno;
: ++ throw std::runtime_error(fmt::format("failed writing pcapng
GPS OPTION PADDING: {} (errno {})",
: ++ errsv ? strerror(errsv) : "Unknown/Buffered Error",
errsv));
: ++ }
: ++ }
: + }
: +
: + opt.option_code = PCAPNG_OPT_ENDOFOPT;
: + opt.option_length = 0;
: +
: +- if (fwrite(&opt, sizeof(pcapng_option_t), 1, pcapng_file) != 1)
: +- throw std::runtime_error(fmt::format("error writing packet
end-of-options: {} (errno {})",
: +- strerror(errno), errno));
: ++ if (fwrite(&opt, sizeof(pcapng_option_t), 1, pcapng_file) != 1) {
: ++ int errsv = errno;
: ++ throw std::runtime_error(fmt::format("failed writing pcapng
END-OF-OPTIONS: {} (errno {})",
: ++ errsv ? strerror(errsv) : "Unknown/Buffered Error", errsv));
: ++ }
: +
: + data_sz += 4;
: +
: +- if (fwrite(&data_sz, 4, 1, pcapng_file) != 1)
: +- throw std::runtime_error(fmt::format("error writing packet
end-of-packet: {} (errno {})",
: +- strerror(errno), errno));
: ++ if (fwrite(&data_sz, 4, 1, pcapng_file) != 1) {
: ++ int errsv = errno;
: ++ throw std::runtime_error(fmt::format("failed writing pcapng BLOCK
TRAILER (total length): {} (errno {})",
: ++ errsv ? strerror(errsv) : "Unknown/Buffered Error", errsv));
: ++ }
: + }
a lot of this just seems to be rewriting the checks to do pretty
much exactly the same thing ?
: +
: +@@ -975,8 +1027,10 @@ int main(int argc, char *argv[]) {
: + fmt::print("Datasource #{} ({} {} {}) {} packets\n",
: + ifnum++, i->uuid, i->name, i->interface,
i->num_packets);
: + for (auto d : i->dlts) {
: ++ const char* n = pcap_datalink_val_to_name(d);
: ++ const char* v = pcap_datalink_val_to_description(d);
: + fmt::print(" DLT {}: {} {}\n",
: +- d, pcap_datalink_val_to_name(d),
pcap_datalink_val_to_description(d));
: ++ d, n ? n : "unknown", v ? v : "unknown");
: + }
: +
: + if (i->dlts.size() == 0)
: Index: pkg/README
: ===================================================================
: RCS file: /cvs/ports/net/kismet/pkg/README,v
: diff -u -r1.1 README
: --- pkg/README 19 Jan 2026 13:00:38 -0000 1.1
: +++ pkg/README 8 May 2026 17:49:35 -0000
: @@ -8,11 +8,22 @@
: The following capture drivers are known to work:
: * openbsd_wifi (autodetected)
: * sdr_rtladsb (autodetected)
: + * planes
: * sdr_rtl433 (autodetected)
: + * meters
: * nrf_51822 (not autodetected)
: + * Bluetooth LE
: * use with:
: * -c nrf51822:type=nrf51822,device=/dev/cuaU0,name=adafruit
: -
: + * tested with Adafruit Bluefruit sniffer as well as nrf52840
: + nice!Nano with Bluetooth sniffer firmware
: + * nrf_52840 (not autodetected)
: + * Zigbee
: + * use with:
: + * -c nrf52840:type=nrf52840,device=/dev/cuaU0,name=niceNano
: + * note: haven't seen it reporting any packets yet using a nice!Nano
: + * ti_cc_2531 (autodetected)
: + * Zigbee
:
: Many other capture drivers are enabled. They are untested,
: but may work as well.