Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# Root CMake configuration for collector.
#
# The actual build logic lives in collector/CMakeLists.txt. This file exists
# so CMake can be invoked from the repo root (standard convention) and to
# hold project-wide settings like enable_testing().
cmake_minimum_required(VERSION 3.15)
project(collector)

Expand Down
10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# Top-level Makefile for the collector repository.
#
# CMake handles C++ compilation, but the overall build also involves Docker
# image assembly, builder container lifecycle, and integration test
# orchestration — tasks better expressed as Make targets. The builder
# container provides a reproducible toolchain so developers don't need
# to install C++ deps locally.
BASE_PATH = .
include Makefile-constants.mk

Expand Down Expand Up @@ -72,6 +79,9 @@ ci-all-tests: ci-benchmarks ci-integration-tests

.PHONY: start-builder
start-builder: builder teardown-builder
# --cap-add sys_ptrace: needed for address sanitizer and debugging.
# -v $(CURDIR):$(CURDIR):Z : same absolute path inside the container keeps
# CMake build artifacts consistent. :Z relabels for SELinux on RHEL/Fedora.
docker run -id \
--name $(COLLECTOR_BUILDER_NAME) \
--pull never \
Expand Down
44 changes: 41 additions & 3 deletions collector/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
# Build configuration for the three collector executables:
#
# collector - Main daemon. Runs as PID 1 in the DaemonSet pod, attaches
# the CO-RE eBPF probe via Falco's sinsp library, and streams
# events to Sensor over gRPC.
#
# self-checks - Lightweight startup validator. Confirms the BPF CO-RE driver
# can load on the current kernel before the full collector
# starts, enabling fast-fail with a clear diagnostic.
#
# connscrape - Diagnostic utility for dumping live connection state from
# /proc. Useful for debugging network-related collection issues.
#
project(collector-bin)

find_package(Threads)
Expand All @@ -8,11 +21,14 @@ find_package(civetweb CONFIG REQUIRED)
find_package(prometheus-cpp CONFIG REQUIRED)

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR})
# -fno-omit-frame-pointer: needed for gperftools CPU profiling and perf.
# -rdynamic: crash-handler backtraces need exported symbols for readable names.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall --std=c++17 -pthread -Wno-deprecated-declarations -fno-omit-frame-pointer -rdynamic")

set(CMAKE_CXX_FLAGS_DEBUG "-g -ggdb -D_DEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -fno-strict-aliasing -DNDEBUG")

# ASan/TSan and gperftools both intercept malloc, so they conflict at link time.
if(ADDRESS_SANITIZER)
set(DISABLE_PROFILING ON)
set(USE_VALGRIND OFF)
Expand Down Expand Up @@ -59,14 +75,20 @@ include_directories(${FALCO_DIR}/userspace/libsinsp)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
set(DRIVER_HEADERS ${FALCO_DIR}/driver/ppm_events_public.h ${FALCO_DIR}/driver/ppm_fillers.h)

# Enables protobuf arena allocation — batches allocations and frees them all at
# once, reducing heap fragmentation in the high-throughput gRPC event path.
add_definitions(-DUSE_PROTO_ARENAS)

# Redirect sinsp ASSERT macros to log warnings instead of abort(). A crash
# in the collector process would blind the entire node.
add_definitions(-DASSERT_TO_LOG)

# Optimization, only process socket file descriptors
# Only track socket file descriptors — ignoring file/pipe FDs avoids tracking
# millions of irrelevant descriptors and substantially reduces memory usage.
add_definitions(-DSCAP_SOCKET_ONLY_FD)

# Filter out some cgroup subsys
# Limit cgroup parsing to these subsystems to avoid scanning dozens of
# irrelevant controllers per process when resolving container IDs.
add_definitions("-DINTERESTING_SUBSYS=\"perf_event\", \"cpu\", \"cpuset\", \"memory\"")

add_subdirectory(lib)
Expand All @@ -81,26 +103,42 @@ add_executable(self-checks self-checks.cpp)

add_subdirectory(test)

# Falco Wrapper Library
# Falco sinsp library configuration.
# Legacy kernel module driver is unused — collector uses CO-RE eBPF (below).
set(BUILD_DRIVER OFF CACHE BOOL "Build the driver on Linux" FORCE)
set(USE_BUNDLED_DEPS OFF CACHE BOOL "Enable bundled dependencies instead of using the system ones" FORCE)
set(USE_BUNDLED_CARES OFF CACHE BOOL "Enable bundled dependencies instead of using the system ones" FORCE)
# gVisor intercepts syscalls differently and is not a supported runtime.
set(BUILD_LIBSCAP_GVISOR OFF CACHE BOOL "Do not build gVisor support" FORCE)
set(MINIMAL_BUILD OFF CACHE BOOL "Minimal" FORCE)
# Reduces per-thread memory from ~1KB to a few hundred bytes. Prevents OOM
# on nodes with thousands of threads.
set(SINSP_SLIM_THREADINFO ON CACHE BOOL "Slim threadinfo" FORCE)
# Collector ships as a statically-linked binary in a minimal UBI-micro
# container — dynamic linking would require shipping .so files.
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build position independent libraries and executables" FORCE)
# Exception to static linking: libbpf dlopen()s libelf at runtime to parse
# BPF ELF objects, so libelf must remain a shared library.
set(LIBELF_LIB_SUFFIX ".so" CACHE STRING "Use libelf.so" FORCE)
Comment on lines +117 to 122

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/sh
set -eu
rg -n 'BUILD_SHARED_LIBS|LIBELF_LIB_SUFFIX|target_link_libraries|dnf install|libstdc\+\+|openssl|tbb' \
  collector/CMakeLists.txt collector/lib/CMakeLists.txt collector/container/Dockerfile

Repository: stackrox/collector

Length of output: 1860


🏁 Script executed:

#!/bin/sh
set -eu

sed -n '108,126p' collector/CMakeLists.txt
printf '\n---\n'
sed -n '1,40p' collector/container/Dockerfile

Repository: stackrox/collector

Length of output: 3098


Reword this to avoid implying a fully static binary. BUILD_SHARED_LIBS only changes the default for project libraries; the image still ships shared runtime deps like libstdc++, openssl, tbb, and libelf remains shared. The cache help text should also describe static/shared linkage, not position-independent code.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@collector/CMakeLists.txt` around lines 117 - 122, Reword the comments around
BUILD_SHARED_LIBS and LIBELF_LIB_SUFFIX to state that project libraries default
to static linkage while required shared runtime dependencies remain supported,
avoiding any implication that the binary is fully static. Update the
BUILD_SHARED_LIBS cache help text to describe static/shared linkage rather than
position-independent code.

Source: Path instructions


# Turn OFF falco's unit tests and examples
set(CREATE_TEST_TARGETS OFF CACHE BOOL "Enable make-targets for unit testing" FORCE)
set(BUILD_LIBSCAP_EXAMPLES OFF CACHE BOOL "Build libscap examples" FORCE)
set(BUILD_LIBSINSP_EXAMPLES OFF CACHE BOOL "Build libsinsp examples" FORCE)

# Collector runs in a container but needs the host's /proc and /sys. The
# DaemonSet mounts the host root at /host; this tells sinsp to prefix all
# host filesystem lookups accordingly (e.g. /host/proc instead of /proc).
set(SCAP_HOST_ROOT_ENV_VAR_NAME "COLLECTOR_HOST_ROOT" CACHE STRING "Host root environment variable name" FORCE)

# CO-RE (Compile Once - Run Everywhere) eBPF eliminates the need to ship
# per-kernel driver modules, simplifying deployment across kernel versions.
set(BUILD_LIBSCAP_MODERN_BPF ON CACHE BOOL "Enable modern bpf engine" FORCE)
set(MODERN_BPF_DEBUG_MODE ${BPF_DEBUG_MODE} CACHE BOOL "Enable BPF debug prints" FORCE)

# Exclude high-frequency syscalls (ppoll, nanosleep) and ones not used for
# detection (openat2, setsockopt, io_uring_setup) to reduce BPF memory
# footprint and verifier load time.
set(MODERN_BPF_EXCLUDE_PROGS "^(openat2|ppoll|setsockopt|io_uring_setup|nanosleep)$" CACHE STRING "Set of syscalls to exclude from modern bpf engine " FORCE)

add_subdirectory(${FALCO_DIR} falco)
18 changes: 17 additions & 1 deletion collector/collector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,17 @@ extern "C" {
#include "Logging.h"
#include "Utility.h"

// Sensor connection timeout: 30 polls × 1s each = 30s before giving up.
// This is a startup-only timeout; once connected, the gRPC channel handles
// reconnection internally.
static const int MAX_GRPC_CONNECTION_POLLS = 30;

using namespace collector;

// Global control variable shared with CollectorService via pointer.
// Must be lock-free for safe use inside signal handlers.
static std::atomic<ControlValue> g_control(ControlValue::RUN);
// Stores the signal number that triggered shutdown, for logging purposes.
static std::atomic<int> g_signum(0);

static void
Expand Down Expand Up @@ -115,6 +121,9 @@ void gplNotice() {
}

void initialChecks() {
// The control variable is written from signal handlers, so it must be
// lock-free to avoid deadlocks. This should always succeed on modern
// architectures, but we check defensively.
if (!g_control.is_lock_free()) {
CLOG(FATAL) << "Internal error: could not create a lock-free control variable.";
}
Expand Down Expand Up @@ -158,6 +167,10 @@ int main(int argc, char** argv) {

CollectorConfig config;
config.InitCollectorConfig(args);
// Load the runtime config file once at startup. The ConfigLoader inside
// CollectorService will watch for changes via inotify after this point.
// FILE_NOT_FOUND is not fatal (the config file is optional), but
// PARSE_ERROR means the file exists but is malformed.
if (ConfigLoader(config).LoadConfiguration() == collector::ConfigLoader::PARSE_ERROR) {
CLOG(FATAL) << "Unable to parse configuration file";
}
Expand All @@ -184,7 +197,10 @@ int main(int argc, char** argv) {
CLOG(INFO) << "GRPC is disabled. Specify GRPC_SERVER='server addr' env and signalFormat = 'signal_summary' and signalOutput = 'grpc'";
}

// Register signal handlers
// Register signal handlers after gRPC is connected but before RunForever(),
// so that crash signals produce stack traces (AbortHandler) and graceful
// shutdown signals (SIGTERM/SIGINT) set the atomic control variable rather
// than terminating immediately.
signal(SIGABRT, AbortHandler);
signal(SIGSEGV, AbortHandler);
signal(SIGTERM, ShutdownHandler);
Expand Down
17 changes: 16 additions & 1 deletion collector/container/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
# UBI-micro: required for Red Hat container certification. The smallest UBI
# variant — no package manager, keeping the final image minimal.
FROM registry.access.redhat.com/ubi10/ubi-micro:latest AS ubi-micro-base

# ubi-micro has no dnf, so we use the full UBI image to install packages into
# an --installroot overlay. The final image gets the packages without dnf.
FROM registry.access.redhat.com/ubi10/ubi:latest AS package_installer

# Copy ubi-micro base to /out to preserve its rpmdb
COPY --from=ubi-micro-base / /out/

# Install packages directly to /out/ using --installroot
# Install runtime dependencies into /out/ using --installroot.
# elfutils-libelf: BPF ELF parsing; tbb: sinsp runtime dep; curl-minimal:
# healthcheck; libcap-ng: capability ops; ca-certificates: TLS to Sensor.
RUN dnf install -y \
--installroot=/out/ \
--releasever=10 \
Expand All @@ -15,6 +21,8 @@ RUN dnf install -y \
dnf clean all --installroot=/out/ && \
rm -rf /out/var/cache/dnf /out/var/cache/yum

# Final image is based on ubi-micro (not package_installer) to exclude dnf
# and the full UBI toolchain — only the /out/ overlay is merged in.
FROM ubi-micro-base

ARG COLLECTOR_VERSION
Expand All @@ -37,12 +45,17 @@ COPY --from=package_installer /out/ /

COPY container/THIRD_PARTY_NOTICES/ /THIRD_PARTY_NOTICES/
COPY kernel-modules /kernel-modules
# self-checks is a separate binary for BPF driver validation at startup,
# kept independent from the full collector dependency tree.
COPY container/bin/collector /usr/local/bin/
Comment on lines +48 to 50

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Correct the self-checks dependency claim.

collector/lib/CMakeLists.txt states that collector_lib is linked by all three executables, so copying self-checks separately does not make it independent from the collector dependency tree. Describe it as a separate startup-validation executable unless its link graph is also changed.

As per path instructions, this is a cross-layer maintainability issue with release-time dependency implications, not a wording nit.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@collector/container/Dockerfile` around lines 48 - 50, Update the Dockerfile
comment above the COPY command to describe self-checks only as a separate
startup-validation executable, removing the claim that it is independent from
the full collector dependency tree. Do not change the executable or copy
behavior unless the link graph is intentionally updated elsewhere.

Source: Path instructions

COPY container/bin/self-checks /usr/local/bin/self-checks
COPY container/status-check.sh /usr/local/bin/status-check.sh

# 8080: civetweb introspection (/ready, /state). 9090: Prometheus metrics.
EXPOSE 8080 9090

# Docker-native healthcheck for non-K8s environments and local dev/debugging.
# 5s start-period avoids false failures while the BPF driver loads.
HEALTHCHECK \
# health checks within the first 5s are not counted as failure
--start-period=5s \
Expand All @@ -51,4 +64,6 @@ HEALTHCHECK \
# the command uses /ready API
CMD /usr/local/bin/status-check.sh

# Exec form ensures collector runs as PID 1, receiving signals directly for
# graceful shutdown of the BPF probe and gRPC connection.
ENTRYPOINT ["collector"]
7 changes: 6 additions & 1 deletion collector/container/status-check.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#!/usr/bin/env bash

# Pattern-matches the JSON response rather than just checking HTTP status,
# confirming the collector event loop is actually running (not just the HTTP
# server). Uses shell glob matching since jq is not available in UBI-micro.

# /ready API will return the following formatted response:
# {
# "collector" : {
Expand All @@ -11,7 +15,8 @@
# "status" : "ok"
# }
#
# Pattern match for "status":"ok" in the JSON response
# -s: suppress progress noise; -f: non-zero exit on HTTP errors.
# Port 8080 is the civetweb introspection server (not Prometheus on 9090).
case "$(curl -sf localhost:8080/ready)" in
*'"status"'*'"ok"'*) exit 0 ;;
*) exit 1 ;;
Expand Down
14 changes: 14 additions & 0 deletions collector/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
# collector_lib: shared library linked by all three executables (collector,
# self-checks, connscrape). Centralises detection logic, gRPC transport, and
# introspection so the executables themselves are thin entry points.
file(GLOB COLLECTOR_LIB_SRC_FILES
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/system-inspector/*.cpp
)

add_library(collector_lib ${DRIVER_HEADERS} ${COLLECTOR_LIB_SRC_FILES})
# sinsp: Falco's eBPF event engine, syscall parsing, and container-aware thread tables.
add_dependencies(collector_lib sinsp)
target_link_libraries(collector_lib sinsp)
target_link_libraries(collector_lib stdc++fs) # This is needed for GCC-8 to link against the filesystem library
# cap-ng: inspect and drop Linux capabilities for BPF operations.
target_link_libraries(collector_lib cap-ng)
target_link_libraries(collector_lib uuid)
# gRPC: bidirectional streaming to Sensor for high-volume runtime events.
target_link_libraries(collector_lib gRPC::grpc++)
# civetweb: lightweight embeddable HTTP server for introspection endpoints on 8080.
target_link_libraries(collector_lib civetweb::civetweb-cpp)
target_link_libraries(collector_lib yaml-cpp::yaml-cpp)
# Pull mode: collector hosts a /metrics endpoint on 9090 for Prometheus scraping.
target_link_libraries(collector_lib prometheus-cpp::core prometheus-cpp::pull)

# Generated protobuf/gRPC stubs for the Collector↔Sensor API.
target_link_libraries(collector_lib rox-proto)

# tcmalloc reduces malloc lock contention in the multi-threaded event pipeline.
# libprofiler enables on-demand CPU profiling in production via SIGPROF.
# Both are disabled under sanitizers/valgrind to avoid conflicts.
if(NOT DISABLE_PROFILING)
find_library(GPERFTOOLS_PROFILER profiler)
find_library(GPERFTOOLS_TCMALLOC tcmalloc)
Expand All @@ -37,4 +49,6 @@ if (COVERAGE)
target_link_options(collector_lib PUBLIC "--coverage")
endif()

# z: gRPC compression + BPF ELF decompression. ssl/crypto: TLS to Sensor.
# bpf: libbpf for loading CO-RE eBPF programs.
target_link_libraries(collector_lib z ssl crypto bpf)
16 changes: 11 additions & 5 deletions collector/lib/CollectorService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@

namespace collector {

// Civetweb configuration: serves HTTP introspection endpoints (status, log
// level, profiler, container info, network state) on port 8080.
static const char* OPTIONS[] = {"listening_ports", "8080", nullptr};
// Prometheus metrics are exposed on a separate port to keep them isolated
// from the introspection endpoints.
static const std::string PROMETHEUS_PORT = "9090";

CollectorService::CollectorService(CollectorConfig& config, std::atomic<ControlValue>* control,
Expand All @@ -36,11 +40,12 @@ CollectorService::CollectorService(CollectorConfig& config, std::atomic<ControlV
config_loader_(config_) {
CLOG(INFO) << "Config: " << config_;

// Network tracking
// Network tracking subsystem setup.
// When gRPC is disabled (no Sensor), we still initialize the networking
// infrastructure so that connections can be logged to stdout — this is
// useful for standalone debugging. NetworkConnectionInfoServiceComm
// detects the null channel and falls back to stdout output.
if (!config_.grpc_channel || !config_.DisableNetworkFlows()) {
// In case if no GRPC is used, continue to setup networking infrasturcture
// with empty grpc_channel. NetworkConnectionInfoServiceComm will pick it
// up and use stdout instead.
conn_tracker_ = std::make_shared<ConnectionTracker>();
UnorderedSet<L4ProtoPortPair> ignored_l4proto_port_pairs(config_.IgnoredL4ProtoPortPairs());
conn_tracker_->UpdateIgnoredL4ProtoPortPairs(std::move(ignored_l4proto_port_pairs));
Expand Down Expand Up @@ -87,7 +92,8 @@ CollectorService::~CollectorService() {

exporter_.stop();

// system_inspector_ needs to be last, since other components relay on it.
// system_inspector_ must be torn down last because NetworkStatusNotifier
// and other components hold pointers into sinsp state (thread table, etc.).
system_inspector_.CleanUp();
}

Expand Down
8 changes: 8 additions & 0 deletions collector/lib/CollectorService.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@

namespace collector {

/// Top-level service that owns and orchestrates all collector subsystems:
/// system inspector (BPF event capture), network status notifier (periodic
/// /proc scraping + delta reporting), configuration hot-reload, HTTP
/// introspection endpoints (civetweb), and Prometheus metrics export.
///
/// Lifecycle: construct → InitKernel() → RunForever() → destructor.
/// RunForever() blocks in the sinsp event loop until the atomic control
/// variable signals STOP_COLLECTOR.
class CollectorService {
public:
CollectorService(const CollectorService&) = delete;
Expand Down
17 changes: 13 additions & 4 deletions collector/lib/ConfigLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,19 @@ class ParserYaml {
ValidationMode validation_mode_;
};

/**
* Reload configuration based on inotify events received on a
* configuration file.
*/
/// Watches the runtime configuration file (default: /etc/stackrox/runtime_config.yaml)
/// for changes via inotify and hot-reloads the CollectorConfig accordingly.
///
/// Uses protobuf reflection to map YAML fields to the sensor::CollectorConfig
/// proto, so adding new config fields only requires updating the proto definition
/// — no code changes needed in the loader itself.
///
/// Handles both direct files and symlinks (Kubernetes ConfigMaps are mounted
/// as symlink chains that get atomically swapped, which generates different
/// inotify events than a simple file write). Three watchers are maintained:
/// - LOADER_PARENT_PATH: directory-level events (create/delete of the file)
/// - LOADER_CONFIG_FILE: events on the config file/symlink itself
/// - LOADER_CONFIG_REALPATH: events on the symlink target (for ConfigMap swaps)
Comment on lines +180 to +185

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document these as up to three watcher categories.

WatchFile() only creates the realpath watcher for symlinks, and it does not create the config-file watcher until the file exists. Saying “Three watchers are maintained” is therefore inaccurate for direct-file and missing-file configurations.

Proposed wording
-/// as symlink chains that get atomically swapped, which generates different
-/// inotify events than a simple file write). Three watchers are maintained:
+/// as symlink chains that get atomically swapped, which generates different
+/// inotify events than a simple file write). Up to three watcher categories
+/// are used:
...
-///   - LOADER_CONFIG_REALPATH: events on the symlink target (for ConfigMap swaps)
+///   - LOADER_CONFIG_REALPATH: events on the symlink target, when the config
+///     path is a symlink (for ConfigMap swaps)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// Handles both direct files and symlinks (Kubernetes ConfigMaps are mounted
/// as symlink chains that get atomically swapped, which generates different
/// inotify events than a simple file write). Three watchers are maintained:
/// - LOADER_PARENT_PATH: directory-level events (create/delete of the file)
/// - LOADER_CONFIG_FILE: events on the config file/symlink itself
/// - LOADER_CONFIG_REALPATH: events on the symlink target (for ConfigMap swaps)
/// Handles both direct files and symlinks (Kubernetes ConfigMaps are mounted
/// as symlink chains that get atomically swapped, which generates different
/// inotify events than a simple file write). Up to three watcher categories
/// are used:
/// - LOADER_PARENT_PATH: directory-level events (create/delete of the file)
/// - LOADER_CONFIG_FILE: events on the config file/symlink itself
/// - LOADER_CONFIG_REALPATH: events on the symlink target, when the config
/// path is a symlink (for ConfigMap swaps)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@collector/lib/ConfigLoader.h` around lines 180 - 185, Update the
documentation comment above WatchFile to describe the watchers as up to three
categories rather than stating that all three are always maintained. Clarify
that LOADER_CONFIG_FILE is created only when the file exists and
LOADER_CONFIG_REALPATH only applies to symlink targets, while retaining the
existing category descriptions.

class ConfigLoader {
public:
ConfigLoader() = delete;
Expand Down
11 changes: 10 additions & 1 deletion collector/lib/ConnTracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,14 @@ namespace collector {

namespace {

// Sentinel addresses representing "all external IPs" when external-IPs
// mode is disabled. Public addresses that don't match any known network
// are aggregated to these canonical addresses, reducing cardinality in
// the network flow data sent to Sensor.
static const Address canonical_external_ipv4_addr(255, 255, 255, 255);
static const Address canonical_external_ipv6_addr(0xffffffffffffffffULL, 0xffffffffffffffffULL);
// Pre-built radix tree of RFC 1918 / RFC 4193 private networks, used to
// determine whether known_ip_networks overlap with private address space.
static const NRadixTree private_networks_tree(PrivateNetworks());

} // namespace
Expand Down Expand Up @@ -167,7 +173,10 @@ void ConnectionTracker::CloseConnectionsOnExternalIPsConfigChange(ExternalIPsCon
Connection ConnectionTracker::NormalizeConnectionNoLock(const Connection& conn) const {
bool is_server = conn.is_server();
if (conn.l4proto() == L4Proto::UDP) {
// Inference of server role is unreliable for UDP, so go by port.
// UDP is connectionless, so the kernel doesn't track client/server roles.
// We use a port-based heuristic: the side with the higher ephemeral port
// score is likely the client. See IsEphemeralPort() for the scoring
// system that accounts for different OS port range conventions.
is_server = IsEphemeralPort(conn.remote().port()) > IsEphemeralPort(conn.local().port());
}

Expand Down
Loading
Loading