Files
mitm-webserver/documentation/thesis/02-preliminaries.tex
malmert a4b19f8c3e
Some checks failed
Build and Deploy MITM Webserver / build (push) Has been cancelled
Build and Deploy MITM Webserver / traffic_target (push) Has been cancelled
doc
2026-05-23 12:19:22 +02:00

166 lines
32 KiB
TeX

\chapter{Preliminaries}
\label{chap:preliminaries}
In this chapter, the necessary background and foundational concepts underlying the research presented in this thesis are introduced. First, the theoretical frameworks and methodologies guiding the approach are discussed, followed by an overview of the key technologies and tools used in this work. The chapter is intended to establish a common understanding and provide context for the subsequent chapters, in which the specific contributions and findings of the research are presented.
\section[OSI Model]{\ac{OSI} Model}
\label{sec:osi}
The \ac{OSI} Basic Reference Model provides a conceptual framework for describing communication between open systems in a structured and interoperable way. Instead of treating network communication as a single process, it divides it into seven layers with clearly separated responsibilities. This layered view simplifies the analysis of communication systems and provides a common terminology for discussing protocols and interfaces.
The \ac{OSI} model is not itself a concrete protocol suite, but rather a reference architecture. It does not prescribe which technologies must be used in practice. Instead, it provides a general structure that can be used to classify communication functions and to explain how different protocols relate to one another. Each layer offers services to the layer above while relying on the services of the layer below.
\subsection{Physical Layer}
The Physical Layer is concerned with the transmission of raw bit streams over the physical medium. It defines how signals are represented and transferred, for example over cables, optical fibers, or wireless links. It therefore forms the foundation of all higher-level communication.
\subsection{Data Link Layer}
The Data Link Layer organizes the raw bits received from the Physical Layer into structured units and supports communication between adjacent nodes on the same link. It is responsible for local addressing, medium access control, and error detection on the local transmission path.
\subsection{Network Layer}
The Network Layer enables communication beyond a single local link. It provides logical addressing and routing functions that allow data to be forwarded across interconnected networks from a source to a destination.
\subsection{Transport Layer}
The Transport Layer provides end-to-end communication services between application entities in different systems. Depending on the protocol and service model, this can include segmentation, reassembly, flow control, and error recovery.
\subsection{Session Layer}
The Session Layer is responsible for establishing, managing, and terminating communication sessions between applications. It structures the dialogue between communicating systems and can support synchronization during longer exchanges.
\subsection{Presentation Layer}
The Presentation Layer deals with the representation of data. It ensures that information exchanged between systems can be interpreted correctly even when internal data formats differ. Typical functions include formatting, translation, and related representation issues.
\subsection{Application Layer}
The Application Layer is the highest layer of the model and contains the communication functions used directly by application processes. It forms the interface between the communication system and the software that uses network services.
\subsection{Layered Structure and Function}
A key principle of the \ac{OSI} model is that each layer has a defined scope of responsibility and interacts mainly with the layers directly above and below it. This reduces complexity and supports standardization by allowing communication functions to be discussed separately while still being part of one overall architecture.
For the present thesis, the \ac{OSI} model is mainly used as a conceptual orientation for the discussion of communication layers and network functions. Even though the implemented system is better described using the practical \ac{TCP}/\ac{IP} stack, the \ac{OSI} structure remains useful for introducing the general principles of layered communication.
\section{Transparent Network Interception Models}
\label{sec:transparent-network-interception-models}
\subsection{Man-in-the-Middle Terminology}
The term \ac{MITM} describes a communication setting in which an intermediate system is positioned between two endpoints and can observe, relay, insert, or modify messages exchanged between them \cite{conti2016mitmsurvey}. In security literature, this position is often discussed as an adversarial capability \cite{conti2016mitmsurvey}. In the present thesis, the term is used in a controlled experimental sense: the system is intentionally placed in the communication path in order to observe, correlate, and selectively manipulate traffic. The relevant distinction is therefore not only whether traffic can be observed, but also at which layer the intermediate system is inserted and whether it becomes visible to the endpoints.
\subsection[Passive Capture with TAP and SPAN]{Passive Capture with \ac{TAP} and \ac{SPAN}}
Passive monitoring systems obtain a copy of network traffic without becoming the forwarding element. A \ac{TAP} is a dedicated device inserted directly into the monitored physical link, for example between a host and a switch or between two switches. It copies the traffic that crosses this link to one or more monitoring interfaces while the original traffic continues between the connected endpoints. In contrast, \ac{SPAN}, also known as port mirroring, is configured on a switch. The monitored devices remain connected to their normal switch ports, and the switch duplicates selected ingress, egress, or bidirectional traffic from these ports to a separate monitoring port. The main difference is therefore where the traffic copy is produced. A \ac{TAP} observes the link directly at its physical position in the path, whereas \ac{SPAN} observes traffic indirectly from inside the switch forwarding and mirroring implementation. Neither mechanism gives the monitoring device direct control over the original forwarding decision, so passive capture cannot directly block or modify packets in the original stream. Zhang and Moore show that \ac{SPAN}-based monitoring can also introduce measurement artifacts, including inter-packet timings, packet reordering, and packet loss \cite{zhang2007portmirroring}.
\subsection{Layer-3 Routed Interception}
In a routed interception model, the intermediate system is part of the \ac{IP} forwarding path. An \ac{IP} router receives a packet, determines the next hop based on the destination \ac{IP} address and routing information, and transmits the packet through the selected outgoing interface \cite{rfc1812}. From the perspective of the endpoints, a routed intermediary therefore behaves as a router or gateway rather than as an Ethernet switch. Traffic must either be configured to use this system as its next hop, for example through a default gateway setting, or the surrounding network must otherwise be changed so that packets are routed through it.
This placement has visible protocol effects. In \ac{IPv4}, every router that forwards a packet decrements the \ac{TTL} field \cite{rfc1812}. Therefore, a routed intermediary can appear as an additional \ac{IP} hop to tools and diagnostics that inspect hop-count behavior.
A routed intermediary may also modify packet headers. If \ac{NAT} is used, address information is rewritten as packets traverse the translator \cite{rfc3022}. Depending on the configuration, this can affect source or destination \ac{IP} addresses, transport-layer ports, and the reverse mapping needed for return traffic \cite{rfc3022}. Even without \ac{NAT}, routed forwarding changes the Layer-2 next hop because the packet is emitted through the outgoing link selected by the routing decision \cite{rfc1812}. Consequently, the intermediary is not merely observing an existing Ethernet segment; it actively participates in \ac{IP} forwarding. This makes routed interception useful when the intermediate system is intended to enforce Layer-3 policy, apply firewalling, perform \ac{NAT}, or deliberately act as a gateway.
\subsection{Proxy-Based Interception}
Proxy-based interception moves the intermediary even higher in the stack. An \ac{HTTP} proxy terminates or relays application-layer requests rather than merely forwarding Ethernet frames. For \ac{HTTPS}, interception typically requires a \ac{TLS} proxy that presents itself as the server to the client and as the client to the external server, thereby creating two separate \ac{TLS} connections \cite{waked2018tlsinterception}. This model can expose plaintext to the proxy when the client trusts a signing \ac{CA} controlled by the proxy \cite{waked2018tlsinterception}. At the same time, it changes the end-to-end security model of \ac{TLS} \cite{decarnedecarnavalet2023tlsinterception}. Empirical studies show that \ac{HTTPS} interception can be detected through inconsistencies between \ac{HTTP} \texttt{User-Agent} information and \ac{TLS} client behavior \cite{durumeric2017httpsinterception}, and that interception appliances may introduce certificate-validation and parameter-mapping weaknesses \cite{waked2018tlsinterception}. Proxy-based interception is therefore powerful for application-layer inspection, but it is not transparent in the same sense as Layer-2 forwarding.
\subsection{Transparent Layer-2 Inline Bridges}
A transparent inline bridge occupies the forwarding path without acting as an \ac{IP} router or application proxy. Such a bridge connects network segments at the data link layer and forwards frames based on bridge state and destination \ac{MAC} addresses \cite{ieee8021q2022}. The Linux bridge implements this behavior by learning source \ac{MAC} addresses, maintaining an \ac{FDB}, and forwarding, filtering, flooding, or locally delivering frames according to the bridge configuration \cite{linuxkernelbridgedocs}. In this model, the bridge does not have to be configured as the endpoints' \ac{IP} gateway or as an application proxy, because forwarding is performed below the \ac{IP} layer.
\subsection{Transparency and Detectability}
Transparency should not be understood as complete undetectability. An inline bridge can affect latency, packet ordering, loss behavior, link-state propagation, and bridge-control behavior. If \ac{STP} is enabled, \acp{BPDU} and forwarding-delay behavior may become externally visible \cite{linuxkernelbridgedocs}. If \ac{TLS} proxying is added on top of forwarding, certificate and handshake artifacts can reveal the interception point \cite{durumeric2017httpsinterception}. The transparency goal in this thesis is therefore narrower and technical: the system should forward traffic as a Layer-2 inline bridge without introducing an additional \ac{IP} hop, without requiring endpoint proxy configuration, and without terminating application-layer sessions unless a later manipulation component explicitly does so.
\section{Linux Packet Processing Path}
\label{sec:linux-packet-processing-path}
The following section explains how network packets are processed by the Linux kernel. First, the internal packet representation is described. Next, the receive path from the \ac{NIC} into the kernel is outlined. Then, the local delivery, forwarding, and bridge paths are distinguished. Lastly, the relevant programmable hook points are explained because they define where a transparent traffic capture and manipulation platform can observe, mark, forward, or drop packets.
Linux networking is not a single processing step. Instead, packets move through device drivers, protocol implementations, routing or bridge logic, filtering hooks, queueing disciplines, and user space socket interfaces \cite{linuxkernelnetworkingdocs}. The exact path depends on whether a packet is locally generated, locally delivered, routed, or bridged \cite{stephan2024packetpath}. This distinction is important for the present thesis because a transparent \ac{MITM} system should normally forward frames at Layer 2, while still observing and manipulating packets at selected kernel hook points.
\subsection{Packet Representation}
On an Ethernet-based system, the bytes on the wire are structured as a frame. The Ethernet header contains source and destination \ac{MAC} addresses and an \texttt{EtherType} field. Depending on the \texttt{EtherType}, the frame may contain an \ac{ARP} message, an \ac{IPv4} packet, an \ac{IPv6} packet, or another payload. For \ac{IP} traffic, the network-layer header is followed by a transport-layer header such as \ac{TCP} or \ac{UDP}. The remaining bytes form the payload delivered to the application or forwarded to another interface.
Inside the Linux kernel, packets are mainly represented by \texttt{struct sk\_buff} \cite{linuxkernelskbuffdocs}. This structure does not contain the packet bytes directly. Instead, it stores metadata and pointers to one or more buffers that contain the actual headers and payload \cite{linuxkernelskbuffdocs}. The \texttt{head}, \texttt{data}, \texttt{tail}, and \texttt{end} pointers describe the usable packet buffer, while header offsets such as \texttt{mac\_header}, \texttt{network\_header}, and \texttt{transport\_header} indicate where individual protocol headers begin \cite{linuxkernelskbuffdocs}. As a result, protocol layers can prepend or remove headers by adjusting pointers instead of copying the complete packet \cite{stephan2024packetpath}.
The \texttt{sk\_buff} also carries processing metadata such as the receiving or transmitting network device, the packet length, protocol information, checksum state, priority values, and marks \cite{linuxkernelskbuffdocs}. Such metadata is not visible on the wire, but it can influence routing, filtering, queueing, and later processing stages. This property is useful for packet correlation because a mark stored in \texttt{skb->mark} can follow a packet through multiple kernel stages without changing the actual Ethernet frame.
Furthermore, Linux can clone an \texttt{sk\_buff} efficiently. A clone gets its own metadata structure while sharing the packet data buffer until modification becomes necessary. This is relevant for packet capture. Passive observers such as raw packet sockets can receive a clone of the packet while the original packet continues through the normal kernel path. Hence, capturing a packet does not necessarily mean that the packet was consumed by the capture process \cite{linuxkernelskbuffdocs}.
\subsection{Ingress Path}
The ingress path begins when the \ac{NIC} receives a frame from the physical medium. Modern \acp{NIC} often use multiple receive queues. With \ac{RSS}, the device can assign packets to queues based on a hash over packet header fields, allowing receive processing to be distributed over multiple \acp{CPU} \cite{linuxkernelscalingdocs}. The received bytes are transferred into main memory using \ac{DMA}, and the driver notifies the kernel that new receive work is available. Drivers commonly process this work through \ac{NAPI}, which combines interrupt notification with polling under load.
Before the regular networking stack processes the packet, \ac{XDP} may run in supported drivers \cite{hoilandjorgensen2018xdp}. Native \ac{XDP} executes an \ac{eBPF} program very early in the receive path, before the kernel allocates the normal \texttt{sk\_buff} structure \cite{hoilandjorgensen2018xdp}. The program can return a verdict to pass the packet to the kernel stack, drop it, transmit it back out, or redirect it to another target \cite{hoilandjorgensen2018xdp}. This makes \ac{XDP} useful for high-performance packet processing \cite{scholz2018ebpfpacketfiltering}. However, the early position also means that normal \texttt{sk\_buff} metadata is not yet available in native mode.
If the packet continues into the regular networking stack, the driver creates or completes an \texttt{sk\_buff} and passes it into the generic receive path, commonly through functions such as \texttt{netif\_receive\_skb()} \cite{stephan2024packetpath}. At this stage, Linux has metadata about the receiving interface and can expose the packet to early ingress processing. This includes \texttt{tc} ingress programs and the \texttt{nftables} \texttt{netdev} \texttt{ingress} hook \cite{nftableshooks}. In contrast to native \ac{XDP}, these hooks operate after the \texttt{sk\_buff} exists and can therefore read or write metadata such as \texttt{skb->mark}.
After early ingress processing, the packet may be cloned for packet sockets, handled by \ac{VLAN} logic, passed to a receive handler associated with a master device, or delivered to a protocol handler \cite{stephan2024packetpath}. The receive handler is particularly relevant for Linux bridges. If the ingress interface is enslaved to a bridge, the bridge receive handler can take ownership of the packet before the packet is delivered to the local \ac{IP} stack \cite{linuxkernelbridgedocs}.
\subsection{Local Delivery and \ac{IP} Forwarding}
If the packet is an \ac{IP} packet and is not taken over by a bridge or another master device, the \ac{IP} receive function processes it. For \ac{IPv4}, this path includes \texttt{ip\_rcv()}. The kernel validates essential header fields, checks packet length and checksum information, sets the transport header pointer, and invokes the \texttt{netfilter} \texttt{PRE\_ROUTING} hook. Afterwards, the routing decision determines whether the packet is locally delivered, forwarded to another interface, or handled as multicast traffic \cite{stephan2024packetpath}.
For local delivery, the packet follows the input path. Fragmented packets may first be reassembled. The packet then reaches the \texttt{netfilter} \texttt{LOCAL\_IN} hook and is passed to the appropriate transport-layer handler. For \ac{TCP}, Linux performs socket lookup, checksum validation, state-machine processing, sequence-number handling, and receive-queue insertion. For \ac{UDP}, the path is shorter and mainly consists of checksum validation, socket lookup, and datagram delivery. Finally, a user-space application reads the data through a system call such as \texttt{recv()} or \texttt{read()} \cite{stephan2024packetpath}.
For routed forwarding, the packet follows a different path. After the routing decision, \texttt{netfilter} can inspect the packet at the \texttt{FORWARD} hook. If the packet is accepted, Linux applies post-routing processing, performs neighbor resolution if necessary, and sends the packet to the selected output device. The kernel documentation on \texttt{netfilter} \texttt{flowtable} processing describes this classic forwarding path as a sequence of ingress, prerouting, routing decision, forward, postrouting, and neighbor transmission, while also describing how \texttt{flowtable} offload can bypass parts of that path for later packets of a flow \cite{linuxkernelflowtabledocs}.
\subsection{Ethernet Switching Concepts}
Ethernet switching is based on forwarding at the data link layer. The \ac{IEEE} \texttt{802.1Q-2022} standard specifies the operation of \ac{MAC} bridges and \ac{VLAN} bridges, which interconnect \acp{LAN} below the \ac{MAC} service boundary \cite{ieee8021q2022}. From the perspective of higher-layer protocols, such a bridge should be transparent: endpoints do not need to know that an intermediate bridge forwards the frame. Consequently, forwarding decisions are based on Ethernet destination addresses and bridge state rather than on \ac{IP} routes.
A learning bridge builds forwarding state from the source address of received frames. When a frame enters a bridge port, the bridge can associate the source \ac{MAC} address with the ingress port and store this association in the \ac{FDB} \cite{linuxkernelbridgedocs}. In \ac{VLAN}-aware operation, the relevant forwarding identity also includes the \ac{VLAN}; the Linux switch device documentation describes a bridge \ac{FDB} entry as a \texttt{\{port, mac, vlan\}} forwarding destination \cite{linuxkernelswitchdevdocs}. This distinction matters because the same \ac{MAC} address can belong to different Layer-2 domains when \acp{VLAN} are used.
If the destination address is known, the bridge can forward a unicast frame only to the port associated with that destination. If the destination is located on the same port as the source, the frame can be filtered instead of being sent back to the segment from which it arrived. If no matching destination entry exists, the frame is an unknown unicast and must be flooded to eligible ports in the same forwarding domain. Broadcast frames are also flooded within that domain, and multicast frames are flooded or forwarded according to multicast bridge state \cite{linuxkernelswitchdevdocs}. Thus, a bridge extends a broadcast domain unless \ac{VLAN} filtering or another separation mechanism divides the traffic into distinct Layer-2 domains.
\ac{VLAN} awareness allows one physical or virtual bridge to represent multiple separated broadcast domains. With \texttt{vlan\_filtering} enabled, forwarding decisions depend on both the destination \ac{MAC} address and the \ac{VLAN} tag \cite{linuxkernelbridgedocs}. The \texttt{ip-link(8)} manual describes the same configuration point as \texttt{vlan\_filtering}; when it is disabled, the bridge does not consider the \ac{VLAN} tag during packet handling \cite{man7iplink}.
Layer-2 loops are especially problematic because Ethernet frames do not contain a hop limit comparable to the \ac{IP} \ac{TTL} field. In a looped topology, flooded broadcast, multicast, or unknown-unicast frames can therefore circulate and be replicated until the network becomes unusable. \ac{STP} was introduced to let bridges compute a loop-free active topology in an extended \ac{LAN} \cite{perlman1985spanningtree}. \ac{RSTP} later improved reconfiguration behavior and is part of the modern bridge standards lineage described by \texttt{802.1Q} \cite{ieee8021q2022}. In Linux, \ac{STP} controls bridge port states such as blocking, learning, and forwarding, and it uses \acp{BPDU} to exchange topology information \cite{linuxkernelbridgedocs}.
\subsection{Linux Bridge Forwarding Path}
A Linux bridge implements the switching behavior described above inside the kernel. The bridge receives Ethernet frames from enslaved interfaces, learns source addresses, consults the \ac{FDB}, and either forwards, filters, floods, or locally delivers frames depending on the destination address and bridge configuration \cite{linuxkernelbridgedocs}. The \texttt{bridge} command exposes this state through objects such as \texttt{fdb}, \texttt{vlan}, and \texttt{link} \cite{man7bridge}.
This Layer-2 behavior is central for transparent interception. When two hosts communicate through a Linux bridge, their packets do not need to be routed by the bridge. Therefore, no additional \ac{IP} hop is introduced and the \ac{TTL} or hop-limit value is not decremented by normal bridge forwarding. From the perspective of the endpoints, the bridge behaves like an Ethernet segment or switch, although the kernel can still inspect, mark, filter, and capture frames while they traverse the bridge.
The bridge path has its own \texttt{netfilter} integration \cite{nftablesbridgefiltering}. The \texttt{nftables} \texttt{bridge} family provides hook points before and after the \ac{FDB} decision \cite{nftablesbridgefiltering}. In the \texttt{prerouting} hook, packets can be filtered before the bridge decides the output port. In the \texttt{forward} hook, packets can be filtered when they are bridged from one port to another. The \texttt{input} hook covers frames passed to the local stack, \texttt{output} covers frames coming from the local stack toward a bridge port, and \texttt{postrouting} covers both locally generated and forwarded bridge traffic \cite{nftablesbridgefiltering}.
The distinction between the \texttt{inet}, \texttt{ip}, and \texttt{bridge} \texttt{nftables} families is important. Rules in the \texttt{ip} or \texttt{inet} family operate on packets that enter the \ac{IP} stack. Rules in the \texttt{bridge} family operate on Ethernet frames in the bridge path. A transparent bridge that should inspect traffic without acting as an \ac{IP} router therefore needs \texttt{bridge}-family rules for Layer-2 forwarding decisions.
For the setup used in the present thesis, \ac{STP} is not required because the bridge is used as a controlled inline bridge between two network segments and no redundant Layer-2 path is intentionally introduced. Disabling \ac{STP} through \texttt{stp\_state} avoids topology negotiation, \ac{BPDU} processing, and forwarding-delay behavior that would otherwise add configuration-dependent effects to packet timing \cite{man7iplink}. This is only safe under the assumption that the physical and virtual topology is loop-free. If additional bridge ports or redundant links are added, \ac{STP} or \ac{RSTP} should remain enabled because Linux uses it to prevent loops and broadcast storms in Ethernet networks \cite{linuxkernelbridgedocs}.
\subsection{Egress Path}
The egress path depends on where the packet originates. For locally generated traffic, the path begins when an application writes to a socket. The socket layer calls functions such as \texttt{sock\_sendmsg()}, which select the transport-layer implementation. At this point, \acp{LSM} may already apply security checks. The \ac{TCP} implementation segments data, maintains connection state, enforces congestion-control behavior, and enqueues \texttt{sk\_buff} structures in the socket write queue. The \ac{UDP} implementation builds datagrams with less connection state and less protocol machinery \cite{stephan2024packetpath}.
After transport-layer processing, the packet enters the \ac{IP} output path. Linux determines the route, often by consulting the \ac{FIB}, and builds the \ac{IP} header. \texttt{Netfilter} can inspect locally generated traffic at \texttt{LOCAL\_OUT} and later at \texttt{POST\_ROUTING}. If the destination is on an Ethernet network, the neighbor subsystem resolves the next-hop \ac{MAC} address, for example through \ac{ARP}. Then the Ethernet header is prepared and the packet is passed to the device transmission path \cite{stephan2024packetpath}.
For both locally generated and forwarded packets, the final transmission path goes through the network device queueing layer. Linux calls \texttt{dev\_queue\_xmit()}, where queueing disciplines can schedule, delay, classify, or drop packets. \texttt{tc} egress programs can also run at this stage. Afterwards, the driver transmission function, commonly exposed as \texttt{ndo\_start\_xmit}, places the packet into the transmit ring of the \ac{NIC}. The packet buffer is mapped for \ac{DMA}, and the hardware transmits the frame onto the physical medium \cite{stephan2024packetpath}.
For bridged packets, the local socket and transport-layer construction steps are skipped. The packet already exists as an Ethernet frame. After the bridge has selected an output port and the frame has passed the relevant bridge filtering hooks, the packet enters the output device path and is eventually queued for transmission on the selected interface. Consequently, \texttt{tc} egress and device-level queueing remain relevant even for purely bridged traffic.
\subsection{Programmable Hook Points}
Linux provides several hook points that allow packet processing to be extended without modifying the kernel source code. \ac{eBPF}, the successor of \ac{BPF}, is one of the main mechanisms for this \cite{man7tcbpf}. It allows user-supplied programs to be loaded into the kernel and executed at designated hooks after verification by the kernel \cite{gbadamosi2024ebpfruntime}. The verifier is intended to ensure that programs cannot corrupt kernel memory or run without bounds, while just-in-time compilation can provide efficient execution \cite{man7tcbpf}.
\texttt{Netfilter} and \texttt{nftables} provide another programmable processing layer. The \texttt{nftables} hook model distinguishes packet families, hook names, chain types, and priorities. Locally delivered packets pass through \texttt{prerouting} and \texttt{input}; forwarded routed packets pass through \texttt{prerouting}, \texttt{forward}, and \texttt{postrouting}; locally generated packets pass through \texttt{output} and \texttt{postrouting}. Within a hook, priorities determine the order in which \texttt{nftables} chains and internal \texttt{netfilter} operations run \cite{nftableshooks}.
The earliest hook point considered here is \ac{XDP}. Native \ac{XDP} programs are executed in the driver receive path before the normal \texttt{sk\_buff} is allocated \cite{hoilandjorgensen2018xdp}. This position allows very early pass, drop, transmit, and redirect decisions \cite{hoilandjorgensen2018xdp}. Because of this position, \ac{XDP} is suitable for high packet-rate processing \cite{scholz2018ebpfpacketfiltering}. However, because the packet has not yet entered the regular \texttt{sk\_buff}-based networking stack, normal \texttt{sk\_buff} metadata is not available in native \ac{XDP} mode.
After an \texttt{sk\_buff} exists, \texttt{tc} ingress and egress programs can process packets as \ac{eBPF} classifiers \cite{man7tcbpf}. The ingress side is reached shortly after the packet enters the receive path, while the egress side is reached after routing or bridge forwarding has selected an output interface \cite{stephan2024packetpath}. Since these programs operate on an \texttt{\_\_sk\_buff} context, they can inspect packet bytes and use metadata such as \texttt{skb->mark} \cite{man7tcbpf}. This makes \texttt{tc}/\ac{eBPF} useful for low-overhead telemetry and packet correlation without changing the frame transmitted on the wire.
For bridged traffic, \texttt{nftables} \texttt{bridge} hooks provide the main verdict mechanism. Rules in the \texttt{bridge} family are evaluated in the bridge path and can therefore affect Ethernet frames that are forwarded between bridge ports without entering the routed \ac{IP} path \cite{nftablesbridgefiltering}. In particular, \texttt{bridge}-family rules can be attached before or after the \ac{FDB} decision \cite{nftablesbridgefiltering}. They can be used to accept, drop, or redirect frames at Layer 2 \cite{westphal2016bridgefiltering}.
For passive raw capture, Linux provides packet sockets through \texttt{AF\_PACKET}. Packet sockets are used to receive or send raw packets at the device-driver level and can be bound to a specific interface \cite{man7packet}. This makes them suitable for Layer-2 observation of Ethernet frames. In the context of a forwarding bridge, such capture is conceptually separate from the bridge forwarding decision, because observing a packet through a packet socket does not itself define the packet's forwarding verdict.
Lastly, \texttt{tracepoint} hooks expose selected kernel events to tracing tools and \ac{eBPF} programs \cite{linuxkerneltracepointsdocs}. They are useful for events that are difficult to infer from raw packet captures alone, for example packet free or drop paths. In such cases, \texttt{tracepoint}-based telemetry can complement ingress and egress observations by providing metadata about what happened to an \texttt{sk\_buff} inside the kernel \cite{gbadamosi2024ebpfruntime}.
\ac{NFQUEUE} is built on top of \texttt{netfilter}. A rule can queue a packet to user space, where an application inspects the packet and returns a verdict such as accept, drop, or modified accept. This is more flexible than a purely in-kernel rule, but it also introduces user-kernel transfer overhead and makes packet latency depend on the user-space application. Therefore, \ac{NFQUEUE} is suitable for programmable manipulation, while early in-kernel hooks are better suited for low-overhead telemetry or simple filtering.
For the present thesis, these hook points explain the structure of the developed system. Raw packet capture observes frame contents, \texttt{tc}/\ac{eBPF} telemetry observes kernel metadata on ingress and egress, \texttt{nftables} \texttt{bridge} rules can decide the fate of bridged packets, and packet marks can connect observations from different stages of the same kernel path. Since a single Ethernet frame can be captured, cloned, forwarded, marked, and later observed again on another interface, reliable correlation requires an explicit packet identity or a stable reconstruction from packet fields.