First python commit

This commit is contained in:
Djeex 2025-05-31 19:46:12 +00:00
parent 5471371401
commit 5afe9c1601
6 changed files with 235 additions and 95 deletions

View File

@ -1,10 +1,21 @@
FROM alpine:latest
FROM python:3.11-slim
RUN apk add --no-cache curl bash busybox tzdata
# Install curl and cron
RUN apt-get update && apt-get install -y curl cron && rm -rf /var/lib/apt/lists/*
COPY update-blocklist.sh /usr/local/bin/update-blocklist.sh
COPY entrypoint.sh /entrypoint.sh
# Install Python requests
RUN pip install --no-cache-dir requests
RUN chmod +x /usr/local/bin/update-blocklist.sh /entrypoint.sh
# Create adguard config dir
RUN mkdir -p /adguard
ENTRYPOINT ["/entrypoint.sh"]
# Copy update-blocklist script
COPY update-blocklist.py /usr/local/bin/update-blocklist.py
RUN chmod +x /usr/local/bin/update-blocklist.py
# Copy entrypoint script (on next step)
# Setup cron config dir
RUN mkdir -p /etc/crontabs
ENTRYPOINT ["/usr/local/bin/entrypoint.py"]

View File

@ -3,6 +3,7 @@ services:
adguard-cidre:
build: .
container_name: adguard-cidre
restart: unless-stopped
environment:
- TZ=Europe/Paris # change to your timezone
- BLOCK_COUNTRIES=cn,ru,ir # choose countries listed IP to block. Full lists here https://github.com/vulnebify/cidre/tree/main/output/cidr/ipv4

61
entrypoint.py Normal file
View File

@ -0,0 +1,61 @@
#!/usr/bin/env python3
import os
import sys
import subprocess
import logging
from pathlib import Path
logging.basicConfig(
level=logging.INFO,
format='[entrypoint] %(message)s',
stream=sys.stdout
)
ADGUARD_YAML = Path("/adguard/AdGuardHome.yaml")
FIRST_BACKUP = Path("/adguard/AdGuardHome.yaml.first-start.bak")
def backup_first_start():
if not FIRST_BACKUP.exists():
logging.info("Creating first start backup...")
FIRST_BACKUP.write_text(ADGUARD_YAML.read_text())
else:
logging.info("First start backup already exists.")
def run_initial_update():
logging.info("Running initial update-blocklist.py script...")
try:
subprocess.run(
["/usr/local/bin/update-blocklist.py"],
check=True,
stdout=sys.stdout,
stderr=sys.stderr,
)
except subprocess.CalledProcessError as e:
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"])
def main():
# Check AdGuardHome.yaml exists
if not ADGUARD_YAML.exists():
logging.error(f"{ADGUARD_YAML} not found. Exiting.")
sys.exit(1)
backup_first_start()
run_initial_update()
setup_cron()
start_cron_foreground()
if __name__ == "__main__":
main()

View File

@ -1,14 +0,0 @@
#!/bin/sh
set -e
if [ -n "$TZ" ]; then
if [ -f "/usr/share/zoneinfo/$TZ" ]; then
cp "/usr/share/zoneinfo/$TZ" /etc/localtime
echo "$TZ" > /etc/timezone
fi
fi
CRON_EXPR="${BLOCKLIST_CRON:-"0 6 * * *"}"
echo "$CRON_EXPR /usr/local/bin/update-blocklist.sh" > /etc/crontabs/root
exec crond -f -c /etc/crontabs

156
update-blocklist.py Normal file
View File

@ -0,0 +1,156 @@
#!/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
)
# 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")
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():
if not FIRST_BACKUP.exists():
logging.info(f"Creating first-start backup: {FIRST_BACKUP}")
shutil.copy2(ADGUARD_YAML, FIRST_BACKUP)
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)
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"
logging.info(f"Downloading CIDR list for {code} from {url}")
try:
r = requests.get(url, timeout=15)
r.raise_for_status()
lines = r.text.strip().splitlines()
logging.info(f"Downloaded {len(lines)} CIDR entries for {code}")
all_ips.extend(lines)
except Exception as e:
logging.warning(f"Failed to download {url}: {e}")
return all_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}")
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]
def update_yaml_with_ips(ips):
if not ADGUARD_YAML.exists():
logging.error(f"AdGuardHome.yaml not found at {ADGUARD_YAML}")
sys.exit(1)
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
else:
inside_disallowed = False
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))
with TMP_YAML.open("w") as f:
f.writelines(new_lines)
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}")
def main():
backup_first_start()
backup_last_cron()
cidr_ips = download_cidr_lists(COUNTRIES)
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()

View File

@ -1,75 +0,0 @@
#!/bin/bash
set -e
ADGUARD_YAML="/adguard/AdGuardHome.yaml"
TMP_YAML="/tmp/AdGuardHome.yaml"
MANUAL_IPS_FILE="/adguard/manually_blocked_ips.conf"
CIDR_BASE_URL="https://raw.githubusercontent.com/vulnebify/cidre/main/output/cidr/ipv4"
COUNTRIES=${BLOCK_COUNTRIES:-""}
DOCKER_API_URL=${DOCKER_API_URL:-"http://socket-proxy-adguard:2375"}
CONTAINER_NAME=${ADGUARD_CONTAINER_NAME:-"adguard-home"}
if [ -z "$COUNTRIES" ]; then
echo "No countries specified in BLOCK_COUNTRIES."
exit 1
fi
mkdir -p /tmp/cidr
> /tmp/cidr/all.txt
IFS=',' read -ra CODES <<< "$COUNTRIES"
for CODE in "${CODES[@]}"; do
echo "Downloading CIDR list for $CODE..."
curl -sf "$CIDR_BASE_URL/${CODE,,}.cidr" -o "/tmp/cidr/${CODE}.cidr" || continue
cat "/tmp/cidr/${CODE}.cidr" >> /tmp/cidr/all.txt
done
if [ -f "$MANUAL_IPS_FILE" ]; then
echo "Validating and adding manually blocked IPs from $MANUAL_IPS_FILE..."
grep -E '^([0-9]{1,3}\.){3}[0-9]{1,3}(/[0-9]{1,2})?$' "$MANUAL_IPS_FILE" >> /tmp/cidr/all.txt
fi
# Format IPs as YAML list items
sed 's/^/ - /' /tmp/cidr/all.txt > /tmp/cidr/ips_formatted.txt
awk '
BEGIN {
# Read formatted IPs into array
while ((getline line < "/tmp/cidr/ips_formatted.txt") > 0) {
ips[++count] = line
}
close("/tmp/cidr/ips_formatted.txt")
inside=0
}
/^ disallowed_clients:/ {
print
inside=1
next
}
/^ [^ ]/ && inside==1 {
# Insert all IPs here
for (i=1; i<=count; i++) print ips[i]
inside=0
}
{
if (!inside) print
}
END {
# If file ended while still inside disallowed_clients section
if (inside==1) {
for (i=1; i<=count; i++) print ips[i]
}
}
' "$ADGUARD_YAML" > "$TMP_YAML"
mv "$TMP_YAML" "$ADGUARD_YAML"
echo "Restarting $CONTAINER_NAME container..."
curl -s -X POST "$DOCKER_API_URL/containers/$CONTAINER_NAME/restart" -o /dev/null
echo "Done."