Development

This commit is contained in:
Matthew Grotke 2026-06-09 13:52:07 -04:00
parent eabded2ef2
commit 836f4557f2
4 changed files with 20 additions and 5 deletions

View file

@ -111,6 +111,21 @@ In all modes, captive portal behavior is a per-VLAN flag, consistent with Routli
--- ---
## Feature 10: Usage Rate Monitoring and Automatic Suspension
Routlin Pro will track inbound and outbound traffic rates per external IP address and automatically suspend connections that exceed configurable thresholds.
- **Per-IP rate monitoring** - real-time tracking of bandwidth consumption by external source/destination IP
- **Configurable rate limits** - set thresholds by bytes per second, requests per second, or connection count within a rolling time window
- **Automatic suspension** - IPs exceeding limits are temporarily blocked via nftables; the block duration is configurable (e.g. 5 minutes, 1 hour, permanent until manually cleared)
- **Dashboard visibility** - live view of top external IPs by usage, with current rate, total bytes transferred, and suspension status
- **Allowlist** - trusted IPs (CDNs, VPN endpoints, remote offices) can be exempted from rate enforcement
- **Alerting** - optional notifications when an IP is suspended, including the triggering rule and measured rate
Designed to protect against bandwidth abuse, accidental runaway processes, and low-level denial-of-service from external sources without requiring a full IPS deployment.
---
## Feature 9: Mobile-Aware Dashboard Layout ## Feature 9: Mobile-Aware Dashboard Layout
Routlin Pro will include a responsive, mobile-optimized layout for the entire dashboard, allowing administrators to monitor and manage their network from a phone or tablet. Routlin Pro will include a responsive, mobile-optimized layout for the entire dashboard, allowing administrators to monitor and manage their network from a phone or tablet.

View file

@ -84,7 +84,7 @@
} }
}, },
{ {
"label": "Record", "label": "Recorded",
"field": "dnsmasq_log_queries", "field": "dnsmasq_log_queries",
"class": "col-narrow", "class": "col-narrow",
"render": "badge_yes_no", "render": "badge_yes_no",

View file

@ -57,7 +57,7 @@
"type": "stat_card", "type": "stat_card",
"label": "Queries Blocked", "label": "Queries Blocked",
"value": "%STAT_BLOCKED_TODAY%", "value": "%STAT_BLOCKED_TODAY%",
"sub": "since midnight", "sub": "in last 24h",
"variant": "warning" "variant": "warning"
}, },
{ {

View file

@ -8,7 +8,7 @@ from pages.dhcpleases.view import live_dhcp_leases
def get_dnsmasq_stats(): def get_dnsmasq_stats():
stats = {'queries': '-', 'hits': '-', 'hit_rate': '-', 'forwarded': '-', 'auth': '-', 'tcp_peak': '-'} stats = {'queries': '-', 'hits': '-', 'hit_rate': '-', 'forwarded': '-', 'auth': '-', 'tcp_peak': '-'}
out = factory.run('journalctl -u dnsmasq -n 200 --no-pager 2>/dev/null') out = factory.run("journalctl -u 'dnsmasq-routlin-*' -n 200 --no-pager 2>/dev/null")
for line in reversed(out.splitlines()): for line in reversed(out.splitlines()):
if 'queries forwarded' in line: if 'queries forwarded' in line:
m = re.search(r'queries forwarded (\d+)', line) m = re.search(r'queries forwarded (\d+)', line)
@ -36,8 +36,8 @@ def get_dnsmasq_stats():
def count_blocked_today(): def count_blocked_today():
out = factory.run("journalctl -u dnsmasq --since today --no-pager 2>/dev/null | grep -c 'is NXDOMAIN'") out = factory.run("journalctl -u 'dnsmasq-routlin-*' --since '24 hours ago' --no-pager 2>/dev/null | grep -c ' is 0\\.0\\.0\\.0'")
return out or '0' return out.strip() or '0'
def count_blocked_domains(): def count_blocked_domains():