<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mohamed Zrouga</title>
    <description>The latest articles on DEV Community by Mohamed Zrouga (@zrouga).</description>
    <link>https://dev.to/zrouga</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2175334%2Fe47a09a0-b4cc-4518-9873-52b431dd2bc1.jpeg</url>
      <title>DEV Community: Mohamed Zrouga</title>
      <link>https://dev.to/zrouga</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zrouga"/>
    <language>en</language>
    <item>
      <title>Meet Orion-Belt, Go ZeroTrust Bastion</title>
      <dc:creator>Mohamed Zrouga</dc:creator>
      <pubDate>Thu, 01 Jan 2026 20:46:39 +0000</pubDate>
      <link>https://dev.to/zrouga/meet-orion-belt-go-zerotrust-bastion-clp</link>
      <guid>https://dev.to/zrouga/meet-orion-belt-go-zerotrust-bastion-clp</guid>
      <description>&lt;p&gt;Stop opening Port 22 to the world. 🛑&lt;/p&gt;

&lt;p&gt;In the world of infrastructure, we’ve long accepted a "security tax." If you want your servers to be accessible, you either open holes in your firewall, maintain a complex VPN, or pay thousands for enterprise PAM (Privileged Access Management) tools. &lt;/p&gt;

&lt;p&gt;I felt there was a massive gap for a lightweight, developer-centric tool that follows &lt;strong&gt;Zero Trust&lt;/strong&gt; principles without the enterprise bloat. That’s why I built &lt;strong&gt;Orion-Belt&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Orion-Belt in Action
&lt;/h2&gt;

&lt;p&gt;Seeing is believing. Here is a quick look at &lt;code&gt;osh&lt;/code&gt; (the Orion-Belt SSH client) connecting to a machine that has &lt;strong&gt;zero inbound ports open&lt;/strong&gt;, while the gateway handles the heavy lifting of authentication and recording.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F74j5jjjdcyk6w7jq2wn6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F74j5jjjdcyk6w7jq2wn6.gif" alt="Orion-Belt in Action" width="1200" height="415"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The "Security Tax" of Traditional Access
&lt;/h2&gt;

&lt;p&gt;Most teams handle remote server access in one of three ways, and all of them have a "catch":&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Static SSH Keys:&lt;/strong&gt; Great until a laptop is stolen or an employee leaves. Auditing "who did what" is nearly impossible.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The "Jump Box" (Bastion):&lt;/strong&gt; A single point of failure. If your bastion is compromised, your whole network is exposed.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;VPNs:&lt;/strong&gt; They give "flat" network access. Once a user is on the VPN, they can often see everything, violating the &lt;strong&gt;Principle of Least Privilege&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I wanted something that felt like a modern SaaS (like Teleport or Boundary) but remained &lt;strong&gt;self-hosted, open-source, and dead simple.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Feature Comparison: Why Orion-Belt?
&lt;/h2&gt;

&lt;p&gt;How does Orion-Belt stack up against the status quo?&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Orion-Belt (Open Source)&lt;/th&gt;
&lt;th&gt;Traditional SSH/VPN&lt;/th&gt;
&lt;th&gt;Enterprise Gateways&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Inbound Firewall Rules&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;❌ No (Reverse Tunnel)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;✅ Yes (Port 22/VPN)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;❌ No (Agent/Tunnel)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Session Recording&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;✅ Yes (Built-in)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ No (Hard to config)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;✅ Yes (Built-in)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Access Control&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;ReBAC&lt;/strong&gt; (Fine-Grained)&lt;/td&gt;
&lt;td&gt;Coarse-Grained&lt;/td&gt;
&lt;td&gt;RBAC/ABAC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Temporary Access&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;✅ Yes (JIT Approval)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;✅ Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Protocol Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SSH, SCP&lt;/td&gt;
&lt;td&gt;SSH, SCP (VPN allows more)&lt;/td&gt;
&lt;td&gt;SSH, Kubernetes, Databases, HTTP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Free (Self-Hosted)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;$$$ High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Architecture&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lightweight Go Binary&lt;/td&gt;
&lt;td&gt;Standard Utilities&lt;/td&gt;
&lt;td&gt;Complex Microservices&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  How it Works (Under the Hood)
&lt;/h2&gt;

&lt;p&gt;Orion-Belt is built on a &lt;strong&gt;Reverse SSH Tunnel&lt;/strong&gt; architecture. Instead of you reaching &lt;em&gt;into&lt;/em&gt; your private network, your servers reach &lt;em&gt;out&lt;/em&gt; to the Orion-Belt gateway.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;The Agent:&lt;/strong&gt; A small Go binary runs on your target VMs. It creates an outbound connection to your Orion-Belt server. &lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The Gateway:&lt;/strong&gt; The "Brain." It handles authentication, ReBAC (Relationship-Based Access Control), and session recording.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The Client (&lt;code&gt;osh&lt;/code&gt; / &lt;code&gt;ocp&lt;/code&gt;):&lt;/strong&gt; CLI tools that feel like standard SSH/SCP but verify permissions with the gateway’s API first.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because the connection is outbound from the server to the gateway, &lt;strong&gt;you can keep Port 22 closed.&lt;/strong&gt; This effectively hides your infrastructure from automated bot scans and 0-day SSH exploits.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Features for Modern Teams
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. ReBAC (Relationship-Based Access Control)
&lt;/h3&gt;

&lt;p&gt;Orion-Belt checks the &lt;em&gt;relationship&lt;/em&gt; between the user and the resource. This allows for fine-grained permissions that scale as your team grows.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Session DVR-Style Replay
&lt;/h3&gt;

&lt;p&gt;Compliance (SOC2/HIPAA) requires seeing what happened during a session. Orion-Belt records every keystroke at the gateway level. You can replay the entire session later to see exactly what commands were run.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. JIT (Just-In-Time) Temporary Access
&lt;/h3&gt;

&lt;p&gt;Need a developer to debug a production issue for one hour?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;osh &lt;span class="nt"&gt;--request-access&lt;/span&gt; prod-db-01 &lt;span class="nt"&gt;--duration&lt;/span&gt; 1h &lt;span class="nt"&gt;--reason&lt;/span&gt; &lt;span class="s2"&gt;"Investigating latency"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Admins get a notification, approve the request, and the access automatically expires. No "orphaned" keys left behind.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Client &lt;span class="o"&gt;(&lt;/span&gt;osh/ocp&lt;span class="o"&gt;)&lt;/span&gt;
      │
      ▼
Orion-Belt Gateway Server &lt;span class="o"&gt;(&lt;/span&gt;ReBAC + Session Recording&lt;span class="o"&gt;)&lt;/span&gt;
      │
      ▼ &lt;span class="o"&gt;(&lt;/span&gt;Reverse SSH Tunnel&lt;span class="o"&gt;)&lt;/span&gt;
Agent &lt;span class="o"&gt;(&lt;/span&gt;on your locked-down servers&lt;span class="o"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Build from source:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/zrougamed/orion-belt.git
&lt;span class="nb"&gt;cd &lt;/span&gt;orion-belt &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; make build

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Start the Server:&lt;/strong&gt;&lt;br&gt;
The server acts as your central hub. It uses PostgreSQL to store sessions and permissions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Deploy the Agent:&lt;/strong&gt;&lt;br&gt;
Drop the agent binary on any server behind a firewall. Once it connects to the gateway, that server is accessible via &lt;code&gt;osh&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  I need your feedback!
&lt;/h2&gt;

&lt;p&gt;Orion-Belt is currently in &lt;strong&gt;Alpha&lt;/strong&gt;. It’s functional and stable, but I’m looking for early adopters to help shape the roadmap.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does this architecture fit your current workflow?&lt;/li&gt;
&lt;li&gt;What notification plugins would you like to see (Slack, Discord, Email)?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check out the repo, leave a ⭐ if you like the concept, and let's discuss in the comments!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/zrougamed/orion-belt" rel="noopener noreferrer"&gt;https://github.com/zrougamed/orion-belt&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;br&gt;
Infrastructure access doesn't need to be a choice between "easy" and "secure." By combining Go's performance with a Zero-Trust architecture, Orion-Belt makes high-end security accessible to everyone.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>security</category>
      <category>devops</category>
      <category>go</category>
    </item>
    <item>
      <title>Building a Security Test Lab with QEMU: From Zero to Network Monitoring</title>
      <dc:creator>Mohamed Zrouga</dc:creator>
      <pubDate>Fri, 26 Dec 2025 23:47:51 +0000</pubDate>
      <link>https://dev.to/zrouga/building-a-security-test-lab-with-qemu-from-zero-to-network-monitoring-4onm</link>
      <guid>https://dev.to/zrouga/building-a-security-test-lab-with-qemu-from-zero-to-network-monitoring-4onm</guid>
      <description>&lt;h2&gt;
  
  
  Why QEMU for Your Test Lab?
&lt;/h2&gt;

&lt;p&gt;As software engineers and security professionals, we constantly need isolated environments to test new tools, experiment with network configurations, or validate security measures before production deployment. While solutions like VirtualBox and VMware are popular, QEMU offers something special: lightweight, scriptable, headless operation perfect for automation and CI/CD pipelines.&lt;/p&gt;

&lt;p&gt;In this guide, I'll walk you through building a complete QEMU-based test lab focused on network security and infrastructure testing. By the end, you'll have a reproducible environment for testing firewalls, monitoring tools, and distributed systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We'll Build
&lt;/h2&gt;

&lt;p&gt;We're creating a multi-VM test lab that simulates a realistic network environment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gateway VM&lt;/strong&gt;: Acts as router/firewall &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application VM&lt;/strong&gt;: Simulates production workloads&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attacker VM&lt;/strong&gt;: For security testing and validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This setup mirrors real-world scenarios where you need to test network policies, intrusion detection, or packet filtering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before we start, ensure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Linux host (Ubuntu/Debian in examples, but adaptable to any distro)&lt;/li&gt;
&lt;li&gt;At least 8GB RAM and 20GB free disk space&lt;/li&gt;
&lt;li&gt;Basic command-line familiarity&lt;/li&gt;
&lt;li&gt;Sudo access for network configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Installing QEMU
&lt;/h2&gt;

&lt;p&gt;First, let's get QEMU installed with all necessary components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Ubuntu/Debian&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;qemu-kvm qemu-utils libvirt-daemon-system virtinst bridge-utils

&lt;span class="c"&gt;# Verify installation&lt;/span&gt;
qemu-system-x86_64 &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For other distributions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Fedora/RHEL&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install &lt;/span&gt;qemu-kvm qemu-img libvirt virt-install

&lt;span class="c"&gt;# Arch&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;pacman &lt;span class="nt"&gt;-S&lt;/span&gt; qemu libvirt virt-manager
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add your user to necessary groups to avoid constant sudo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; libvirt,kvm &lt;span class="nv"&gt;$USER&lt;/span&gt;
&lt;span class="c"&gt;# Log out and back in for changes to take effect&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Creating Your First VM - The Gateway
&lt;/h2&gt;

&lt;p&gt;Let's start with the gateway VM, which will be our network's control point.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Disk Image
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a working directory&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/qemu-lab/images
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/qemu-lab

&lt;span class="c"&gt;# Create a 20GB disk image (qcow2 format for snapshots)&lt;/span&gt;
qemu-img create &lt;span class="nt"&gt;-f&lt;/span&gt; qcow2 images/gateway.qcow2 20G
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why qcow2? It supports snapshots, copy-on-write, and compression - essential for test environments where you'll want to reset frequently.&lt;/p&gt;

&lt;h3&gt;
  
  
  Download a Minimal OS
&lt;/h3&gt;

&lt;p&gt;For security testing, I recommend Alpine Linux (lightweight) or Debian netinst:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Alpine Linux (very lightweight, boots in seconds)&lt;/span&gt;
wget https://dl-cdn.alpinelinux.org/alpine/v3.23/releases/x86_64/alpine-virt-3.23.0-x86_64.iso &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-O&lt;/span&gt; images/alpine.iso

&lt;span class="c"&gt;# Or Debian if you prefer more familiar tools&lt;/span&gt;
&lt;span class="c"&gt;# wget https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-13.2.0-amd64-netinst.iso \&lt;/span&gt;
&lt;span class="c"&gt;#   -O images/debian.iso&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  First Boot and Installation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;qemu-system-x86_64 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-name&lt;/span&gt; gateway &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-m&lt;/span&gt; 1024 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-smp&lt;/span&gt; 2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-hda&lt;/span&gt; images/gateway.qcow2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-cdrom&lt;/span&gt; images/alpine.iso &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-boot&lt;/span&gt; d &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-enable-kvm&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-nic&lt;/span&gt; user,model&lt;span class="o"&gt;=&lt;/span&gt;virtio &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-nographic&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Flag breakdown:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-name gateway&lt;/code&gt;: Identifies your VM&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-m 1024&lt;/code&gt;: 1GB RAM (adjust based on your needs)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-smp 2&lt;/code&gt;: 2 CPU cores&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-hda&lt;/code&gt;: Primary disk&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-cdrom&lt;/code&gt;: Installation media&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-boot d&lt;/code&gt;: Boot from CD-ROM first&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-enable-kvm&lt;/code&gt;: Hardware acceleration (crucial for performance)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-nic user&lt;/code&gt;: Simple NAT networking for installation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-nographic&lt;/code&gt;: Console mode (no GUI needed)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Quick Alpine Installation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Once booted, login as root (no password)&lt;/span&gt;
setup-alpine

&lt;span class="c"&gt;# Follow prompts:&lt;/span&gt;
&lt;span class="c"&gt;# - Keyboard: us&lt;/span&gt;
&lt;span class="c"&gt;# - Hostname: gateway&lt;/span&gt;
&lt;span class="c"&gt;# - Network: eth0, dhcp&lt;/span&gt;
&lt;span class="c"&gt;# - Password: (set a strong one)&lt;/span&gt;
&lt;span class="c"&gt;# - Timezone: your timezone&lt;/span&gt;
&lt;span class="c"&gt;# - Disk: sda, sys (use entire disk)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installation completes, power off the VM (type &lt;code&gt;poweroff&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Setting Up Advanced Networking
&lt;/h2&gt;

&lt;p&gt;This is where QEMU shines for security testing. We'll create an isolated network that simulates real infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Network Configuration Script
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create scripts directory&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/qemu-lab/scripts

&lt;span class="c"&gt;# Network setup script&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/qemu-lab/scripts/setup-network.sh &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
#!/bin/bash

# Create an isolated bridge for our test lab
sudo ip link add name br-testlab type bridge
sudo ip addr add 10.0.100.1/24 dev br-testlab
sudo ip link set br-testlab up

# Enable IP forwarding (so gateway can route)
sudo sysctl -w net.ipv4.ip_forward=1

# Create TAP interfaces for VMs
for i in 0 1 2; do
  sudo ip tuntap add tap&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="sh"&gt; mode tap user &lt;/span&gt;&lt;span class="nv"&gt;$USER&lt;/span&gt;&lt;span class="sh"&gt;
  sudo ip link set tap&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="sh"&gt; master br-testlab
  sudo ip link set tap&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="sh"&gt; up
done

echo "Test lab network ready: 10.0.100.0/24 on br-testlab"
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x ~/qemu-lab/scripts/setup-network.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you will end up with this network topology&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.0.100.1/24 Network
       |
   [Bridge](br-testlab)
    /   |    \
  TAP0 TAP1 TAP2
  VM1  VM2   VM3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Characteristics:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;VMs are on SAME subnet as host&lt;/li&gt;
&lt;li&gt;VMs are "visible" to external network&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Network Teardown Script
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/qemu-lab/scripts/teardown-network.sh &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
#!/bin/bash

# Remove TAP interfaces
for i in 0 1 2; do
  sudo ip link set tap&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="sh"&gt; down 2&amp;gt;/dev/null
  sudo ip link delete tap&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="sh"&gt; 2&amp;gt;/dev/null
done

# Remove bridge
sudo ip link set br-testlab down 2&amp;gt;/dev/null
sudo ip link delete br-testlab 2&amp;gt;/dev/null

echo "Test lab network removed"
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x ~/qemu-lab/scripts/teardown-network.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/qemu-lab/scripts/setup-network.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Creating VM Launch Scripts
&lt;/h2&gt;

&lt;p&gt;Rather than typing long QEMU commands, let's create reusable launch scripts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gateway VM Script
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/qemu-lab/scripts/run-gateway.sh &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
#!/bin/bash

qemu-system-x86_64 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -name gateway &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -m 1024 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -smp 2 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -hda ~/qemu-lab/images/gateway.qcow2 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -enable-kvm &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -netdev tap,id=net0,ifname=tap0,script=no,downscript=no &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -device virtio-net-pci,netdev=net0,mac=52:54:00:12:34:00 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -netdev user,id=net1 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -device virtio-net-pci,netdev=net1,mac=52:54:00:12:34:01 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -nographic &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -serial mon:stdio
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x ~/qemu-lab/scripts/run-gateway.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gateway has TWO network interfaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;net0&lt;/code&gt;: Connected to internal test network (10.0.100.0/24)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;net1&lt;/code&gt;: NAT to internet for updates&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Quick Clone Function for Additional VMs
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create application VM from gateway template&lt;/span&gt;
qemu-img create &lt;span class="nt"&gt;-f&lt;/span&gt; qcow2 &lt;span class="nt"&gt;-b&lt;/span&gt; images/gateway.qcow2 &lt;span class="nt"&gt;-F&lt;/span&gt; qcow2 images/app.qcow2

&lt;span class="c"&gt;# Create attacker VM&lt;/span&gt;
qemu-img create &lt;span class="nt"&gt;-f&lt;/span&gt; qcow2 &lt;span class="nt"&gt;-b&lt;/span&gt; images/gateway.qcow2 &lt;span class="nt"&gt;-F&lt;/span&gt; qcow2 images/attacker.qcow2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are &lt;strong&gt;backing images&lt;/strong&gt; - they only store differences from the base, saving massive disk space.&lt;/p&gt;

&lt;h3&gt;
  
  
  Application VM Script
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/qemu-lab/scripts/run-app.sh &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
#!/bin/bash

qemu-system-x86_64 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -name app-server &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -m 2048 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -smp 2 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -hda ~/qemu-lab/images/app.qcow2 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -enable-kvm &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -netdev tap,id=net0,ifname=tap1,script=no,downscript=no &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -device virtio-net-pci,netdev=net0,mac=52:54:00:12:34:10 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -nographic &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -serial mon:stdio
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x ~/qemu-lab/scripts/run-app.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Attacker VM Script
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/qemu-lab/scripts/run-attacker.sh &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
#!/bin/bash

qemu-system-x86_64 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -name attacker &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -m 1024 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -smp 2 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -hda ~/qemu-lab/images/attacker.qcow2 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -enable-kvm &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -netdev tap,id=net0,ifname=tap2,script=no,downscript=no &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -device virtio-net-pci,netdev=net0,mac=52:54:00:12:34:20 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -nographic &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="sh"&gt;
  -serial mon:stdio
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x ~/qemu-lab/scripts/run-attacker.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Network Configuration Inside VMs
&lt;/h2&gt;

&lt;p&gt;Start each VM and configure networking:&lt;/p&gt;

&lt;h3&gt;
  
  
  Gateway VM (10.0.100.1)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start gateway&lt;/span&gt;
~/qemu-lab/scripts/run-gateway.sh

&lt;span class="c"&gt;# Inside VM - configure interfaces&lt;/span&gt;
&lt;span class="c"&gt;# For Alpine Linux:&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /etc/network/interfaces &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
    address 10.0.100.1
    netmask 255.255.255.0

auto eth1
iface eth1 inet dhcp
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="c"&gt;# Restart networking&lt;/span&gt;
rc-service networking restart

&lt;span class="c"&gt;# Enable forwarding permanently&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'net.ipv4.ip_forward = 1'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /etc/sysctl.conf
sysctl &lt;span class="nt"&gt;-p&lt;/span&gt;

&lt;span class="c"&gt;# Setup basic NAT (so internal VMs can reach internet via gateway)&lt;/span&gt;
apk add iptables
iptables &lt;span class="nt"&gt;-t&lt;/span&gt; nat &lt;span class="nt"&gt;-A&lt;/span&gt; POSTROUTING &lt;span class="nt"&gt;-o&lt;/span&gt; eth1 &lt;span class="nt"&gt;-j&lt;/span&gt; MASQUERADE
iptables &lt;span class="nt"&gt;-A&lt;/span&gt; FORWARD &lt;span class="nt"&gt;-i&lt;/span&gt; eth0 &lt;span class="nt"&gt;-o&lt;/span&gt; eth1 &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT
iptables &lt;span class="nt"&gt;-A&lt;/span&gt; FORWARD &lt;span class="nt"&gt;-i&lt;/span&gt; eth1 &lt;span class="nt"&gt;-o&lt;/span&gt; eth0 &lt;span class="nt"&gt;-m&lt;/span&gt; state &lt;span class="nt"&gt;--state&lt;/span&gt; RELATED,ESTABLISHED &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT

&lt;span class="c"&gt;# Save iptables rules&lt;/span&gt;
rc-update add iptables
/etc/init.d/iptables save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Application VM (10.0.100.10)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Configure static IP&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /etc/network/interfaces &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
    address 10.0.100.10
    netmask 255.255.255.0
    gateway 10.0.100.1
    dns-nameservers 8.8.8.8
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;rc-service networking restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Attacker VM (10.0.100.20)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Configure static IP&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /etc/network/interfaces &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
    address 10.0.100.20
    netmask 255.255.255.0
    gateway 10.0.100.1
    dns-nameservers 8.8.8.8
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;rc-service networking restart

&lt;span class="c"&gt;# Install security testing tools&lt;/span&gt;
apk add nmap tcpdump hping3 netcat-openbsd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Snapshots for Quick Resets
&lt;/h2&gt;

&lt;p&gt;One of QEMU's killer features - instant rollback:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a "clean state" snapshot for each VM&lt;/span&gt;
qemu-img snapshot &lt;span class="nt"&gt;-c&lt;/span&gt; clean-install images/gateway.qcow2
qemu-img snapshot &lt;span class="nt"&gt;-c&lt;/span&gt; clean-install images/app.qcow2
qemu-img snapshot &lt;span class="nt"&gt;-c&lt;/span&gt; clean-install images/attacker.qcow2

&lt;span class="c"&gt;# After testing, rollback to clean state&lt;/span&gt;
qemu-img snapshot &lt;span class="nt"&gt;-a&lt;/span&gt; clean-install images/gateway.qcow2

&lt;span class="c"&gt;# List all snapshots&lt;/span&gt;
qemu-img snapshot &lt;span class="nt"&gt;-l&lt;/span&gt; images/gateway.qcow2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 7: Practical Use Cases
&lt;/h2&gt;

&lt;p&gt;Now your lab is ready! Here are some real-world scenarios:&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing Network Monitoring Tools
&lt;/h3&gt;

&lt;p&gt;On the gateway VM, install your monitoring solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Example: tcpdump for packet analysis&lt;/span&gt;
apk add tcpdump

&lt;span class="c"&gt;# Capture traffic between app and attacker&lt;/span&gt;
tcpdump &lt;span class="nt"&gt;-i&lt;/span&gt; eth0 &lt;span class="nt"&gt;-w&lt;/span&gt; /tmp/capture.pcap

&lt;span class="c"&gt;# Or install eBPF-based tools for advanced monitoring&lt;/span&gt;
&lt;span class="c"&gt;# (Great for testing tools like Cilium, Falco, or custom eBPF monitors like Cerberus)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Simulating Attack Scenarios
&lt;/h3&gt;

&lt;p&gt;From attacker VM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Port scan the application&lt;/span&gt;
nmap &lt;span class="nt"&gt;-sV&lt;/span&gt; 10.0.100.10

&lt;span class="c"&gt;# Test firewall rules&lt;/span&gt;
hping3 &lt;span class="nt"&gt;-S&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 80 10.0.100.10

&lt;span class="c"&gt;# Monitor on gateway to see what's blocked&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing Firewall Rules
&lt;/h3&gt;

&lt;p&gt;On gateway, add restrictive rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Block all traffic from attacker to app&lt;/span&gt;
iptables &lt;span class="nt"&gt;-I&lt;/span&gt; FORWARD &lt;span class="nt"&gt;-s&lt;/span&gt; 10.0.100.20 &lt;span class="nt"&gt;-d&lt;/span&gt; 10.0.100.10 &lt;span class="nt"&gt;-j&lt;/span&gt; DROP

&lt;span class="c"&gt;# Allow only SSH&lt;/span&gt;
iptables &lt;span class="nt"&gt;-I&lt;/span&gt; FORWARD &lt;span class="nt"&gt;-s&lt;/span&gt; 10.0.100.20 &lt;span class="nt"&gt;-d&lt;/span&gt; 10.0.100.10 &lt;span class="nt"&gt;-p&lt;/span&gt; tcp &lt;span class="nt"&gt;--dport&lt;/span&gt; 22 &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Container Testing
&lt;/h3&gt;

&lt;p&gt;Install Docker on the app VM to test container networking and security policies in isolation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8: Automation and Management
&lt;/h2&gt;

&lt;p&gt;Create a master control script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/qemu-lab/manage-lab.sh &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
#!/bin/bash

case "&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="sh"&gt;" in
  start)
    ./scripts/setup-network.sh
    echo "Starting VMs in tmux sessions..."
    tmux new-session -d -s gateway './scripts/run-gateway.sh'
    tmux new-session -d -s app './scripts/run-app.sh'
    tmux new-session -d -s attacker './scripts/run-attacker.sh'
    echo "Lab started. Attach with: tmux attach -t &amp;lt;gateway|app|attacker&amp;gt;"
    ;;
  stop)
    echo "Stopping all VMs..."
    tmux kill-session -t gateway 2&amp;gt;/dev/null
    tmux kill-session -t app 2&amp;gt;/dev/null
    tmux kill-session -t attacker 2&amp;gt;/dev/null
    ./scripts/teardown-network.sh
    ;;
  reset)
    echo "Resetting all VMs to clean snapshot..."
    qemu-img snapshot -a clean-install images/gateway.qcow2
    qemu-img snapshot -a clean-install images/app.qcow2
    qemu-img snapshot -a clean-install images/attacker.qcow2
    echo "Reset complete"
    ;;
  *)
    echo "Usage: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="sh"&gt; {start|stop|reset}"
    exit 1
    ;;
esac
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x ~/qemu-lab/manage-lab.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start entire lab&lt;/span&gt;
./manage-lab.sh start

&lt;span class="c"&gt;# Access any VM&lt;/span&gt;
tmux attach &lt;span class="nt"&gt;-t&lt;/span&gt; gateway

&lt;span class="c"&gt;# Reset everything to clean state&lt;/span&gt;
./manage-lab.sh reset

&lt;span class="c"&gt;# Shut down cleanly&lt;/span&gt;
./manage-lab.sh stop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Performance Tips
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Always use KVM acceleration&lt;/strong&gt; (&lt;code&gt;-enable-kvm&lt;/code&gt;) - it's 10-20x faster than emulation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Allocate appropriate resources&lt;/strong&gt; - Don't over-provision RAM&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use virtio drivers&lt;/strong&gt; - Much faster than emulated hardware&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;qcow2 for flexibility, raw for performance&lt;/strong&gt; - Use raw images if speed is critical&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CPU pinning for consistency&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nt"&gt;-smp&lt;/span&gt; 2,sockets&lt;span class="o"&gt;=&lt;/span&gt;1,cores&lt;span class="o"&gt;=&lt;/span&gt;2,threads&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Troubleshooting Common Issues
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;VM won't start with KVM error:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check if KVM is available&lt;/span&gt;
lsmod | &lt;span class="nb"&gt;grep &lt;/span&gt;kvm
&lt;span class="c"&gt;# If not, enable in BIOS (Intel VT-x or AMD-V)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Network not working:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Verify TAP interfaces are up&lt;/span&gt;
ip &lt;span class="nb"&gt;link &lt;/span&gt;show | &lt;span class="nb"&gt;grep &lt;/span&gt;tap

&lt;span class="c"&gt;# Check bridge configuration&lt;/span&gt;
bridge &lt;span class="nb"&gt;link &lt;/span&gt;show br-testlab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cannot connect to VMs:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# From host, ping the bridge IP&lt;/span&gt;
ping 10.0.100.1

&lt;span class="c"&gt;# Check iptables isn't blocking&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Performance is slow:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Verify KVM is actually being used&lt;/span&gt;
ps aux | &lt;span class="nb"&gt;grep &lt;/span&gt;qemu | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; kvm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Next Steps and Advanced Topics
&lt;/h2&gt;

&lt;p&gt;Your test lab is now ready for serious work! Consider exploring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ansible automation&lt;/strong&gt; - Provision VMs automatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud-init integration&lt;/strong&gt; - Pre-configure VMs on first boot&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PXE boot testing&lt;/strong&gt; - Network installation scenarios&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-host clustering&lt;/strong&gt; - Test Kubernetes or Docker Swarm&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VPN testing&lt;/strong&gt; - Simulate site-to-site connections&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VLAN tagging&lt;/strong&gt; - Complex network segmentation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;QEMU provides a powerful, scriptable foundation for testing network security tools and infrastructure. Unlike heavyweight alternatives, it integrates seamlessly into CI/CD pipelines, supports headless operation, and gives you complete control over the network topology.&lt;/p&gt;

&lt;p&gt;The lab we built mirrors production environments while remaining completely isolated and reproducible. Use it to validate security tools, test infrastructure changes, or experiment with new technologies risk-free.&lt;/p&gt;

&lt;p&gt;All scripts and configurations from this guide are available in my GitHub &lt;a href="https://github.com/zrougamed/blog" rel="noopener noreferrer"&gt;https://github.com/zrougamed/blog&lt;/a&gt; .&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What will you test first in your new lab?&lt;/strong&gt; Drop a comment below!&lt;/p&gt;




&lt;p&gt;About the author: I'm a Senior Software Engineer at Deltaflare, where we work on the Phoenix Platform protecting Critical National Infrastructure across energy, water, and transport sectors. I use QEMU extensively for testing security tools and validating infrastructure changes before production deployment in CNI environments. You can find me at &lt;a href="https://zrouga.email" rel="noopener noreferrer"&gt;https://zrouga.email&lt;/a&gt; or check out my open-source work on GitHub.&lt;/p&gt;

</description>
      <category>qemu</category>
      <category>security</category>
      <category>devops</category>
      <category>networking</category>
    </item>
    <item>
      <title>Building a Real-Time Network Monitor with eBPF: Lessons from Cerberus</title>
      <dc:creator>Mohamed Zrouga</dc:creator>
      <pubDate>Sat, 20 Dec 2025 18:09:12 +0000</pubDate>
      <link>https://dev.to/zrouga/building-a-real-time-network-monitor-with-ebpf-lessons-from-cerberus-mm</link>
      <guid>https://dev.to/zrouga/building-a-real-time-network-monitor-with-ebpf-lessons-from-cerberus-mm</guid>
      <description>&lt;p&gt;As a platform engineer working with critical infrastructure, I needed deep visibility into network behavior without the overhead of traditional packet capture tools. The result? &lt;a href="https://github.com/zrougamed/cerberus" rel="noopener noreferrer"&gt;Cerberus&lt;/a&gt; - an eBPF-based network monitor that processes packets at the kernel level with near-zero overhead.&lt;/p&gt;

&lt;p&gt;This post walks through the architecture, challenges, and lessons learned from building a production-grade network monitoring tool using eBPF and Go.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdwrfb9c0zaiprgquvsav.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdwrfb9c0zaiprgquvsav.png" alt="Cerberus in Action" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why eBPF for Network Monitoring?
&lt;/h2&gt;

&lt;p&gt;Traditional network monitoring tools like &lt;code&gt;tcpdump&lt;/code&gt; and &lt;code&gt;Wireshark&lt;/code&gt; are powerful but come with drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Context switches&lt;/strong&gt;: Every packet copies data from kernel to user space&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance overhead&lt;/strong&gt;: Processing in user space is slower&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt;: Full packet capture requires elevated privileges everywhere&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: High-traffic networks can overwhelm traditional tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;eBPF (Extended Berkeley Packet Filter) solves these by running sandboxed programs directly in the Linux kernel, allowing you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Filter and process packets at line rate&lt;/li&gt;
&lt;li&gt;Extract only the data you need (no full packet copies)&lt;/li&gt;
&lt;li&gt;Aggregate statistics in kernel space&lt;/li&gt;
&lt;li&gt;Minimize context switches with ring buffers&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

&lt;p&gt;Cerberus uses a two-layer architecture:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyn4bh5ae5d2slrih7ay3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyn4bh5ae5d2slrih7ay3.png" alt="Cerberus user space and Kernel space" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The eBPF Program: Kernel-Space Magic
&lt;/h2&gt;

&lt;p&gt;The heart of Cerberus is a TC (Traffic Control) classifier written in C that attaches to network interfaces. Here's what it does:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Packet Parsing at Line Rate
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;network_event&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;__u8&lt;/span&gt; &lt;span class="n"&gt;event_type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       &lt;span class="c1"&gt;// Event classification&lt;/span&gt;
    &lt;span class="n"&gt;__u8&lt;/span&gt; &lt;span class="n"&gt;src_mac&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;       &lt;span class="c1"&gt;// Source MAC&lt;/span&gt;
    &lt;span class="n"&gt;__u8&lt;/span&gt; &lt;span class="n"&gt;dst_mac&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;       &lt;span class="c1"&gt;// Destination MAC&lt;/span&gt;
    &lt;span class="n"&gt;__u32&lt;/span&gt; &lt;span class="n"&gt;src_ip&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;          &lt;span class="c1"&gt;// Source IP&lt;/span&gt;
    &lt;span class="n"&gt;__u32&lt;/span&gt; &lt;span class="n"&gt;dst_ip&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;          &lt;span class="c1"&gt;// Destination IP&lt;/span&gt;
    &lt;span class="n"&gt;__u16&lt;/span&gt; &lt;span class="n"&gt;src_port&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c1"&gt;// Source port&lt;/span&gt;
    &lt;span class="n"&gt;__u16&lt;/span&gt; &lt;span class="n"&gt;dst_port&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c1"&gt;// Destination port&lt;/span&gt;
    &lt;span class="n"&gt;__u8&lt;/span&gt; &lt;span class="n"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;         &lt;span class="c1"&gt;// IP protocol&lt;/span&gt;
    &lt;span class="n"&gt;__u8&lt;/span&gt; &lt;span class="n"&gt;tcp_flags&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c1"&gt;// TCP flags&lt;/span&gt;
    &lt;span class="n"&gt;__u16&lt;/span&gt; &lt;span class="n"&gt;arp_op&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;          &lt;span class="c1"&gt;// ARP operation&lt;/span&gt;
    &lt;span class="n"&gt;__u8&lt;/span&gt; &lt;span class="n"&gt;icmp_type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c1"&gt;// ICMP type&lt;/span&gt;
    &lt;span class="n"&gt;__u8&lt;/span&gt; &lt;span class="n"&gt;l7_payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;   &lt;span class="c1"&gt;// Layer 7 inspection data&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;__attribute__&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;packed&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Design Decision&lt;/strong&gt;: We only capture 75 bytes per event. This is enough for classification and L7 inspection without the overhead of full packet capture.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Multi-Protocol Detection
&lt;/h3&gt;

&lt;p&gt;The eBPF program identifies 7 different protocol types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Simplified version of the protocol detection logic&lt;/span&gt;
&lt;span class="n"&gt;SEC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tc"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;monitor_ingress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;__sk_buff&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;skb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;skb&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data_end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;skb&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data_end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ethhdr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;eth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;eth&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;data_end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;TC_ACT_OK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// ARP detection&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eth&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;h_proto&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;bpf_htons&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ETH_P_ARP&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;handle_arp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data_end&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// IP packet processing&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eth&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;h_proto&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;bpf_htons&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ETH_P_IP&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;iphdr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;eth&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;data_end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;TC_ACT_OK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;IPPROTO_TCP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;handle_tcp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data_end&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;IPPROTO_UDP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;handle_udp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data_end&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;IPPROTO_ICMP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;handle_icmp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data_end&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;TC_ACT_OK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Layer 7 Inspection
&lt;/h3&gt;

&lt;p&gt;Here's where it gets interesting. We extract application-layer data for DNS, HTTP, and TLS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// DNS query extraction&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;__always_inline&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;handle_dns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;__sk_buff&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;skb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                                       &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;udphdr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;udp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                       &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data_end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;dns_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;udp&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Copy up to 32 bytes of DNS payload&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dns_data&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;data_end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;bpf_probe_read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;l7_payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dns_data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EVENT_DNS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;bpf_ringbuf_submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;TC_ACT_OK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// HTTP detection (simplified)&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;__always_inline&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;handle_http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;__sk_buff&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;skb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                        &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;tcphdr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;tcp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                        &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data_end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;tcp&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Check for HTTP methods&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http_data&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;data_end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="n"&gt;bpf_probe_read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http_data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'G'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'E'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
            &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'T'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EVENT_HTTP&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;bpf_probe_read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;l7_payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http_data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;TC_ACT_OK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// TLS handshake detection&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;__always_inline&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;handle_tls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;__sk_buff&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;skb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                       &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;tcphdr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;tcp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                       &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data_end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;tls_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;tcp&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tls_data&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;data_end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;__u8&lt;/span&gt; &lt;span class="n"&gt;content_type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;bpf_probe_read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;content_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tls_data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// 0x16 = Handshake&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mh"&gt;0x16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EVENT_TLS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;bpf_probe_read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;l7_payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tls_data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;TC_ACT_OK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Challenge #1: The Verifier&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The eBPF verifier is strict. Every memory access must be bounds-checked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This will fail verification:&lt;/span&gt;
&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// ❌ No bounds check&lt;/span&gt;

&lt;span class="c1"&gt;// This passes:&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;data_end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// ✅ Verified safe&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  User-Space Processing: Go Application
&lt;/h2&gt;

&lt;p&gt;The Go application reads events from the ring buffer and performs higher-level analysis:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Ring Buffer Polling
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;NetworkMonitor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;pollEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InitRingBuf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"events"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eventsChannel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;rb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;rb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Poll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;300&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// 300ms timeout&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eventsChannel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;processEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Smart Deduplication with LRU Cache
&lt;/h3&gt;

&lt;p&gt;To avoid alert fatigue, we only show new traffic patterns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;NetworkMonitor&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;deviceCache&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;lru&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cache&lt;/span&gt;        &lt;span class="c"&gt;// Device tracking&lt;/span&gt;
    &lt;span class="n"&gt;patternCache&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;lru&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cache&lt;/span&gt;        &lt;span class="c"&gt;// Unique communication patterns&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;           &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buntdb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;        &lt;span class="c"&gt;// Persistent storage&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;NetworkMonitor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;processEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;parseNetworkEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Track device&lt;/span&gt;
    &lt;span class="n"&gt;deviceKey&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SrcMAC&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deviceCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deviceKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;announceNewDevice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deviceCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deviceKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Track pattern (first occurrence only)&lt;/span&gt;
    &lt;span class="n"&gt;patternKey&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s:%s:%d:%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SrcMAC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DstIP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DstPort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;patternCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;patternKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;printTrafficPattern&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;patternCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;patternKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Update statistics&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;updateStats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Layer 7 Parsing in User Space
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;parseL7Payload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;NetworkEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;EVENT_DNS&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;parseDNSQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;L7Payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;EVENT_HTTP&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;parseHTTPRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;L7Payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;EVENT_TLS&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"TLS"&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;parseDNSQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Skip DNS header (12 bytes)&lt;/span&gt;
    &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Performance Optimizations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Zero-Copy with Ring Buffers
&lt;/h3&gt;

&lt;p&gt;Ring buffers allow the kernel to write directly to memory shared with user space:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// No data copying - just reading shared memory&lt;/span&gt;
&lt;span class="n"&gt;rb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Poll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;300&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Batch Database Writes
&lt;/h3&gt;

&lt;p&gt;Instead of writing every event to disk, we batch them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;NetworkMonitor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;persistStats&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ticker&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewTicker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;ticker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;ticker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buntdb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stats&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deviceStats&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. LRU Cache Tuning
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Balance memory vs. accuracy&lt;/span&gt;
&lt;span class="n"&gt;deviceCache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;lru&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c"&gt;// Track 1000 devices&lt;/span&gt;
&lt;span class="n"&gt;patternCache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;lru&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Track 10k patterns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real-World Output
&lt;/h2&gt;

&lt;p&gt;Here's what you see when running Cerberus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NEW DEVICE DETECTED!
   MAC:     dc:62:79:2f:39:28
   IP:      192.168.0.108
   Vendor:  Apple
   First Seen: 2024-12-06 16:51:12

[DNS] 192.168.0.100 (aa:bb:cc:dd:ee:ff) [Apple] → 8.8.8.8:53 [google.com]
[HTTP] 192.168.0.100 (aa:bb:cc:dd:ee:ff) [Apple] → 93.184.216.34:80 [GET /api/v1/users]
[TLS] 192.168.0.100 (aa:bb:cc:dd:ee:ff) [Apple] → 142.250.185.46:443 [TLS]
[TCP] 192.168.0.50 (11:22:33:44:55:66) [Raspberry Pi] → 192.168.0.200:22 (SSH)

╔════════════════════════════════════════════════════╗
║         NETWORK STATISTICS SUMMARY                 ║
╠════════════════════════════════════════════════════╣
║ Total Devices: 15                                  ║
║ Total Packets: 45821                               ║
║   - TCP:  38456                                    ║
║   - UDP:  6120                                     ║
║   - DNS:  892                                      ║
║   - HTTP: 156                                      ║
║   - TLS:  1834                                     ║
╚════════════════════════════════════════════════════╝
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Challenges and Solutions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Challenge #1: eBPF Complexity Limit
&lt;/h3&gt;

&lt;p&gt;eBPF programs are limited to ~1 million instructions. Solution: Keep parsing logic simple and move complex analysis to user space.&lt;/p&gt;

&lt;h3&gt;
  
  
  Challenge #2: Payload Size Tradeoff
&lt;/h3&gt;

&lt;p&gt;More payload = better L7 inspection, but higher overhead. Solution: 32 bytes is enough for DNS queries, HTTP methods, and TLS detection.&lt;/p&gt;

&lt;h3&gt;
  
  
  Challenge #3: TC vs XDP
&lt;/h3&gt;

&lt;p&gt;Initially considered XDP (eXpress Data Path) but TC offered better compatibility and easier development. XDP is faster but more restrictive.&lt;/p&gt;

&lt;h3&gt;
  
  
  Challenge #4: Cross-Kernel Compatibility
&lt;/h3&gt;

&lt;p&gt;Different kernel versions support different eBPF features. Solution: Use CO-RE (Compile Once, Run Everywhere) via libbpf.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start simple&lt;/strong&gt;: Basic packet capture first, then add L7 inspection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trust the verifier&lt;/strong&gt;: If it rejects your code, there's probably a real bug&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test incrementally&lt;/strong&gt;: Use &lt;code&gt;bpftool&lt;/code&gt; to inspect maps and programs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory matters&lt;/strong&gt;: Every byte in your event structure adds overhead&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User space is your friend&lt;/strong&gt;: Don't try to do everything in eBPF&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Production Considerations
&lt;/h2&gt;

&lt;p&gt;For critical infrastructure monitoring (my day job), I've learned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Alert fatigue is real&lt;/strong&gt;: Smart deduplication is essential&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance monitoring&lt;/strong&gt;: Track your own overhead&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graceful degradation&lt;/strong&gt;: Handle packet loss at high traffic volumes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt;: Limit L7 payload capture to metadata only&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;The roadmap for Cerberus includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Redis backend&lt;/strong&gt; for distributed deployments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prometheus metrics&lt;/strong&gt; export&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anomaly detection&lt;/strong&gt; using pattern baselines&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IPv6 support&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extended L7 inspection&lt;/strong&gt; (128-256 byte payloads)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web dashboard&lt;/strong&gt; for visualization&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/zrougamed/cerberus.git
&lt;span class="nb"&gt;cd &lt;/span&gt;cerberus
make
&lt;span class="nb"&gt;sudo&lt;/span&gt; ./build/cerberus
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Requirements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linux kernel 4.18+&lt;/li&gt;
&lt;li&gt;Go 1.24+&lt;/li&gt;
&lt;li&gt;Root privileges&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Contributing
&lt;/h2&gt;

&lt;p&gt;Cerberus is open source and looking for contributors! Whether you're interested in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;eBPF kernel programming&lt;/li&gt;
&lt;li&gt;Go application development&lt;/li&gt;
&lt;li&gt;Network protocol analysis&lt;/li&gt;
&lt;li&gt;Performance optimization&lt;/li&gt;
&lt;li&gt;Documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check out the &lt;a href="https://github.com/zrougamed/cerberus" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; and open an issue or PR.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ebpf.io/" rel="noopener noreferrer"&gt;eBPF Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/aquasecurity/libbpfgo" rel="noopener noreferrer"&gt;libbpfgo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nakryiko.com/posts/bpf-portability-and-co-re/" rel="noopener noreferrer"&gt;BPF CO-RE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.cilium.io/en/stable/bpf/" rel="noopener noreferrer"&gt;Cilium eBPF Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Building Cerberus taught me that eBPF isn't just about performance - it's about rethinking how we approach observability. By moving intelligence into the kernel, we can monitor networks at scale without sacrificing visibility.&lt;/p&gt;

&lt;p&gt;The combination of eBPF's efficiency and Go's expressiveness creates a powerful platform for building modern monitoring tools. Whether you're securing critical infrastructure or just curious about network traffic, eBPF opens up possibilities that weren't feasible before.&lt;/p&gt;

&lt;p&gt;What would you build with eBPF? Let me know in the comments!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Mohamed Zrouga is a Senior Platform Engineer at Deltaflare, specializing in critical infrastructure protection and DevSecOps. Connect on &lt;a href="https://github.com/zrougamed" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; or visit &lt;a href="https://zrouga.email" rel="noopener noreferrer"&gt;zrouga.email&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>opensource</category>
      <category>networking</category>
      <category>kernel</category>
    </item>
    <item>
      <title>Build a Secure Multi-Tenant SSO System with Keycloak, Go &amp; React: Step-by-Step Guide</title>
      <dc:creator>Mohamed Zrouga</dc:creator>
      <pubDate>Sat, 07 Jun 2025 19:55:54 +0000</pubDate>
      <link>https://dev.to/zrouga/build-a-secure-multi-tenant-sso-system-with-keycloak-go-react-step-by-step-guide-218m</link>
      <guid>https://dev.to/zrouga/build-a-secure-multi-tenant-sso-system-with-keycloak-go-react-step-by-step-guide-218m</guid>
      <description>&lt;p&gt;Managing authentication across multiple tenants can be a nightmare—different domains, identity providers, and security models all add complexity. In this guide, you’ll learn how to build a production-ready multi-tenant SSO system using &lt;strong&gt;Keycloak&lt;/strong&gt;, &lt;strong&gt;React&lt;/strong&gt;, and &lt;strong&gt;Go&lt;/strong&gt;, enabling your users to log in with Google, GitHub, or Microsoft accounts, while keeping each tenant securely isolated.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stack Overview
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Tech&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Identity&lt;/td&gt;
&lt;td&gt;Keycloak&lt;/td&gt;
&lt;td&gt;Central identity provider (OAuth2, JWT, social login, multi-tenancy)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;React&lt;/td&gt;
&lt;td&gt;User and admin interfaces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;Stateless API with JWT validation and business logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data&lt;/td&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;Stores tenants, users, and metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DevOps&lt;/td&gt;
&lt;td&gt;Docker Compose&lt;/td&gt;
&lt;td&gt;Container orchestration for local setup&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Architecture: A Layered Security Model
&lt;/h2&gt;

&lt;p&gt;The solution follows a cleanly separated, layered architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Identity Providers Layer&lt;/strong&gt;: Social login via Google, Microsoft, and GitHub&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend Layer&lt;/strong&gt;: 

&lt;ul&gt;
&lt;li&gt;React user interface (&lt;code&gt;http://localhost:3000&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Admin dashboard (&lt;code&gt;http://localhost:3001&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Authentication Layer&lt;/strong&gt;: 

&lt;ul&gt;
&lt;li&gt;Keycloak (&lt;code&gt;http://localhost:8080&lt;/code&gt;) handles all identity and access flows&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Backend Layer&lt;/strong&gt;: 

&lt;ul&gt;
&lt;li&gt;Go API (&lt;code&gt;http://localhost:8081&lt;/code&gt;) that verifies JWTs and executes tenant-aware logic&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Data Layer&lt;/strong&gt;: 

&lt;ul&gt;
&lt;li&gt;PostgreSQL database for user, tenant, and relationship data&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why This Stack?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjfwpsuujcqgf0pwnk9s6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjfwpsuujcqgf0pwnk9s6.png" alt="Image description" width="800" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Keycloak
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Open-source IAM platform with OAuth2, OpenID Connect, social login, and multi-tenancy.&lt;/li&gt;
&lt;li&gt;Saves you from writing brittle auth code.&lt;/li&gt;
&lt;li&gt;Highly customizable with realms, clients, and mappers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  React
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Modern, component-driven framework.&lt;/li&gt;
&lt;li&gt;Perfect separation of user frontend and admin interface.&lt;/li&gt;
&lt;li&gt;Great developer experience and large ecosystem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Go
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Lightweight and performant.&lt;/li&gt;
&lt;li&gt;Excellent standard library for JWT handling and HTTP.&lt;/li&gt;
&lt;li&gt;Strong concurrency model for scalable APIs.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Authentication Flow
&lt;/h2&gt;

&lt;p&gt;Here’s how the secure OAuth2-based login works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User starts login from the React frontend.&lt;/li&gt;
&lt;li&gt;Keycloak redirects to the selected identity provider.&lt;/li&gt;
&lt;li&gt;User authenticates, and the OAuth callback returns to Keycloak.&lt;/li&gt;
&lt;li&gt;Keycloak issues a JWT with user and tenant context.&lt;/li&gt;
&lt;li&gt;Frontend includes the JWT in API requests.&lt;/li&gt;
&lt;li&gt;Go backend validates the token and extracts tenant info.&lt;/li&gt;
&lt;li&gt;Tenant-isolated operations run based on JWT claims.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbxlvcq5h105v7h2ygrhw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbxlvcq5h105v7h2ygrhw.png" alt="Image description" width="800" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This setup ensures centralized auth with stateless APIs and strong tenant isolation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Multi-Tenancy: Key Considerations
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;Solution&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tenant Isolation&lt;/td&gt;
&lt;td&gt;Users and data are scoped to their own organization.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flexible Auth&lt;/td&gt;
&lt;td&gt;Each tenant chooses which social login providers to enable.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Self-Service Admin&lt;/td&gt;
&lt;td&gt;Admin panel allows tenant admins to manage users without overlap.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scalable Infrastructure&lt;/td&gt;
&lt;td&gt;Each component is containerized and independently scalable.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Security Best Practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JWT Validation&lt;/strong&gt;: Go backend checks tokens against Keycloak’s JWKS endpoint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CORS Configuration&lt;/strong&gt;: Proper headers configured in both Keycloak and backend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment Variables&lt;/strong&gt;: All sensitive values are managed via &lt;code&gt;.env&lt;/code&gt; files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolated Networks&lt;/strong&gt;: Docker containers communicate over private networks.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Clone and boot the system using Docker Compose:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Clone and navigate to the repo
git clone https://github.com/zrougamed/multitenant-sso
cd multitenant-sso

# Start all services
docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Access services at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keycloak: &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;User frontend: &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Admin panel: &lt;a href="http://localhost:3001" rel="noopener noreferrer"&gt;http://localhost:3001&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Go API: &lt;a href="http://localhost:8081" rel="noopener noreferrer"&gt;http://localhost:8081&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Configuring OAuth Providers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Google
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://console.cloud.google.com/" rel="noopener noreferrer"&gt;Google Cloud Console&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Create OAuth credentials&lt;/li&gt;
&lt;li&gt;Set redirect URI:
&lt;code&gt;http://localhost:8080/realms/{realm}/broker/google/endpoint&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  GitHub
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://github.com/settings/developers" rel="noopener noreferrer"&gt;GitHub Developer Settings&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Set callback URI:
&lt;code&gt;http://localhost:8080/realms/{realm}/broker/github/endpoint&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Microsoft
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Register an app via &lt;a href="https://portal.azure.com" rel="noopener noreferrer"&gt;Azure App Registrations&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Set redirect URI:
&lt;code&gt;http://localhost:8080/realms/{realm}/broker/azure/endpoint&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Common Challenges and Solutions
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Solution&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Port Conflicts&lt;/td&gt;
&lt;td&gt;Modify &lt;code&gt;docker-compose.yml&lt;/code&gt; or Keycloak config.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CORS Errors&lt;/td&gt;
&lt;td&gt;Ensure correct CORS settings in backend and Keycloak.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JWT Validation Fails&lt;/td&gt;
&lt;td&gt;Double-check audience (&lt;code&gt;aud&lt;/code&gt;), issuer (&lt;code&gt;iss&lt;/code&gt;), and realm configuration.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Extending the System
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Add more identity providers: Twitter, Facebook, etc.&lt;/li&gt;
&lt;li&gt;Add Role-Based Access Control (RBAC) via Keycloak groups and roles.&lt;/li&gt;
&lt;li&gt;Implement API rate limiting in Go middleware.&lt;/li&gt;
&lt;li&gt;Add monitoring with Prometheus, Grafana, or ELK.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Production Considerations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;High Availability&lt;/strong&gt;: Cluster Keycloak and PostgreSQL with redundancy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSL/TLS&lt;/strong&gt;: Use reverse proxy like NGINX or Traefik for HTTPS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backups&lt;/strong&gt;: Regular backups for Keycloak and PostgreSQL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring&lt;/strong&gt;: Alerting on auth failures, performance, and token expiry issues.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Building a secure, scalable, multi-tenant SSO system doesn’t have to be painful. By using &lt;strong&gt;Keycloak&lt;/strong&gt; for identity management, &lt;strong&gt;React&lt;/strong&gt; for the frontend, and &lt;strong&gt;Go&lt;/strong&gt; for the API, you get a powerful and maintainable architecture that scales with your needs.&lt;/p&gt;

&lt;p&gt;The system supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi-tenant user isolation&lt;/li&gt;
&lt;li&gt;Social logins via OAuth&lt;/li&gt;
&lt;li&gt;Stateless APIs with secure JWTs&lt;/li&gt;
&lt;li&gt;Admin management for each tenant&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Source Code&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
👉 &lt;a href="https://github.com/zrougamed/multitenant-sso" rel="noopener noreferrer"&gt;GitHub Repository – multitenant-sso&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Questions or feedback?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Open an issue on GitHub or connect with me on &lt;a href="https://www.linkedin.com/in/zrouga-mohamed/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

</description>
      <category>oauth</category>
      <category>devops</category>
      <category>sso</category>
      <category>programming</category>
    </item>
    <item>
      <title>🚀 Open Source Notification Scheduler in Go! 🌟 [Looking for Contributors]</title>
      <dc:creator>Mohamed Zrouga</dc:creator>
      <pubDate>Mon, 16 Dec 2024 02:37:43 +0000</pubDate>
      <link>https://dev.to/zrouga/open-source-notification-scheduler-in-go-looking-for-contributors-1o8j</link>
      <guid>https://dev.to/zrouga/open-source-notification-scheduler-in-go-looking-for-contributors-1o8j</guid>
      <description>&lt;p&gt;Hi Dev! 👋&lt;/p&gt;

&lt;p&gt;I’m excited to share my latest open-source project, Dynamic Notification System! 🎉&lt;/p&gt;

&lt;p&gt;This is a Go-based extensible notification scheduler that supports multiple channels, including:&lt;/p&gt;

&lt;p&gt;📨 Slack&lt;br&gt;
🔔 Discord&lt;br&gt;
📩 Telegram&lt;br&gt;
📧 SMTP&lt;br&gt;
🖥️ Webhooks&lt;br&gt;
And many more!&lt;br&gt;
With dynamic plugin support, the system allows you to add new notification channels effortlessly. It’s designed for cross-platform compatibility (Linux, macOS, Windows) and supports Go 1.23+.&lt;/p&gt;

&lt;p&gt;Why Contribute?&lt;br&gt;
✅ Learn and improve your skills in Go and dynamic plugin systems.&lt;br&gt;
✅ Work on cross-platform builds for Linux, macOS, and Windows.&lt;br&gt;
✅ Be part of a growing open-source project and build your portfolio.&lt;br&gt;
✅ Help the community by adding new features and optimizing existing ones.&lt;/p&gt;

&lt;p&gt;How You Can Help&lt;br&gt;
👨‍💻 We’re looking for contributors to:&lt;/p&gt;

&lt;p&gt;Add new notification channels like Twilio, Signal, etc.&lt;br&gt;
Improve documentation and examples.&lt;br&gt;
Fix bugs and optimize builds.&lt;br&gt;
No matter your experience level, we’d love your input! 🚀&lt;/p&gt;

&lt;p&gt;Links&lt;br&gt;
🔗 GitHub Repository: &lt;a href="https://github.com/zrougamed/dynamic-notification-system" rel="noopener noreferrer"&gt;Dynamic Notification System&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to check out the project, try it, and let us know your thoughts! Contributions, feedback, and stars 🌟 are all greatly appreciated. Let’s build something amazing together! 💪&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>development</category>
      <category>go</category>
      <category>ui</category>
    </item>
  </channel>
</rss>
