diff --git a/docker/routlin-dash/app/pages/dnsblocking/view.py b/docker/routlin-dash/app/pages/dnsblocking/view.py
index ce150b0..5e98bb6 100644
--- a/docker/routlin-dash/app/pages/dnsblocking/view.py
+++ b/docker/routlin-dash/app/pages/dnsblocking/view.py
@@ -36,8 +36,20 @@ def _dnsblocking_log_tail(cfg):
return '(error reading log)', ''
+WARN_ICON = '
'
+
+
+def _last_dl_time():
+ path = f'{config_utils.BLOCKLISTS_DIR}/.last-dl'
+ try:
+ return int(open(path).read().strip())
+ except Exception:
+ return None
+
+
def blocklist_stats_html(cfg):
- db_rows = config_utils._bl_db_rows()
+ db_rows = config_utils._bl_db_rows()
+ last_dl = _last_dl_time()
rows = ''
for bl in cfg.get('dns_blocking', {}).get('blocklists', []):
name = bl.get('name', '')
@@ -53,6 +65,7 @@ def blocklist_stats_html(cfg):
except Exception:
size_str = '-'
last_refreshed = 'Local'
+ warn = ''
else:
fetched_at = db.get('fetched_at')
if fetched_at:
@@ -66,14 +79,19 @@ def blocklist_stats_html(cfg):
bl_path = f'{config_utils.BLOCKLISTS_DIR}/{save_as}' if save_as else ''
try:
size_str = config_utils.fmt_bytes(os.path.getsize(bl_path))
+ file_mtime = int(os.path.getmtime(bl_path))
except Exception:
- size_str = '-'
+ size_str = '-'
+ file_mtime = None
+ warn = ''
+ if last_dl and file_mtime is not None and file_mtime < last_dl:
+ warn = WARN_ICON
rows += (
'
'
f'| {factory.e(name)} | '
f'{entries} | '
f'{size_str} | '
- f'{factory.e(last_refreshed)} | '
+ f'{factory.e(last_refreshed)}{warn} | '
'
'
)
if not rows:
diff --git a/routlin/dl_blocklists.py b/routlin/dl_blocklists.py
index 5ef4d88..d4d1cc7 100644
--- a/routlin/dl_blocklists.py
+++ b/routlin/dl_blocklists.py
@@ -64,11 +64,16 @@ def download_blocklists(data):
return not any_fail
+LAST_DL_FILE = BLOCKLIST_DIR / ".last-dl"
+
+
def main():
check_root()
data = load_config()
print("Downloading blocklists ==============================================")
success = download_blocklists(data)
+ BLOCKLIST_DIR.mkdir(exist_ok=True)
+ LAST_DL_FILE.write_text(str(int(__import__('time').time())))
if not success:
print("WARNING: One or more downloads failed.")
sys.exit(1)
diff --git a/routlin/health.py b/routlin/health.py
index 282a46d..e12e73f 100644
--- a/routlin/health.py
+++ b/routlin/health.py
@@ -515,27 +515,30 @@ def check_configurations(data):
pass
# --- Blocklist file freshness ---
- now = datetime.now(timezone.utc).timestamp()
+ now = datetime.now(timezone.utc).timestamp()
+ bl_library = {bl["name"]: bl for bl in data.get("dns_blocking", {}).get("blocklists", [])}
+ needed = set()
for vlan in vlans:
- names = vlan.get("use_blocklists", [])
- if not names:
+ needed.update(vlan.get("use_blocklists", []))
+ for name in sorted(needed):
+ bl = bl_library.get(name)
+ if not bl or bl.get("bl_type") == "local":
continue
- vlan_name = vlan["name"]
- path = _vlan_hosts_file(vlan)
- label = ", ".join(sorted(names))
- if not path.exists():
+ save_as = bl.get("save_as", "")
+ path = BLOCKLIST_DIR / save_as if save_as else None
+ if not path or not path.exists():
results.append(problem(
- f"blocklist_{vlan_name}", f"blocklist ({vlan_name})", "warning",
- f"Blocklist hosts file for '{vlan_name}' does not exist.",
- "Run `sudo python3 dl_blocklists.py && sudo python3 core.py --merge-blocklists`."))
+ f"blocklist_{name}", f"blocklist ({name})", "warning",
+ f"Blocklist file for '{name}' has not been downloaded.",
+ "Run `sudo python3 dl_blocklists.py`."))
elif now - path.stat().st_mtime > BLOCKLIST_STALE_SECS:
age_h = int((now - path.stat().st_mtime) / 3600)
results.append(problem(
- f"blocklist_{vlan_name}", f"blocklist ({vlan_name})", "warning",
- f"Blocklist hosts file for '{vlan_name}' is {age_h}h old (threshold 36h).",
- "Run `sudo python3 dl_blocklists.py && sudo python3 core.py --merge-blocklists`."))
+ f"blocklist_{name}", f"blocklist ({name})", "warning",
+ f"Blocklist '{name}' is {age_h}h old (threshold 36h).",
+ "Run `sudo python3 dl_blocklists.py`."))
else:
- results.append(ok(f"blocklist_{vlan_name}", f"blocklist ({vlan_name})"))
+ results.append(ok(f"blocklist_{name}", f"blocklist ({name})"))
# --- Disk space ---
try: