Version: 1.4.1 Last Updated: 2026-02-06
The Network Analytics Monitor queries the Cloudflare GraphQL API to detect DDoS mitigation events that may not trigger standard webhook notifications. It provides comprehensive visibility into all traffic dropped by Cloudflare's DDoS protection systems, enriched with GeoIP2 geolocation data.
- GraphQL Polling: Queries
dosdNetworkAnalyticsAdaptiveGroupsevery 5 minutes - Dashboard Preference Sync: Reads "My prefixes only" toggle from dashboard to control notifications
- Destination Filter: Notifies for GOLINE prefixes AND/OR Cloudflare anycast based on preference
- Cloudflare Anycast: Includes 162.159.0.0/16, 172.64.0.0/13, 104.16.0.0/13 (when filter disabled)
- GeoIP2 Enrichment: Source IPs show country, city, and ASN information
- GeoIP Fallback: Supports both commercial (GeoIP2) and free (GeoLite2) databases
- Spoofed IP Detection: Identifies private/reserved IPs with
⚠️ indicator - SQLite Deduplication: Prevents duplicate notifications via event hash
- Telegram Notifications: Single events, aggregated bulk, startup and shutdown messages
- European Date Format: All dates displayed as DD/MM/YYYY HH:MM
┌─────────────────────────────────────────────────────────────────┐
│ NETWORK ANALYTICS MONITOR v1.4.0 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Cloudflare GraphQL API │
│ │ │
│ │ dosdNetworkAnalyticsAdaptiveGroups (every 5 min) │
│ ▼ │
│ ┌────────────────────────┐ │
│ │ Destination Filter │ GOLINE: 185.54.80.0/22, 2a02:4460::/32│
│ │ │ CF Anycast: 162.159/16, 172.64/13 │
│ └───────────┬────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────┐ ┌────────────────────────┐ │
│ │ GeoIP2 Enrichment │────▶│ GeoIP2-City.mmdb │ │
│ │ │────▶│ GeoLite2-ASN.mmdb │ │
│ └───────────┬────────────┘ └────────────────────────┘ │
│ │ │
│ ┌─────────┼─────────┐ │
│ ▼ ▼ ▼ │
│ SQLite Telegram Log files │
│ (dedup) (alerts) (debug) │
│ │
└─────────────────────────────────────────────────────────────────┘
| Component | Path |
|---|---|
| Script | /root/Cloudflare_MT_Integration/scripts/cloudflare-network-analytics-monitor.py |
| Systemd Service | /etc/systemd/system/cloudflare-analytics-monitor.service |
| Log File | /root/Cloudflare_MT_Integration/logs/network-analytics-monitor.log |
| Database | /root/Cloudflare_MT_Integration/db/magic_transit.db |
| Dashboard Prefs | /root/Cloudflare_MT_Integration/config/dashboard_prefs.json |
| GeoIP City | /usr/share/GeoIP/GeoIP2-City.mmdb |
| GeoIP ASN | /usr/share/GeoIP/GeoLite2-ASN.mmdb |
| Parameter | Default | Description |
|---|---|---|
POLL_INTERVAL |
300s (5 min) | Time between API queries |
LOOKBACK_MINUTES |
15 min | Time window for each query |
MIN_PACKETS_THRESHOLD |
1 | Minimum packets to trigger notification |
| Prefix | Type | Description |
|---|---|---|
185.54.80.0/22 |
GOLINE | All GOLINE IPv4 (covers 80, 81, 82, 83) |
2a02:4460::/32 |
GOLINE | GOLINE IPv6 (covers 2a02:4460:1::/48) |
162.159.0.0/16 |
Cloudflare | Anycast IPs (Magic Transit pass-through) |
172.64.0.0/13 |
Cloudflare | Anycast IPs (Magic Transit pass-through) |
104.16.0.0/13 |
Cloudflare | Anycast IPs (Magic Transit pass-through) |
Why include Cloudflare anycast? When Magic Transit is active, some attacks target Cloudflare anycast IPs directly (e.g., 162.159.76.173). These are still attacks against GOLINE infrastructure being mitigated by Cloudflare. Including these prefixes ensures complete visibility of all DDoS mitigation events.
The monitor reads the "My prefixes only" toggle state from the dashboard preferences file:
| File | Path |
|---|---|
| Dashboard Prefs | config/dashboard_prefs.json |
Preference Format:
{"my_prefixes_only": true}Behavior:
| Setting | Notifications For |
|---|---|
my_prefixes_only: true |
Only GOLINE prefixes (185.54.x.x, 2a02:4460:x) |
my_prefixes_only: false |
All traffic including Cloudflare anycast |
Prefix Lists:
MY_PREFIXES = [
'185.54.80.0/22', # GOLINE IPv4
'2a02:4460::/32', # GOLINE IPv6
]
ALL_PREFIXES = MY_PREFIXES + [
'162.159.0.0/16', # Cloudflare anycast
'172.64.0.0/13', # Cloudflare anycast
'104.16.0.0/13', # Cloudflare anycast
]Note: The preference is read on each poll cycle (every 5 minutes), so changes take effect without restarting the service.
Source IPs in notifications are enriched with geolocation data:
| Data | Source | Example |
|---|---|---|
| Country | GeoIP2-City.mmdb | Bangladesh (BD) |
| City | GeoIP2-City.mmdb | Pābna |
| ASN | GeoLite2-ASN.mmdb | AS137959 |
| Organization | GeoLite2-ASN.mmdb | Vision Technologies Ltd. |
Private and reserved IP ranges are automatically detected and marked:
| Range | Type |
|---|---|
10.0.0.0/8 |
Private |
172.16.0.0/12 |
Private |
192.168.0.0/16 |
Private |
127.0.0.0/8 |
Loopback |
169.254.0.0/16 |
Link-local |
224.0.0.0/4 |
Multicast |
The script searches for GeoIP databases in order of preference:
City Database (for Country/City):
1. /usr/share/GeoIP/GeoIP2-City.mmdb # Commercial (more accurate)
2. /usr/share/GeoIP/GeoLite2-City.mmdb # Free fallback
3. /var/lib/GeoIP/GeoIP2-City.mmdb # Alternative location
4. /var/lib/GeoIP/GeoLite2-City.mmdb # Alternative location
ASN Database:
1. /usr/share/GeoIP/GeoIP2-ASN.mmdb # Commercial
2. /usr/share/GeoIP/GeoLite2-ASN.mmdb # Free fallback
3. /var/lib/GeoIP/GeoIP2-ASN.mmdb # Alternative location
4. /var/lib/GeoIP/GeoLite2-ASN.mmdb # Alternative location
Current Setup:
/usr/share/GeoIP/GeoIP2-City.mmdb # 122 MB (commercial)
/usr/share/GeoIP/GeoLite2-ASN.mmdb # 11 MB (free)
The startup message indicates which database type is in use (Commercial or Free) and its last update date.
apt install python3-geoip2🛡️ *CLOUDFLARE DDoS PROTECTION*
🚨 *MITIGATION EVENT*
⏱️ *Time:* `2026-01-19 22:51:50 UTC`
🆔 *Attack ID:* `k9z3t-xx1g6wwhgqngq523mp0nr`
⚔️ *ATTACK INFO*
💥 *Vector:* ICMP Flood
📋 *Rule:* ICMP-0001
🛡️ *Action:* BLOCKED
🌐 *NETWORK*
📤 *Source:* `103.118.76.198:46181`
🌍 *Origin:* Pābna, Bangladesh (BD)
🏢 *ASN:* AS137959 - Vision Technologies Ltd.
📥 *Target:* `185.54.82.4:0`
🔧 *Protocol:* ICMP
🏷️ *TCP Flags:* N/A
📊 *METRICS*
📦 *Packets:* 1,500
📈 *Data:* 9.00 Mbps
📍 *CLOUDFLARE EDGE*
🌍 *Scrubbed at:* Sofia, Bulgaria (SOF)
🏢 *GOLINE SOC* | _Network Analytics Monitor_
🛡️ *CLOUDFLARE DDoS PROTECTION*
🚨 *BULK MITIGATION EVENTS*
📊 *SUMMARY*
📦 *Events:* 15
🆔 *Attack IDs:* 1
📍 *Unique Sources:* 8
⚠️ *Spoofed IPs:* 3/8
⏱️ *TIME RANGE*
🕐 *From:* `2026-01-19T22:50:00Z`
🕑 *To:* `2026-01-19T22:55:00Z`
⚔️ *ATTACK VECTORS*
• ICMP Flood
• GRE Flood
📊 *TOTAL METRICS*
📦 *Packets Dropped:* 15,000
📈 *Data Blocked:* 54.00 Mb
📤 *TOP SOURCE IPs*
• `103.118.76.198` 🌍 BD (AS137959)
• `45.227.254.17` 🌍 BR (AS270523)
• `10.0.0.1` ⚠️ _Spoofed_
🌍 *EDGE LOCATIONS*
SOF (BG), AMS (NL)
🏢 *GOLINE SOC* | _Network Analytics Monitor_
🛡️ *CLOUDFLARE DDoS PROTECTION*
🚀 *Network Analytics Monitor STARTED*
📊 *Configuration*
📌 Version: 1.3.8
⏰ Poll: 300s | Lookback: 15 min
🌍 GeoIP: Commercial (updated: 20/01/2026)
🌐 *BGP Status*
📡 Prefixes: 0/5 ✅ All withdrawn
📈 *Attack History*
🎯 Attacks: 6 total (6 this month)
📊 Mitigations: 402 events logged
🚨 Last: `19/01/2026 21:51`
💥 Type: SYN Flood, 1.2 Gbps → 185.54.82.4
⚙️ *Services*
✅ Webhook | ✅ Autowithdraw | ✅ Dashboard
_Monitoring for DDoS mitigation events..._
Data Sources:
| Field | Source | Description |
|---|---|---|
| Version | Hardcoded | Script version |
| GeoIP Type | Database detection | Commercial or Free |
| GeoIP Updated | File mtime | Last modification date |
| BGP Prefixes | Cloudflare API | Advertised/Total count |
| Attacks Total | SQLite attack_events |
WHERE event_type='START' |
| Attacks Month | SQLite attack_events |
Current month filter |
| Mitigations | SQLite network_analytics_events |
Total count |
| Last Attack | SQLite attack_events |
Most recent START event |
| Services | systemctl is-active | Webhook, Autowithdraw, Dashboard |
🛡️ *CLOUDFLARE DDoS PROTECTION*
⏹️ *Network Analytics Monitor STOPPED*
📈 *Stats*
🎯 Attacks: 6 total (6 this month)
📊 Mitigations: 402 events
⏰ *Stopped at:* 21/01/2026 03:13:01 UTC
🏢 *GOLINE SOC* | _Network Analytics_
# Start/Stop/Restart
systemctl start cloudflare-analytics-monitor
systemctl stop cloudflare-analytics-monitor
systemctl restart cloudflare-analytics-monitor
# Status
systemctl status cloudflare-analytics-monitor
# Logs
journalctl -u cloudflare-analytics-monitor -f# Test query (dry run)
python3 scripts/cloudflare-network-analytics-monitor.py --test
# Test with custom lookback (60 minutes)
python3 scripts/cloudflare-network-analytics-monitor.py --test --lookback 60
# Run once and exit
python3 scripts/cloudflare-network-analytics-monitor.py --once# Recent events
sqlite3 db/magic_transit.db \
"SELECT event_datetime, attack_vector, source_ip, packets
FROM network_analytics_events ORDER BY id DESC LIMIT 10;"
# Events by attack vector
sqlite3 db/magic_transit.db \
"SELECT attack_vector, COUNT(*)
FROM network_analytics_events GROUP BY attack_vector;"
# Events today
sqlite3 db/magic_transit.db \
"SELECT COUNT(*) FROM network_analytics_events
WHERE date(notified_at) = date('now');"CREATE TABLE network_analytics_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
event_hash TEXT UNIQUE NOT NULL,
attack_id TEXT,
event_datetime DATETIME,
attack_vector TEXT,
rule_name TEXT,
rule_id TEXT,
source_ip TEXT,
source_port INTEGER,
destination_ip TEXT,
destination_port INTEGER,
protocol TEXT,
tcp_flags TEXT,
colo_code TEXT,
colo_country TEXT,
packets INTEGER,
bits INTEGER,
outcome TEXT,
mitigation_reason TEXT,
notified_at DATETIME DEFAULT CURRENT_TIMESTAMP,
raw_data JSON
);Deduplication: Events are deduplicated using SHA256 hash of:
- datetime + attackId + sourceIP + destIP + destPort
| Protection | Description |
|---|---|
Restart=always |
Systemd auto-restart on crash |
RestartSec=30 |
Wait 30s before restart |
| Cron Watchdog | External check every 5 minutes |
Note: WatchdogSec removed - script doesn't implement sd_notify heartbeat.
- Check API token has
Account.Account Analyticspermission - Verify account ID in
config/settings.json - Try increasing lookback:
--lookback 60 - Check if GOLINE prefix filter is too restrictive
# Check GeoIP2 package
python3 -c "import geoip2; print('OK')"
# Check database files exist
ls -la /usr/share/GeoIP/
# Test GeoIP lookup
python3 -c "
import geoip2.database
reader = geoip2.database.Reader('/usr/share/GeoIP/GeoIP2-City.mmdb')
result = reader.city('8.8.8.8')
print(f'{result.city.name}, {result.country.name}')
"# Check systemd logs
journalctl -u cloudflare-analytics-monitor -n 100 --no-pager
# Check log file
tail -100 logs/network-analytics-monitor.log- Dashboard Preference Sync - Reads "My prefixes only" toggle from dashboard
- New file:
config/dashboard_prefs.jsonstores user preference - Toggle ON: Only notify for GOLINE prefixes (185.54.x.x, 2a02:4460:x)
- Toggle OFF: Notify for all traffic including Cloudflare anycast
- Preference read on each poll (no restart needed)
- New file:
- Prefix list split - Separate MY_PREFIXES and ALL_PREFIXES lists
- Dynamic filtering -
is_notifiable_ip()checks against current preference
- Cloudflare Anycast Visibility - Added Cloudflare anycast prefixes to destination filter
- New prefixes: 162.159.0.0/16, 172.64.0.0/13, 104.16.0.0/13
- Shows Magic Transit pass-through traffic
- Complete visibility of all DDoS mitigation events
- Removed System section from startup message (hostname, uptime, Python version)
- Last attack emoji - Added 💥 before Type line
- Alignment fix - Removed extra spaces before emoji
- European date format - All dates now DD/MM/YYYY HH:MM
- Shutdown message - Updated to use new stats format
- Fixed get_last_attack() - Was using wrong column name (event_datetime → created_at)
- Last attack details - Now shows datetime, vector, Gbps, target IP
- Clearer stats labels - Attacks (total/month) and Mitigations (events count)
- Last attack on two lines - Better readability
- Enhanced startup message with:
- Version number
- System info (hostname, uptime, Python version)
- BGP prefix status from Cloudflare API
- Attack history from database
- Services health status (systemd)
- Cloudflare Anycast Visibility - Added Cloudflare anycast prefixes to destination filter
- New prefixes: 162.159.0.0/16, 172.64.0.0/13, 104.16.0.0/13
- Shows Magic Transit pass-through traffic (attacks targeting Cloudflare IPs)
- Complete visibility of all DDoS mitigation events
- Polling visibility - Changed "no events" log from DEBUG to INFO for better monitoring
- Enhanced startup message - BGP status, attack history, services health
- European date format - DD/MM/YYYY throughout, shutdown message with stats
- Source ASN/Country - Added to GraphQL query and DB schema
- Enhanced startup message - System info, BGP status, last attack
- GeoIP info in startup - Shows DB type and update date
- GeoIP DB type in footer - Notifications show Commercial or Free
- GeoIP fallback - Supports both commercial (GeoIP2) and free (GeoLite2) databases
- Multiple search paths - /usr/share/GeoIP and /var/lib/GeoIP
- GeoIP in aggregated notifications - Top source IPs show country code and ASN
- GeoIP2 Integration - Source IP geolocation and ASN info
- Individual events show: country, city, ASN, organization
- Spoofed IP detection (private/reserved ranges)
- Uses GeoIP2-City.mmdb and GeoLite2-ASN.mmdb
- Enhanced notifications - Spoofed IP detection, hide Unknown fields, edge locations
- GOLINE prefix filter - Only notify for traffic to 185.54.80.0/22 and 2a02:4460::/32
- Increased lookback - Changed from 10 to 15 minutes
- Removed WatchdogSec - Script doesn't implement sd_notify
- High Availability setup with systemd protections
- Initial release
Documentation v1.3.10 - 2026-02-02 - GOLINE SOC