Skip to content

Loading builds...

Changes

#241 (Jun 17, 2026, 1:51:56 PM)

server: fix misleading data length validation log message

The format string "%u < %u <= %u" was printed with arguments
(min_len, data->len, max_len), placing the offending length in
the middle and mislabeling it.  This is confusing.  Let's print
the actual length followed by the expected interval instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change-Id: Ice95c1f8ad1aa8de259364bd70eba0db8918b19e
Vadim Yanitskiy at

#240 (Jun 17, 2026, 1:51:56 PM)

server: do not abort process on short conn message

conn_read_cb() used OSMO_ASSERT() to check that the received
message holds at least a full osmo_pcap_data header.  Although
conn_segmentation_cb2() should only ever hand up complete frames,
asserting on a length derived from network input means a framing
anomaly would abort the entire server (taking down all other clients'
captures).  Close the offending connection gracefully instead,
consistent with the other error paths in this function.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change-Id: Ia102ff918ef8152d212e10a860f5dc70efec880b
Vadim Yanitskiy at

#239 (Jun 17, 2026, 1:51:56 PM)

server: fix msgb leak on duplicate link header

rx_link_hdr() takes ownership of msg on success (rx_link() only frees
it on failure).  Both branches that call update_conn_file_hdr_msg()
free msg, but when an identical link header was already stored neither
branch ran and msg was leaked.

This happens on every duplicate PKT_LINK_HDR, e.g. a client that
periodically resends its header.  Free msg explicitly in that case.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change-Id: I79344fe942342f2a736878142b3cf036fc982eef
Vadim Yanitskiy at

#238 (Jun 17, 2026, 1:51:56 PM)

tls: fix broken certificate hostname verification

verify_cert_cb() retrieved the gnutls session pointer and passed it to
gnutls_certificate_verify_peers3() as the expected hostname.  But the
session pointer is set to the osmo_tls_session struct (it is needed by
cert_callback()), not a hostname string.  Hostname matching was
therefore performed against raw struct bytes, rendering verification
meaningless and potentially reading out of bounds, even when
"tls verify-cert" was enabled.

Store the configured hostname in struct osmo_tls_session and have
verify_cert_cb() read it from there.  Also drop the stray
gnutls_certificate_verify_peers3() call in the client setup: it ran
before any handshake (so there were no peer certificates yet) and its
result was ignored; the real verification happens via the registered
callback during the handshake.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change-Id: If64950a698bfcfbf556a37ef1be3e68abc124384
Vadim Yanitskiy at

#237 (Jun 17, 2026, 1:51:56 PM)

tls: do not treat GNUTLS_E_AGAIN/INTERRUPTED as fatal on read

osmo_tls_client_bfd_cb() treated any non-positive return from
gnutls_record_recv() as a fatal error and tore down the session.  On a
non-blocking socket gnutls_record_recv() can return GNUTLS_E_AGAIN or
GNUTLS_E_INTERRUPTED (both negative but non-fatal), which would drop
an otherwise healthy TLS session.  Handle them as retryable, mirroring
the existing logic in tls_write().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change-Id: If2f842b202dd08c07dffe3770c51cf0ce886beee
Vadim Yanitskiy at

#236 (Jun 17, 2026, 1:51:55 PM)

client: fix off-by-one in wrapped pcap stats counter

When a libpcap stats counter (ps_recv/ps_drop/ps_ifdrop) wraps around
UINT_MAX, get_psbl_wrapped_ctr() computed the delta as
(UINT_MAX - old_val) + new_val, omitting the single increment that
takes the counter from UINT_MAX through zero.  Add the missing +1 so
the reported delta matches the real number of increments.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change-Id: I66581910dbd1e955831a6ff913042059ad4994a7
Vadim Yanitskiy at

#235 (Jun 17, 2026, 1:51:55 PM)

client: honor IPv4 header length in GPRS filter

The GPRS-NS/BSSGP filter assumed a fixed 20-byte IPv4 header (IP_LEN)
when locating the UDP header and payload.  When the captured packet
carries IPv4 options (ip_hl > 5), udp_data/payload_data pointed into
the middle of the headers and check_gprs() parsed garbage, classifying
packets incorrectly.

Use the actual header length from ip_hl, reject malformed headers
(ip_hl < 5), and re-validate that the larger headers fit within the
captured length before computing the payload.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change-Id: Iac1fa9cc2a3c06cbe19c3e7799a0b335f2e3dda9
Vadim Yanitskiy at

#234 (Jun 17, 2026, 1:51:55 PM)

server: fix NULL deref of file_hdr_msg when store is disabled

When a connection has storing disabled (no store), conn->file_hdr_msg
is never populated.  The previous link-header handling skipped the
first branch (gated on conn->store) and fell through to the comparison
branch, which dereferenced the still-NULL conn->file_hdr_msg, crashing
the server on the first PKT_LINK_HDR from such a client.

Gate the whole header tracking on conn->store and simply free the
message when not storing, since osmo_pcap_conn_restart_trace() already
no-ops in that case.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change-Id: I419e1b66d07307c3e49294984887c153cd8494c3
Vadim Yanitskiy at

#233 (Jun 17, 2026, 1:51:55 PM)

server: fix zmq message leak on send failure

zmq_msg_send() only transfers ownership of the message to ZeroMQ on
success.  On failure the caller retains ownership, so the previously
init'd zmq_msg_t was leaked on every failed publish.  Close it
explicitly on the error path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change-Id: I501b1bf55bede4e69fa5d9b3f38d87341482ff49
Vadim Yanitskiy at

#232 (Jun 17, 2026, 1:51:54 PM)

client: Fix 32-bit overflow when computing pcapng EPB timestamp

tv_sec * 1000 * 1000 was evaluated in int arithmetic.  Where time_t /
tv_sec is 32-bit, this overflows for any tv_sec > ~2147, corrupting
the 64-bit timestamp_usec well before the year 2038.  Cast tv_sec to
uint64_t before the multiplication so the whole expression
is computed in 64 bits.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change-Id: I20d3282b8cba1675ce2d0860e66027e5ee8245ef
Vadim Yanitskiy at

#231 (Jun 17, 2026, 1:51:54 PM)

client: vty: do not print NULL tls hostname

conn->tls_hostname defaults to NULL and can be cleared via "no tls
hostname".  Writing it unconditionally emitted a "tls hostname (null)"
line, producing a config that does not re-parse.  Guard it like the
other optional tls fields.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change-Id: I5b920337409d8c9fa1edb8d47177882cf0a6c4e7
Vadim Yanitskiy at

#230 (Jun 17, 2026, 1:51:54 PM)

server: vty: validate rotate-localtime modulus against the new interval

apply_rotate_localtime() computed the maximum allowed modulus from
pcap_server->rotate_localtime.intv, the currently-stored (old) interval,
rather than the intv argument being applied.  On first configuration the
stored interval is the default 0, so the switch hit the default case and
rejected an otherwise valid command; when changing intervals the modulus
was bounds-checked against the wrong interval.  Switch on intv instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change-Id: I0b367d4e255db3208b41e12adec682026b99cc18
Vadim Yanitskiy at

#229 (Jun 17, 2026, 1:50:23 PM)

server: vty: fix docs for cfg_server_rotate_localtime[_mod_n]

Change-Id: I6fd1d081bba035fbd9d72a1705ab58194edf274e
Fixes: 18747641 ("pcap-server: Make rotate-localtime feature configurable through VTY")
Vadim Yanitskiy at

#228 (Jun 17, 2026, 12:57:20 PM)

doc: clarify 'pcap snaplen' / 'max-snaplen'

Change-Id: Ic2c82173c12814d61f0ee9f7454b9e5dcb0c13f4
Related: SYS#8099
Vadim Yanitskiy at

#227 (Jun 17, 2026, 12:57:18 PM)

vty: clamp configured snaplen to the wire-framing limit

osmo-pcap carries each captured packet in a frame whose length field
(struct osmo_pcap_data.len) is a uint16_t, so any snaplen above ~64 KiB
cannot be transported and is silently clamped by the server when sizing
its receive buffer (calc_data_max_len() caps at UINT16_MAX). The VTY,
however, advertised libpcap's MAXIMUM_SNAPLEN (262144), misleading users
into configuring values that never take effect.

Introduce OSMO_PCAP_MAX_SNAPLEN (65535) and, in both the client "pcap
snaplen" and server "max-snaplen" handlers, warn and cap the value to it
when a larger one is given. The command syntax keeps the <1-262144>
range for backwards compatibility so existing configs still parse; the
help text now documents the effective 64 KiB limit.

Related: SYS#8099
Related: 6d2f7c52 ("server: Limit rx buffer size to UINT16_MAX")
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change-Id: Ia56cad48e8cefe8ae103f2f7d2e037bf28438b71
Vadim Yanitskiy at