<?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: Harshwardhan S. Ranvir</title>
    <description>The latest articles on DEV Community by Harshwardhan S. Ranvir (@harshwardhan_ranvir).</description>
    <link>https://dev.to/harshwardhan_ranvir</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%2F3980920%2F5fd53aa7-778f-46ca-8c91-bcefb6e5b245.jpg</url>
      <title>DEV Community: Harshwardhan S. Ranvir</title>
      <link>https://dev.to/harshwardhan_ranvir</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/harshwardhan_ranvir"/>
    <language>en</language>
    <item>
      <title>CERBERUS: I Built a Network Sentinel Because My Router Wasn't Enough</title>
      <dc:creator>Harshwardhan S. Ranvir</dc:creator>
      <pubDate>Fri, 12 Jun 2026 10:31:32 +0000</pubDate>
      <link>https://dev.to/harshwardhan_ranvir/cerberus-i-built-a-network-sentinel-because-my-router-wasnt-enough-5bmg</link>
      <guid>https://dev.to/harshwardhan_ranvir/cerberus-i-built-a-network-sentinel-because-my-router-wasnt-enough-5bmg</guid>
      <description>&lt;p&gt;&lt;em&gt;A deep dive into building a Python-based network surveillance tool with Scapy, automatic router detection, and a two-phase watch system.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Most people never think about what's actually on their home network. The router has a device list somewhere behind three login screens and a UI that looks like it was designed in 2009. You check it once, forget about it, and move on.&lt;/p&gt;

&lt;p&gt;That's not good enough.&lt;/p&gt;

&lt;p&gt;I wanted to know my network — not by logging into the router every time, but through automation. A tool that runs, learns what's supposed to be there, and then tells me when something isn't. So I built CERBERUS.&lt;/p&gt;

&lt;p&gt;This post covers what it does, how every component works, the engineering decisions behind it, and what I actually learned building it — including the parts that were genuinely difficult.&lt;/p&gt;




&lt;h2&gt;
  
  
  What CERBERUS Does
&lt;/h2&gt;

&lt;p&gt;CERBERUS is a Python-based network sentinel. It scans your local network using ARP, learns which devices are trusted, and runs a continuous surveillance loop that alerts you when something unknown shows up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Feature list:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatic router and subnet detection (no manual config)&lt;/li&gt;
&lt;li&gt;ARP-based device discovery with wake-up broadcast&lt;/li&gt;
&lt;li&gt;Two-phase operation: Learning Mode → Surveillance Mode&lt;/li&gt;
&lt;li&gt;Unknown device alerts with CRITICAL log entries&lt;/li&gt;
&lt;li&gt;Structured file + console logging (reusable module)&lt;/li&gt;
&lt;li&gt;Auto-generated &lt;code&gt;known_devices.json&lt;/code&gt; and &lt;code&gt;cerberus.log&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Windows Npcap auto-installer&lt;/li&gt;
&lt;li&gt;Cross-platform: Linux, macOS, Windows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What it does NOT do (...yet):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No port scanning (that's CERBERUS v2)&lt;/li&gt;
&lt;li&gt;Won't detect devices that block ARP responses entirely&lt;/li&gt;
&lt;li&gt;No persistent background daemon — runs in terminal&lt;/li&gt;
&lt;li&gt;No push/email alerts, just logged output&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Architecture: Four Modules, One Purpose
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cerberus/
├── cerberus_scan.py        # Main orchestrator
├── cerberus_logger.py      # Reusable logging setup
├── router_detector.py      # Network auto-configuration
├── npcap_installer.py      # Windows Npcap helper
├── known_devices.json      # Auto-generated trusted list
└── cerberus.log            # Auto-generated activity log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The design is intentionally modular. Each file has one job. &lt;code&gt;cerberus_scan.py&lt;/code&gt; orchestrates everything but doesn't do the heavy lifting itself — it delegates to the other modules and handles the main execution flow.&lt;/p&gt;

&lt;p&gt;The two auto-generated files (&lt;code&gt;known_devices.json&lt;/code&gt; and &lt;code&gt;cerberus.log&lt;/code&gt;) are created at runtime. You don't set them up. CERBERUS creates them when it first runs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Security note:&lt;/strong&gt; &lt;code&gt;known_devices.json&lt;/code&gt; stores MAC addresses of your trusted devices.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Deep Dive: How Each Component Works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Router Detection — &lt;code&gt;router_detector.py&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Before scanning anything, CERBERUS needs to know what network to scan. This is where most tools either require manual configuration or make a dumb assumption. CERBERUS tries to be smarter.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;RouterDetector&lt;/code&gt; class uses Python's &lt;code&gt;netifaces&lt;/code&gt; library to query the system's default gateway:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;gateways&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;netifaces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gateways&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;gateway_ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;interface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gateways&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;default&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;netifaces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AF_INET&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once it has the interface, it fetches the actual subnet mask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;addrs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;netifaces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ifaddresses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;netmask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;addrs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;netifaces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AF_INET&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;netmask&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;cidr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;bin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;'&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;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;netmask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;network_address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;network_addr&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cidr&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives you the correct CIDR notation — say, &lt;code&gt;192.168.1.0/24&lt;/code&gt; or &lt;code&gt;10.0.0.0/22&lt;/code&gt; — based on your actual network, not a guess.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fallback:&lt;/strong&gt; If subnet mask detection fails (some systems don't return this reliably), CERBERUS falls back to a &lt;code&gt;/24&lt;/code&gt; assumption:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;network_base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;router_ip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[:&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;+&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.0/24&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;TARGET_NETWORK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;network_base&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Using default /24 network assumption: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;TARGET_NETWORK&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This covers the vast majority of home networks. If your network is different, you'll see the warning and can hardcode &lt;code&gt;TARGET_NETWORK&lt;/code&gt; in the config section of &lt;code&gt;cerberus_scan.py&lt;/code&gt;. It's a practical trade-off — automatic detection works 95% of the time, and the fallback handles the rest without crashing.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. ARP Scanning — The Core of CERBERUS
&lt;/h3&gt;

&lt;p&gt;ARP (Address Resolution Protocol) is how devices on a network map IP addresses to MAC addresses. It's stateless, has no authentication, and every device on your network responds to it. That makes it ideal for discovery.&lt;/p&gt;

&lt;p&gt;CERBERUS builds a broadcast ARP request using Scapy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;arp_request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ARP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdst&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;TARGET_NETWORK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ether_frame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Ether&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ff:ff:ff:ff:ff:ff&lt;/span&gt;&lt;span class="sh"&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;ether_frame&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;arp_request&lt;/span&gt;

&lt;span class="n"&gt;answered_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;srp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&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="n"&gt;clients&lt;/span&gt; &lt;span class="o"&gt;=&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;sent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;received&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;answered_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ip&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;received&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;psrc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mac&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;received&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hwsrc&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ARP(pdst=TARGET_NETWORK)&lt;/code&gt; creates an ARP request asking "who has every IP in this range?"&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Ether(dst="ff:ff:ff:ff:ff:ff")&lt;/code&gt; wraps it in an Ethernet broadcast frame — every device on the network receives this.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;srp()&lt;/code&gt; (send/receive at Layer 2) sends the packet and listens for responses. Whatever responds gets added to the clients list with their IP and MAC.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The wake-up call:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before the ARP scan, CERBERUS sends a broadcast ICMP ping:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;broadcast_ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TARGET_NETWORK&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&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="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;'&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.255&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;broadcast_ip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nc"&gt;ICMP&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some devices go into a low-power state and take a moment to respond to ARP. The broadcast ping nudges them awake before the scan. It doesn't work on every device — anything that ignores pings or blocks ICMP stays invisible — but it improves discovery rates on typical home networks.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Learning Mode vs Surveillance Mode
&lt;/h3&gt;

&lt;p&gt;This two-phase design is the core logic of CERBERUS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 1 — Learning Mode&lt;/strong&gt; (first run only):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;learn_network_mode&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;current_devices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;scan_network&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;known_macs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mac&lt;/span&gt;&lt;span class="sh"&gt;"&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;device&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;current_devices&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nf"&gt;save_known_devices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;known_macs&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;known_macs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On first run, there's no &lt;code&gt;known_devices.json&lt;/code&gt;. CERBERUS detects this, scans the network, saves every discovered MAC as trusted, and creates the file. No alerts. Everything found in learning mode is considered legitimate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 2 — Surveillance Mode&lt;/strong&gt; (every run after):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;surveillance_mode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;known_macs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;current_devices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;scan_network&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;device&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;current_devices&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;device&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mac&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;known_macs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unknown: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ip&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; - &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mac&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&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;unknown_devices&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;critical&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ALERT: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unknown_devices&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; intruder(s) detected!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SCAN_INTERVAL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every 60 seconds (configurable), CERBERUS scans, loads the trusted MAC list, and compares. Any MAC not in the trusted list triggers a &lt;code&gt;WARNING&lt;/code&gt;. If unknown devices are found, &lt;code&gt;CRITICAL&lt;/code&gt; level alerts fire for each one.&lt;/p&gt;

&lt;p&gt;The loop runs until &lt;code&gt;Ctrl+C&lt;/code&gt;. No scan limit. CERBERUS watches until you tell it to stop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why MAC addresses and not IPs?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;IP addresses change. Devices get new IPs via DHCP on every reconnect. MAC addresses are hardware identifiers — they're stable. Tracking by MAC means a device can reconnect on a different IP and CERBERUS still recognizes it.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. The Logging Module — &lt;code&gt;cerberus_logger.py&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setup_logging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cerberus.log&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;INFO&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;silent_mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;formatter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Formatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%(asctime)s - %(name)s - %(levelname)s - %(message)s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;datefmt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%Y-%m-%d %H-%M-%S&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Always writes to file
&lt;/span&gt;    &lt;span class="n"&gt;file_handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FileHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Console output optional
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;silent_mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;console_handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StreamHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I built this as a separate module for a reason: I'll use it in future projects. Same interface, drop it in, configure the log file name and level. No rewriting.&lt;/p&gt;

&lt;p&gt;Key behaviors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Always appends to file — you don't lose previous scan history&lt;/li&gt;
&lt;li&gt;Console output is optional via &lt;code&gt;silent_mode=True&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Five log levels available: DEBUG, INFO, WARNING, ERROR, CRITICAL&lt;/li&gt;
&lt;li&gt;Millisecond-precision timestamps on every entry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CERBERUS uses WARNING for unknown devices and CRITICAL for confirmed intruder alerts. The distinction matters when parsing logs programmatically.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Windows Npcap Auto-Installer — &lt;code&gt;npcap_installer.py&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Windows doesn't give raw socket access out of the box. Scapy needs Npcap (a packet capture driver) to function on Windows. Without it, nothing works.&lt;/p&gt;

&lt;p&gt;Most tools say "install Npcap manually" and leave you to figure it out. I didn't want that. The auto-installer handles it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Check if already installed&lt;/strong&gt; — registry lookup + file system check + live Scapy test&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If not found&lt;/strong&gt; — offer options: auto-install, manual install, or skip&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-install path&lt;/strong&gt; — downloads installer, runs silent install with these flags:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;/&lt;span class="n"&gt;S&lt;/span&gt;                    &lt;span class="c"&gt;# Silent mode, no GUI
&lt;/span&gt;&lt;span class="n"&gt;winpcap_mode&lt;/span&gt;=&lt;span class="n"&gt;yes&lt;/span&gt;      &lt;span class="c"&gt;# WinPcap API compatibility
&lt;/span&gt;&lt;span class="n"&gt;loopback_support&lt;/span&gt;=&lt;span class="n"&gt;yes&lt;/span&gt;  &lt;span class="c"&gt;# Capture localhost traffic
&lt;/span&gt;&lt;span class="n"&gt;admin_only&lt;/span&gt;=&lt;span class="n"&gt;no&lt;/span&gt;         &lt;span class="c"&gt;# Allow non-admin capture
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The version is currently hardcoded to Npcap 1.79. It'll work fine for the foreseeable future — Npcap doesn't have breaking releases frequently — but it's something to revisit in v2.&lt;/p&gt;

&lt;p&gt;This module ended up being more code than the scanner itself. Building it taught me more about Windows internals than I expected: registry access with &lt;code&gt;winreg&lt;/code&gt;, process management with &lt;code&gt;subprocess&lt;/code&gt;, installer flags, and the gap between "it works on my machine" and "it works on someone else's machine."&lt;/p&gt;




&lt;h2&gt;
  
  
  Sample Output
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Learning Mode (first run):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;==================================================
PROJECT CERBERUS: The Network Sentinel
==================================================
✔️ Network detected: 192.168.1.0/24
Router: 192.168.1.1
Your IP: 192.168.1.x
Interface: wlan0
--------------------------------------------------
No known devices file found. Starting learning mode...
Scanning 192.168.1.0/24...
Found 5 devices.
Learned 5 devices. They are now trusted.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Surveillance Mode — clean scan:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;------------------------- Scan 1 -------------------------
Scanning 192.168.1.0/24...
Found 5 devices.
All devices are trusted.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Surveillance Mode — intruder detected:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;------------------------- Scan 4 -------------------------
Scanning 192.168.1.0/24...
Found 6 devices.
WARNING  - Unknown: 192.168.1.108 - xx:xx:xx:xx:xx:xx
CRITICAL - ALERT: 1 intruder(s) device detected!
CRITICAL - INTRUDER: 192.168.1.108 - xx:xx:xx:xx:xx:xx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;For security reasons i'm not putting the original terminal outputs here.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Engineering Decisions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why Scapy over &lt;code&gt;subprocess&lt;/code&gt; + system &lt;code&gt;arp&lt;/code&gt;?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The alternative was calling &lt;code&gt;arp -a&lt;/code&gt; via subprocess and parsing text output. That breaks when output format changes across OS versions (and it does). Scapy gives you structured data directly, cross-platform control, and fine-grained timeout/retry configuration. The learning curve is steeper, but you're not writing a brittle text parser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why JSON for device storage?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No database overhead for a list of MAC addresses that'll never exceed 50 entries on a home network. JSON is human-readable, directly editable, and parseable without any dependencies. If you want to add a device manually or remove one, open the file and edit it. Simple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why 60-second scan intervals?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;30 seconds felt aggressive for passive home network monitoring — unnecessary traffic and CPU overhead. 120 seconds means an intruder goes unnoticed for two minutes. 60 is the balance. It's also directly configurable: change &lt;code&gt;SCAN_INTERVAL&lt;/code&gt; in &lt;code&gt;cerberus_scan.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why separate the logging module?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Reusability. &lt;code&gt;cerberus_logger.py&lt;/code&gt; has no CERBERUS-specific logic. It's a clean logging setup function. I'll drop it into the next project without touching it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Actually Learned
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Scapy's documentation is scattered&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most tutorials cover sending a single ping. Understanding &lt;code&gt;srp()&lt;/code&gt; (Layer 2 send/receive) versus &lt;code&gt;sr()&lt;/code&gt; (Layer 3) took actual time — reading source code, not just docs. There's no single good resource that covers it end-to-end. You have to piece it together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. ARP is stateless. That's the attack surface.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Building this made the theory real. ARP has no authentication. Any device can respond to any ARP request, including one it didn't ask for — that's how ARP spoofing works. I understood this conceptually before. After building CERBERUS, I understood it practically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Device discovery is harder than it looks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not all devices respond to ARP every time. Sleeping devices, aggressively firewalled devices, some IoT hardware — they don't always reply. The wake-up broadcast ping helps, but it's not a complete solution. This is the core limitation that's driving CERBERUS v2: multiple discovery methods, not just ARP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Windows is a different world for networking&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Linux gives you raw socket access with &lt;code&gt;sudo&lt;/code&gt;. Windows gates it behind a kernel driver (Npcap). Building the auto-installer taught me about Windows registry interaction, silent installer flags, and the difference between making a tool that works on your development machine versus one that someone else can actually run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. AI helped with syntax. Debugging was still mine.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I used AI assistance for Scapy syntax and parts of the Npcap implementation. But when something failed — wrong subnet detection, missed devices, logging output inconsistencies — figuring out why required reading logs, testing across configurations, and sometimes reading library source code. AI accelerates. It doesn't replace the diagnostic work.&lt;/p&gt;




&lt;h2&gt;
  
  
  Limitations and CERBERUS v2
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What v1 doesn't solve:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Devices that don't respond to ARP stay invisible&lt;/li&gt;
&lt;li&gt;No port/service fingerprinting — you see a device, not what it's running&lt;/li&gt;
&lt;li&gt;No persistent daemon — closes when terminal closes&lt;/li&gt;
&lt;li&gt;No alerting beyond log output (no email, no webhook, no SMS)&lt;/li&gt;
&lt;li&gt;Npcap version hardcoded on Windows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What CERBERUS v2 is adding:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker containerization — runs anywhere, including Raspberry Pi&lt;/li&gt;
&lt;li&gt;Nmap integration for port scanning and service detection&lt;/li&gt;
&lt;li&gt;Multiple discovery methods (not just ARP)&lt;/li&gt;
&lt;li&gt;SQLite for persistent device history&lt;/li&gt;
&lt;li&gt;REST API for status queries&lt;/li&gt;
&lt;li&gt;Webhook/email notifications&lt;/li&gt;
&lt;li&gt;Smarter intruder classification&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;v2 is in active development.&lt;/p&gt;




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

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

&lt;ul&gt;
&lt;li&gt;Python 3.7+&lt;/li&gt;
&lt;li&gt;Linux/macOS: run with &lt;code&gt;sudo&lt;/code&gt; (raw packet access requires root)&lt;/li&gt;
&lt;li&gt;Windows: run as Administrator (auto-installer handles Npcap)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Ranvir2028/Cerberus-The-Network-Sentinel.git
&lt;span class="nb"&gt;cd &lt;/span&gt;Cerberus-The-Network-Sentinel
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Run:&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;# Linux/macOS&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;python3 cerberus_scan.py

&lt;span class="c"&gt;# Windows (Administrator terminal)&lt;/span&gt;
python cerberus_scan.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First run enters learning mode automatically. Every run after that is surveillance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependencies&lt;/strong&gt; (from &lt;code&gt;requirements.txt&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;scapy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;=2.6.1&lt;/span&gt;
&lt;span class="py"&gt;netifaces-plus&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;=0.12.5&lt;/span&gt;
&lt;span class="py"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;=2.32.5&lt;/span&gt;
&lt;span class="py"&gt;colorama&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;=0.4.6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Security Note
&lt;/h2&gt;

&lt;p&gt;Only use CERBERUS on networks you own or have explicit permission to monitor. ARP scanning sends packets to every IP in your network range. On a network you don't own, that's unauthorized network activity.&lt;/p&gt;




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

&lt;p&gt;CERBERUS v2 is being built now. The goal is a containerized network sentinel that runs continuously on a home server or Raspberry Pi, scans with multiple discovery methods, and notifies you without you having to watch a terminal.&lt;/p&gt;

&lt;p&gt;The v1 code is on GitHub named &lt;em&gt;Cerberus: The Network Sentinel&lt;/em&gt;. Read it, break it, use it to understand ARP scanning.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/Ranvir2028/Cerberus-The-Network-Sentinel" rel="noopener noreferrer"&gt;github.com/Ranvir2028/Cerberus-The-Network-Sentinel&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/harshwardhan-s-ranvir-20a328378/" rel="noopener noreferrer"&gt;linkedin.com/in/harshwardhan-s-ranvir-20a328378&lt;/a&gt;&lt;/p&gt;




</description>
      <category>python</category>
      <category>security</category>
      <category>networking</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
