Fixes missing requests + cross device error + cron folder error
This commit is contained in:
parent
17b80fa446
commit
d97348cd17
@ -7,6 +7,12 @@ RUN apt-get update && apt-get install -y \
|
||||
tzdata \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install python dependencies
|
||||
RUN pip install --no-cache-dir requests
|
||||
|
||||
# Create crontabs directory (if needed)
|
||||
RUN mkdir -p /etc/crontabs
|
||||
|
||||
# Copy scripts
|
||||
COPY update-blocklist.py /usr/local/bin/update-blocklist.py
|
||||
COPY entrypoint.py /usr/local/bin/entrypoint.py
|
||||
@ -17,7 +23,7 @@ RUN chmod +x /usr/local/bin/update-blocklist.py /usr/local/bin/entrypoint.py
|
||||
# Set default timezone (can be overridden with TZ env var)
|
||||
ENV TZ=UTC
|
||||
|
||||
# Configure timezone (tzdata) — important for /usr/share/zoneinfo/*
|
||||
# Configure timezone (tzdata)
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
# Set entrypoint
|
||||
|
@ -73,6 +73,6 @@
|
||||
5. **Check logs to verify updates**
|
||||
|
||||
```bash
|
||||
docker-compose logs -f
|
||||
docker compose logs -f
|
||||
```
|
||||
|
||||
|
@ -14,6 +14,20 @@ logging.basicConfig(
|
||||
ADGUARD_YAML = Path("/adguard/AdGuardHome.yaml")
|
||||
FIRST_BACKUP = Path("/adguard/AdGuardHome.yaml.first-start.bak")
|
||||
|
||||
def setup_cron():
|
||||
cron_expr = os.getenv("BLOCKLIST_CRON", "0 6 * * *")
|
||||
cron_line = f"{cron_expr} root /usr/local/bin/update-blocklist.py\n"
|
||||
cron_dir = "/etc/crontabs"
|
||||
cron_file = f"{cron_dir}/root"
|
||||
|
||||
logging.info(f"Setting cron job: {cron_line.strip()}")
|
||||
|
||||
# Ensure cron directory exists
|
||||
os.makedirs(cron_dir, exist_ok=True)
|
||||
|
||||
with open(cron_file, "w") as f:
|
||||
f.write(cron_line)
|
||||
|
||||
def backup_first_start():
|
||||
if not FIRST_BACKUP.exists():
|
||||
logging.info("Creating first start backup...")
|
||||
@ -34,17 +48,9 @@ def run_initial_update():
|
||||
logging.error(f"Initial update script failed: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
def setup_cron():
|
||||
cron_expr = os.getenv("BLOCKLIST_CRON", "0 6 * * *")
|
||||
cron_line = f"{cron_expr} root /usr/local/bin/update-blocklist.py\n"
|
||||
cron_file = "/etc/crontabs/root"
|
||||
logging.info(f"Setting cron job: {cron_line.strip()}")
|
||||
with open(cron_file, "w") as f:
|
||||
f.write(cron_line)
|
||||
|
||||
def start_cron_foreground():
|
||||
logging.info("Starting cron in foreground...")
|
||||
os.execvp("crond", ["crond", "-f"])
|
||||
os.execvp("cron", ["cron", "-f"])
|
||||
|
||||
def main():
|
||||
# Check AdGuardHome.yaml exists
|
||||
|
@ -1,156 +1,117 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import logging
|
||||
import re
|
||||
import requests
|
||||
from pathlib import Path
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='[update-blocklist] %(levelname)s: %(message)s',
|
||||
stream=sys.stdout
|
||||
stream=sys.stdout,
|
||||
)
|
||||
|
||||
# Config / variables
|
||||
ADGUARD_YAML = Path("/adguard/AdGuardHome.yaml")
|
||||
FIRST_BACKUP = Path("/adguard/AdGuardHome.yaml.first-start.bak")
|
||||
LAST_CRON_BACKUP = Path("/adguard/AdGuardHome.yaml.last-cron.bak")
|
||||
TMP_YAML = ADGUARD_YAML.parent / (ADGUARD_YAML.name + ".tmp")
|
||||
MANUAL_IPS_FILE = Path("/adguard/manually_blocked_ips.conf")
|
||||
CIDR_BASE_URL = "https://raw.githubusercontent.com/vulnebify/cidre/main/output/cidr/ipv4"
|
||||
COUNTRIES = os.getenv("BLOCK_COUNTRIES", "")
|
||||
DOCKER_API_URL = os.getenv("DOCKER_API_URL", "http://socket-proxy-adguard:2375")
|
||||
CONTAINER_NAME = os.getenv("ADGUARD_CONTAINER_NAME", "adguard-home")
|
||||
TMP_YAML = Path("/tmp/AdGuardHome.yaml")
|
||||
TMP_DIR = Path("/tmp/cidr")
|
||||
|
||||
def backup_first_start():
|
||||
def backup_files():
|
||||
if not FIRST_BACKUP.exists():
|
||||
logging.info(f"Creating first-start backup: {FIRST_BACKUP}")
|
||||
shutil.copy2(ADGUARD_YAML, FIRST_BACKUP)
|
||||
FIRST_BACKUP.write_text(ADGUARD_YAML.read_text())
|
||||
else:
|
||||
logging.info("First-start backup already exists, skipping.")
|
||||
|
||||
def backup_last_cron():
|
||||
logging.info(f"Creating last-cron backup: {LAST_CRON_BACKUP}")
|
||||
shutil.copy2(ADGUARD_YAML, LAST_CRON_BACKUP)
|
||||
LAST_CRON_BACKUP.write_text(ADGUARD_YAML.read_text())
|
||||
|
||||
def download_cidr_lists(countries):
|
||||
if not countries:
|
||||
logging.error("No countries specified in BLOCK_COUNTRIES environment variable.")
|
||||
sys.exit(1)
|
||||
|
||||
TMP_DIR.mkdir(parents=True, exist_ok=True)
|
||||
all_ips = []
|
||||
|
||||
codes = [c.strip().lower() for c in countries.split(",") if c.strip()]
|
||||
for code in codes:
|
||||
url = f"{CIDR_BASE_URL}/{code}.cidr"
|
||||
combined_ips = []
|
||||
for code in countries:
|
||||
url = f"{CIDR_BASE_URL}/{code.lower()}.cidr"
|
||||
logging.info(f"Downloading CIDR list for {code} from {url}")
|
||||
try:
|
||||
r = requests.get(url, timeout=15)
|
||||
r = requests.get(url, timeout=30)
|
||||
r.raise_for_status()
|
||||
lines = r.text.strip().splitlines()
|
||||
logging.info(f"Downloaded {len(lines)} CIDR entries for {code}")
|
||||
all_ips.extend(lines)
|
||||
ips = r.text.strip().splitlines()
|
||||
logging.info(f"Downloaded {len(ips)} CIDR entries for {code}")
|
||||
combined_ips.extend(ips)
|
||||
except Exception as e:
|
||||
logging.warning(f"Failed to download {url}: {e}")
|
||||
|
||||
return all_ips
|
||||
logging.warning(f"Failed to download {code}: {e}")
|
||||
return combined_ips
|
||||
|
||||
def read_manual_ips():
|
||||
ips = []
|
||||
if MANUAL_IPS_FILE.exists():
|
||||
logging.info(f"Reading manual IPs from {MANUAL_IPS_FILE}")
|
||||
try:
|
||||
with MANUAL_IPS_FILE.open() as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if re.match(r'^(\d{1,3}\.){3}\d{1,3}(/\d{1,2})?$', line):
|
||||
ips.append(line)
|
||||
else:
|
||||
logging.debug(f"Ignoring invalid manual IP line: {line}")
|
||||
logging.info(f"Read {len(ips)} valid manual IP entries")
|
||||
except Exception as e:
|
||||
logging.warning(f"Error reading manual IPs: {e}")
|
||||
valid_ips = []
|
||||
with MANUAL_IPS_FILE.open() as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
# Simple regex match for IPv4 or IPv4 CIDR
|
||||
if line and line.count('.') == 3:
|
||||
valid_ips.append(line)
|
||||
logging.info(f"Added {len(valid_ips)} manual IP entries")
|
||||
return valid_ips
|
||||
else:
|
||||
logging.info("Manual IPs file does not exist, skipping.")
|
||||
return ips
|
||||
|
||||
def format_ips_yaml_list(ips):
|
||||
return [f" - {ip}\n" for ip in ips]
|
||||
return []
|
||||
|
||||
def update_yaml_with_ips(ips):
|
||||
if not ADGUARD_YAML.exists():
|
||||
logging.error(f"AdGuardHome.yaml not found at {ADGUARD_YAML}")
|
||||
sys.exit(1)
|
||||
# Format IPs for YAML list (4 spaces indent + dash)
|
||||
formatted_ips = [f" - {ip}" for ip in ips]
|
||||
|
||||
inside_disallowed = False
|
||||
output_lines = []
|
||||
|
||||
with ADGUARD_YAML.open() as f:
|
||||
lines = f.readlines()
|
||||
|
||||
new_lines = []
|
||||
inside_disallowed = False
|
||||
ips_inserted = False
|
||||
|
||||
for line in lines:
|
||||
stripped = line.rstrip("\n")
|
||||
|
||||
if stripped.startswith(" disallowed_clients:"):
|
||||
# Write key line without any value (no [] etc)
|
||||
new_lines.append(" disallowed_clients:\n")
|
||||
# Insert ips
|
||||
if ips:
|
||||
new_lines.extend(format_ips_yaml_list(ips))
|
||||
# mark inserted
|
||||
inside_disallowed = True
|
||||
ips_inserted = True
|
||||
continue
|
||||
|
||||
if inside_disallowed:
|
||||
# skip old IP entries starting with ' - '
|
||||
if stripped.startswith(" - "):
|
||||
continue
|
||||
for line in f:
|
||||
if line.strip().startswith("disallowed_clients:"):
|
||||
# Replace existing disallowed_clients block
|
||||
output_lines.append("disallowed_clients:")
|
||||
output_lines.extend(formatted_ips)
|
||||
inside_disallowed = True
|
||||
elif inside_disallowed:
|
||||
# Skip old lines under disallowed_clients (assuming indentation)
|
||||
if line.startswith(" ") and not line.startswith(" -"):
|
||||
# This is a new section, disallowed_clients block ended
|
||||
inside_disallowed = False
|
||||
output_lines.append(line.rstrip("\n"))
|
||||
# Else skip line inside disallowed_clients block
|
||||
else:
|
||||
inside_disallowed = False
|
||||
output_lines.append(line.rstrip("\n"))
|
||||
|
||||
new_lines.append(line)
|
||||
|
||||
if not ips_inserted:
|
||||
# disallowed_clients not found - append at end
|
||||
new_lines.append("\n disallowed_clients:\n")
|
||||
if ips:
|
||||
new_lines.extend(format_ips_yaml_list(ips))
|
||||
# If the file ended while still inside disallowed_clients block, append nothing more (already done)
|
||||
|
||||
# Write to temporary YAML in same folder (to avoid cross-device rename error)
|
||||
with TMP_YAML.open("w") as f:
|
||||
f.writelines(new_lines)
|
||||
f.write("\n".join(output_lines) + "\n")
|
||||
|
||||
# Atomic replace
|
||||
TMP_YAML.replace(ADGUARD_YAML)
|
||||
logging.info(f"Updated {ADGUARD_YAML} with {len(ips)} disallowed_clients entries")
|
||||
|
||||
def restart_container():
|
||||
url = f"{DOCKER_API_URL}/containers/{CONTAINER_NAME}/restart"
|
||||
logging.info(f"Restarting container '{CONTAINER_NAME}' via {url}")
|
||||
try:
|
||||
r = requests.post(url, timeout=10)
|
||||
if r.status_code == 204:
|
||||
logging.info("Container restarted successfully.")
|
||||
else:
|
||||
logging.error(f"Failed to restart container. Status: {r.status_code} Response: {r.text}")
|
||||
except Exception as e:
|
||||
logging.error(f"Exception during container restart: {e}")
|
||||
logging.info(f"Updated {ADGUARD_YAML} with new disallowed clients list.")
|
||||
|
||||
def main():
|
||||
backup_first_start()
|
||||
backup_last_cron()
|
||||
cidr_ips = download_cidr_lists(COUNTRIES)
|
||||
if not ADGUARD_YAML.exists():
|
||||
logging.error(f"{ADGUARD_YAML} not found, exiting.")
|
||||
sys.exit(1)
|
||||
|
||||
if not COUNTRIES:
|
||||
logging.error("No countries specified in BLOCK_COUNTRIES environment variable, exiting.")
|
||||
sys.exit(1)
|
||||
|
||||
backup_files()
|
||||
|
||||
countries_list = [c.strip() for c in COUNTRIES.split(",") if c.strip()]
|
||||
cidr_ips = download_cidr_lists(countries_list)
|
||||
manual_ips = read_manual_ips()
|
||||
|
||||
combined_ips = cidr_ips + manual_ips
|
||||
if not combined_ips:
|
||||
logging.warning("No IPs to add to disallowed_clients. The list will be empty.")
|
||||
|
||||
update_yaml_with_ips(combined_ips)
|
||||
restart_container()
|
||||
logging.info("Blocklist update complete.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
Loading…
x
Reference in New Issue
Block a user