Compare commits
2
Commits
0d1cd21468
...
55dad05652
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55dad05652 | ||
|
|
c2eba88ac8 |
No files matched your search
+1
-2
@@ -40,7 +40,7 @@ ROUTER_PASSWORD=change-me
|
|||||||
BLOCKLIST_NAME=Blocked
|
BLOCKLIST_NAME=Blocked
|
||||||
|
|
||||||
# Comma-separated address lists that are treated as whitelisted (never blocked).
|
# Comma-separated address lists that are treated as whitelisted (never blocked).
|
||||||
WHITELIST_NAMES=Cloudflare,Openfactory
|
WHITELIST_NAMES=Cloudflare,Init7
|
||||||
|
|
||||||
# --- WHOIS subnet consolidation --------------------------------------------
|
# --- WHOIS subnet consolidation --------------------------------------------
|
||||||
|
|
||||||
@@ -79,7 +79,6 @@ DEFAULT_TOP_PATHS=20
|
|||||||
|
|
||||||
# --- Whitelist sources -----------------------------------------------------
|
# --- Whitelist sources -----------------------------------------------------
|
||||||
|
|
||||||
OPENFACTORY_URL=https://openfactory.net/geofeed.csv
|
|
||||||
CLOUDFLARE_URL_V4=https://www.cloudflare.com/ips-v4
|
CLOUDFLARE_URL_V4=https://www.cloudflare.com/ips-v4
|
||||||
CLOUDFLARE_URL_V6=https://www.cloudflare.com/ips-v6
|
CLOUDFLARE_URL_V6=https://www.cloudflare.com/ips-v6
|
||||||
PALOALTO_URL=https://docs-cortex.paloaltonetworks.com/r/1/Cortex-Xpanse/Scanning-activity
|
PALOALTO_URL=https://docs-cortex.paloaltonetworks.com/r/1/Cortex-Xpanse/Scanning-activity
|
||||||
@@ -63,8 +63,7 @@ intrusion-detection/
|
|||||||
│ ├── static/ style.css + app.js (dark-theme UI)
|
│ ├── static/ style.css + app.js (dark-theme UI)
|
||||||
│ └── templates/ Jinja2 page templates (dashboard, scan, reports, …)
|
│ └── templates/ Jinja2 page templates (dashboard, scan, reports, …)
|
||||||
├── data/ whitelist source files (cached locally)
|
├── data/ whitelist source files (cached locally)
|
||||||
│ ├── openfactory/
|
│ ├── init7/ (ranges built into app/utils/whitelists.py — no geofeed)
|
||||||
│ │ └── geofeed.csv
|
|
||||||
│ ├── cloudflare/
|
│ ├── cloudflare/
|
||||||
│ │ ├── ips-v4.txt
|
│ │ ├── ips-v4.txt
|
||||||
│ │ └── ips-v6.txt
|
│ │ └── ips-v6.txt
|
||||||
@@ -135,13 +134,26 @@ production can set the same variables via the OS and skip `.env` entirely.
|
|||||||
| `ROUTER_USER` | `admin` | MikroTik connection |
|
| `ROUTER_USER` | `admin` | MikroTik connection |
|
||||||
| `ROUTER_PASSWORD` | _(set in .env)_ | MikroTik connection |
|
| `ROUTER_PASSWORD` | _(set in .env)_ | MikroTik connection |
|
||||||
| `BLOCKLIST_NAME` | `Blocked` | MikroTik address list |
|
| `BLOCKLIST_NAME` | `Blocked` | MikroTik address list |
|
||||||
| `WHITELIST_NAMES` | `Cloudflare,Openfactory` | MikroTik whitelists |
|
| `WHITELIST_NAMES` | `Cloudflare,Init7` | MikroTik whitelists |
|
||||||
| `WEB_HOST` | `127.0.0.1` | web UI bind host |
|
| `WEB_HOST` | `127.0.0.1` | web UI bind host |
|
||||||
| `WEB_PORT` | `54666` | web UI port |
|
| `WEB_PORT` | `54666` | web UI port |
|
||||||
|
|
||||||
See `.env.example` for the complete list of supported variables (WHOIS
|
See `.env.example` for the complete list of supported variables (WHOIS
|
||||||
tuning, scan thresholds, whitelist source URLs, and more).
|
tuning, scan thresholds, whitelist source URLs, and more).
|
||||||
|
|
||||||
|
### Network context (2026-09-08)
|
||||||
|
|
||||||
|
Connectivity provider switched Openfactory → Init7 on 2026-09-08:
|
||||||
|
|
||||||
|
- WAN IPv4: `77.74.80.159/32` (init7 `77.74.80.0/24`, "Hybrid7-NET").
|
||||||
|
- IPv6: delegated `/48` `2001:1620:549f::/48` (init7 allocation `2001:1620::/30`).
|
||||||
|
- Upstream DNS: `77.109.128.2`, `213.144.129.20`.
|
||||||
|
|
||||||
|
The `Openfactory` whitelist (old AS58299 geofeed) is obsolete and must be
|
||||||
|
replaced with an `Init7` whitelist — see
|
||||||
|
[`.github/instructions/TODO.md`](.github/instructions/TODO.md) for the
|
||||||
|
switchover plan and the verified init7 CIDR ranges.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
|
|||||||
+1
-1
@@ -11,5 +11,5 @@ This directory contains data files used by the `allucanget-ids` Intrusion Detect
|
|||||||
- [MikroTik RouterOS IPv6 Firewall rules](./mikrotik/firewall_ipv6.json): Current MikroTik RouterOS IPv6 firewall rules.
|
- [MikroTik RouterOS IPv6 Firewall rules](./mikrotik/firewall_ipv6.json): Current MikroTik RouterOS IPv6 firewall rules.
|
||||||
- [MikroTik RouterOS IPv4 address list](./mikrotik/address_list_ipv4.json): Current MikroTik RouterOS IPv4 address list.
|
- [MikroTik RouterOS IPv4 address list](./mikrotik/address_list_ipv4.json): Current MikroTik RouterOS IPv4 address list.
|
||||||
- [MikroTik RouterOS IPv6 address list](./mikrotik/address_list_ipv6.json): Current MikroTik RouterOS IPv6 address list.
|
- [MikroTik RouterOS IPv6 address list](./mikrotik/address_list_ipv6.json): Current MikroTik RouterOS IPv6 address list.
|
||||||
- [Openfactory Geofeed](./openfactory/geofeed.csv): Contains Openfactory IP addresses and associated geolocation data from `https://openfactory.net/geofeed.csv`. Used for identifying and whitelisting traffic from known Openfactory sources.
|
- [Openfactory Geofeed](./openfactory/geofeed.csv): **Obsolete since 2026-09-08** (provider switched to Init7). Kept for historical reference; the replacement `Init7` ranges are documented in the switchover plan (`.github/instructions/TODO.md`).
|
||||||
- [PaloAlto Scanner IP list](./paloalto/scanner-ips.txt): List of known PaloAlto scanner IP addresses from `https://docs-cortex.paloaltonetworks.com/r/1/Cortex-Xpanse/Scanning-activity`, used for whitelisting traffic from PaloAlto scanners. !NOTE: This list can not be scraped easily (Javascript-based), so it is maintained manually and may be outdated. Please verify the list against the official source if needed.
|
- [PaloAlto Scanner IP list](./paloalto/scanner-ips.txt): List of known PaloAlto scanner IP addresses from `https://docs-cortex.paloaltonetworks.com/r/1/Cortex-Xpanse/Scanning-activity`, used for whitelisting traffic from PaloAlto scanners. !NOTE: This list can not be scraped easily (Javascript-based), so it is maintained manually and may be outdated. Please verify the list against the official source if needed.
|
||||||
+1
-1
@@ -272,7 +272,7 @@ def get_scan_report(report_dir: str = REPORT_DIR) -> dict[str, list[str]]:
|
|||||||
"/ip firewall address-list": [],
|
"/ip firewall address-list": [],
|
||||||
"/ipv6 firewall address-list": [],
|
"/ipv6 firewall address-list": [],
|
||||||
}
|
}
|
||||||
# add list=Cloudflare or list=Openfactory to whitelist sections, list=Blocked to blocked section
|
# add list=Cloudflare or list=Init7 to whitelist sections, list=Blocked to blocked section
|
||||||
with open(report_path, "r", encoding="utf-8") as f:
|
with open(report_path, "r", encoding="utf-8") as f:
|
||||||
current_section = None
|
current_section = None
|
||||||
for line in f:
|
for line in f:
|
||||||
|
|||||||
@@ -73,7 +73,8 @@ REPORT_RETENTION_MAX_FILES = int(
|
|||||||
# Log sources (configurable via environment)
|
# Log sources (configurable via environment)
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
COPYPARTY_LOG_PATH = os.environ.get("COPYPARTY_LOG_PATH", "/srv/projects/copyparty")
|
COPYPARTY_LOG_PATH = os.environ.get(
|
||||||
|
"COPYPARTY_LOG_PATH", "/srv/projects/copyparty")
|
||||||
NPM_LOG_PATH = os.environ.get("NPM_LOG_PATH", "/mnt/backups/npm/logs")
|
NPM_LOG_PATH = os.environ.get("NPM_LOG_PATH", "/mnt/backups/npm/logs")
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -91,7 +92,7 @@ BLOCKLIST_NAME = os.environ.get("BLOCKLIST_NAME", "Blocked")
|
|||||||
WHITELIST_NAMES = [
|
WHITELIST_NAMES = [
|
||||||
name.strip()
|
name.strip()
|
||||||
for name in os.environ.get(
|
for name in os.environ.get(
|
||||||
"WHITELIST_NAMES", "Cloudflare,Openfactory").split(",")
|
"WHITELIST_NAMES", "Cloudflare,Init7").split(",")
|
||||||
if name.strip()
|
if name.strip()
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -131,8 +132,6 @@ WEB_PORT = int(os.environ.get("WEB_PORT", "54666"))
|
|||||||
# Whitelist sources (configurable via environment)
|
# Whitelist sources (configurable via environment)
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
OPENFACTORY_URL = os.environ.get(
|
|
||||||
"OPENFACTORY_URL", "https://openfactory.net/geofeed.csv")
|
|
||||||
CLOUDFLARE_URL_V4 = os.environ.get(
|
CLOUDFLARE_URL_V4 = os.environ.get(
|
||||||
"CLOUDFLARE_URL_V4", "https://www.cloudflare.com/ips-v4")
|
"CLOUDFLARE_URL_V4", "https://www.cloudflare.com/ips-v4")
|
||||||
CLOUDFLARE_URL_V6 = os.environ.get(
|
CLOUDFLARE_URL_V6 = os.environ.get(
|
||||||
@@ -143,7 +142,6 @@ PALOALTO_URL = os.environ.get(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Local whitelist files (checked before remote download)
|
# Local whitelist files (checked before remote download)
|
||||||
OPENFACTORY_FILE = os.path.join(DATA_DIR, "openfactory", "geofeed.csv")
|
|
||||||
CLOUDFLARE_V4_FILE = os.path.join(DATA_DIR, "cloudflare", "ips-v4.txt")
|
CLOUDFLARE_V4_FILE = os.path.join(DATA_DIR, "cloudflare", "ips-v4.txt")
|
||||||
CLOUDFLARE_V6_FILE = os.path.join(DATA_DIR, "cloudflare", "ips-v6.txt")
|
CLOUDFLARE_V6_FILE = os.path.join(DATA_DIR, "cloudflare", "ips-v6.txt")
|
||||||
PALOALTO_FILE = os.path.join(DATA_DIR, "paloalto", "scanner-ips.txt")
|
PALOALTO_FILE = os.path.join(DATA_DIR, "paloalto", "scanner-ips.txt")
|
||||||
+19
-19
@@ -23,8 +23,6 @@ from .constants import (
|
|||||||
CLOUDFLARE_URL_V6,
|
CLOUDFLARE_URL_V6,
|
||||||
CLOUDFLARE_V4_FILE,
|
CLOUDFLARE_V4_FILE,
|
||||||
CLOUDFLARE_V6_FILE,
|
CLOUDFLARE_V6_FILE,
|
||||||
OPENFACTORY_FILE,
|
|
||||||
OPENFACTORY_URL,
|
|
||||||
PALOALTO_FILE,
|
PALOALTO_FILE,
|
||||||
PALOALTO_URL,
|
PALOALTO_URL,
|
||||||
)
|
)
|
||||||
@@ -40,15 +38,26 @@ CIDR_RE = re.compile(
|
|||||||
# Local file paths (checked first, before remote download)
|
# Local file paths (checked first, before remote download)
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
# (paths live in app/constants.py as OPENFACTORY_FILE, CLOUDFLARE_V4_FILE,
|
# (paths live in app/constants.py as CLOUDFLARE_V4_FILE,
|
||||||
# CLOUDFLARE_V6_FILE, PALOALTO_FILE; URLs as OPENFACTORY_URL, ...)
|
# CLOUDFLARE_V6_FILE, PALOALTO_FILE; URLs as CLOUDFLARE_URL_V4, ...)
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Built-in fallback CIDR lists
|
# Built-in fallback CIDR lists
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
#: Openfactory AS58299 colocation IP range (https://openfactory.net/geofeed.csv)
|
#: Init7 (Switzerland) Ltd. ranges — AS13030, verified via RIPE RDAP 2026-09-08.
|
||||||
OPENFACTORY_IPV4 = ["5.226.144.0/21"]
|
#: Includes the Hybrid7 WAN /24 (router WAN 77.74.80.159), init7 DNS
|
||||||
|
#: infrastructure, and the PPPoE gateway. init7 publishes no geofeed, so
|
||||||
|
#: these are maintained here rather than downloaded.
|
||||||
|
INIT7_IPV4 = [
|
||||||
|
"77.74.80.0/24", # Hybrid7 WAN /24
|
||||||
|
"77.109.128.0/18", # init7 DNS / infrastructure
|
||||||
|
"213.144.128.0/19", # init7 DNS / infrastructure
|
||||||
|
"5.180.132.0/22", # init7 PPPoE gateway
|
||||||
|
]
|
||||||
|
|
||||||
|
#: init7 IPv6 allocation (contains delegated /48 2001:1620:549f::/48)
|
||||||
|
INIT7_IPV6 = ["2001:1620::/30"]
|
||||||
|
|
||||||
#: https://www.cloudflare.com/ips-v4
|
#: https://www.cloudflare.com/ips-v4
|
||||||
CLOUDFLARE_IPV4 = [
|
CLOUDFLARE_IPV4 = [
|
||||||
@@ -85,7 +94,7 @@ PALOALTO_IPV6 = [
|
|||||||
|
|
||||||
#: address-list name -> CIDR ranges (v4 + v6 mixed, split at render time)
|
#: address-list name -> CIDR ranges (v4 + v6 mixed, split at render time)
|
||||||
WHITELISTS: dict[str, list[str]] = {
|
WHITELISTS: dict[str, list[str]] = {
|
||||||
"Openfactory": OPENFACTORY_IPV4,
|
"Init7": INIT7_IPV4 + INIT7_IPV6,
|
||||||
"Cloudflare": CLOUDFLARE_IPV4 + CLOUDFLARE_IPV6,
|
"Cloudflare": CLOUDFLARE_IPV4 + CLOUDFLARE_IPV6,
|
||||||
"PaloAlto": PALOALTO_IPV4 + PALOALTO_IPV6,
|
"PaloAlto": PALOALTO_IPV4 + PALOALTO_IPV6,
|
||||||
}
|
}
|
||||||
@@ -141,9 +150,7 @@ def _load_local_whitelists() -> dict[str, list[str]]:
|
|||||||
successfully parsed CIDRs are included.
|
successfully parsed CIDRs are included.
|
||||||
"""
|
"""
|
||||||
out: dict[str, list[str]] = {}
|
out: dict[str, list[str]] = {}
|
||||||
cidrs = _read_local_file(OPENFACTORY_FILE)
|
# Init7 has no published geofeed; its ranges are built-in (INIT7_IPV4/6).
|
||||||
if cidrs:
|
|
||||||
out["Openfactory"] = cidrs
|
|
||||||
cf_v4 = _read_local_file(CLOUDFLARE_V4_FILE)
|
cf_v4 = _read_local_file(CLOUDFLARE_V4_FILE)
|
||||||
cf_v6 = _read_local_file(CLOUDFLARE_V6_FILE)
|
cf_v6 = _read_local_file(CLOUDFLARE_V6_FILE)
|
||||||
if cf_v4 or cf_v6:
|
if cf_v4 or cf_v6:
|
||||||
@@ -190,14 +197,7 @@ def _download_whitelists() -> dict[str, list[str]]:
|
|||||||
Saves each download to the corresponding local file on success.
|
Saves each download to the corresponding local file on success.
|
||||||
"""
|
"""
|
||||||
out: dict[str, list[str]] = {}
|
out: dict[str, list[str]] = {}
|
||||||
try:
|
# Init7 has no published geofeed; its ranges are built-in (INIT7_IPV4/6).
|
||||||
text = _download_text(OPENFACTORY_URL)
|
|
||||||
cidrs = extract_cidrs(text)
|
|
||||||
if cidrs:
|
|
||||||
out["Openfactory"] = cidrs
|
|
||||||
_save_local_file(OPENFACTORY_FILE, text)
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error downloading Openfactory whitelist: {e}")
|
|
||||||
try:
|
try:
|
||||||
text_v4 = _download_text(CLOUDFLARE_URL_V4)
|
text_v4 = _download_text(CLOUDFLARE_URL_V4)
|
||||||
text_v6 = _download_text(CLOUDFLARE_URL_V6)
|
text_v6 = _download_text(CLOUDFLARE_URL_V6)
|
||||||
@@ -242,7 +242,7 @@ def update_whitelists() -> None:
|
|||||||
|
|
||||||
# Start from built-in fallbacks, then layer local, then remote
|
# Start from built-in fallbacks, then layer local, then remote
|
||||||
WHITELISTS = {
|
WHITELISTS = {
|
||||||
"Openfactory": OPENFACTORY_IPV4,
|
"Init7": INIT7_IPV4 + INIT7_IPV6,
|
||||||
"Cloudflare": CLOUDFLARE_IPV4 + CLOUDFLARE_IPV6,
|
"Cloudflare": CLOUDFLARE_IPV4 + CLOUDFLARE_IPV6,
|
||||||
"PaloAlto": PALOALTO_IPV4 + PALOALTO_IPV6,
|
"PaloAlto": PALOALTO_IPV4 + PALOALTO_IPV6,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Shell script to be run as cron job to copy npm logs to backup location.
|
||||||
|
|
||||||
|
# Stop npm service to ensure logs are not being written to while copying.
|
||||||
|
systemctl stop npm
|
||||||
|
|
||||||
|
# Only copy new/changed log files to avoid re-copying existing backups.
|
||||||
|
# --ignore-existing: never overwrite files already present in the destination.
|
||||||
|
# -c: compare files by checksum so matching files are not re-written.
|
||||||
|
# -P: preserve permissions + show progress.
|
||||||
|
rsync -qcP --ignore-existing /data/logs/*access* /data/logs/*error* /mnt/backups/npm/
|
||||||
|
|
||||||
|
# Start npm service again after copying logs.
|
||||||
|
systemctl start npm
|
||||||
Reference in new issue
Block a user