From 31d07d4484f337d0f6f066db0fda06aaf0129f10 Mon Sep 17 00:00:00 2001 From: Kirill Kodanev Date: Thu, 11 Sep 2025 19:49:28 +0300 Subject: [PATCH] Rewrite logic, use env variables, and add comments to the following code to make it more readable and maintainable. --- .forgejo/workflows/deploy.yaml | 28 ++++- README.md | 202 ++++++++++++++++++++++++++++++++- scripts/deploy-to-gateway.sh | 33 +++--- scripts/generate-configs.sh | 31 ++--- 4 files changed, 259 insertions(+), 35 deletions(-) diff --git a/.forgejo/workflows/deploy.yaml b/.forgejo/workflows/deploy.yaml index 50c8cfc..f7857d5 100644 --- a/.forgejo/workflows/deploy.yaml +++ b/.forgejo/workflows/deploy.yaml @@ -3,10 +3,31 @@ name: Deploy DNS Configuration on: push: branches: [ main ] + paths: [ 'domains.txt' ] jobs: deploy: runs-on: self-hosted # Используем self-hosted runner на шлюзе + env: + # ==== Конфигурация проекта ==== + INPUT_FILE: domains.txt + + # Временные конфиги (куда пишутся generate-configs.sh) + IPSET_CONF: /tmp/91-ipset-bbrkn.conf + RESOLVE_CONF: /tmp/92-resolve-bbrkn.conf + + # DNS-сервер для резолвинга + DNS_SERVER: 8.8.8.8 + + # Адрес сервиса Chromium + API_URL: http://10.100.1.2:3000/domains?domain= + + # Директория конфигов на шлюзе + TARGET_DIR: /opt/appdata/pihole/etc/dnsmasq.d + + # Имя контейнера Pi-hole + DOCKER_CONTAINER: pihole + steps: - name: Checkout repository uses: actions/checkout@v3 @@ -30,10 +51,9 @@ jobs: chmod +x scripts/generate-configs.sh chmod +x scripts/deploy-to-gateway.sh - - name: Run workflow (clean → check → all) + - name: Run workflow (clean → all) run: | make clean - make check make all - name: Upload configs as artifacts @@ -41,5 +61,5 @@ jobs: with: name: dnsmasq-configs path: | - /tmp/91-ipset-bbrkn.conf - /tmp/92-resolve-bbrkn.conf + ${{ env.IPSET_CONF }} + ${{ env.RESOLVE_CONF }} diff --git a/README.md b/README.md index f393eb5..d44265b 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,202 @@ -# bbrkn +# BBRKN DNS Configurator +## Описание + +**BBRKN** — это инструмент для автоматического формирования и деплоя конфигураций +для `dnsmasq` (через Pi-hole), необходимых для корректной работы целевых сайтов и сервисов. + +Проект решает задачу: у нас есть список базовых доменов (`domains.txt`), но для работы +сайтов часто требуется множество дополнительных ресурсов — CDN, API-эндпоинты, +трекеры и т.д. Ручное отслеживание этих зависимостей неудобно. + +Для этого используется сервис на базе Chromium, который автоматически анализирует +страницу и возвращает список всех связанных доменов. Проект берёт этот список, +нормализует его и формирует два конфигурационных файла для `dnsmasq`: + +- `91-ipset-bbrkn.conf` — добавляет все домены в ipset `bbrkn` +- `92-resolve-bbrkn.conf` — указывает резолвить все эти домены через DNS-сервер `8.8.8.8` + +Эти файлы затем автоматически деплоятся в Pi-hole и активируются перезапуском контейнера. + +--- + +## Архитектура + +```mermaid +flowchart TD + A[domains.txt] --> B[generate-configs.sh] + B -->|HTTP API| C[Chromium service
API_URL] + B --> D[91-ipset-bbrkn.conf
92-resolve-bbrkn.conf] + D --> E[deploy-to-gateway.sh] + E --> F[Pi-hole
(dnsmasq)] +``` + +--- + +## Переменные окружения + +Все важные параметры конфигурируются через **переменные окружения**. +Если переменная не задана, используется дефолтное значение. + +| Переменная | По умолчанию | Назначение | +| ------------------ | ---------------------------------------- | ------------------------------------------- | +| `INPUT_FILE` | `domains.txt` | Входной список доменов | +| `IPSET_CONF` | `/tmp/91-ipset-bbrkn.conf` | Временный файл конфигурации для ipset | +| `RESOLVE_CONF` | `/tmp/92-resolve-bbrkn.conf` | Временный файл конфигурации для серверов | +| `API_URL` | `http://10.100.1.2:3000/domains?domain=` | Адрес API сервиса Chromium | +| `DNS_SERVER` | `8.8.8.8` | DNS-сервер, через который резолвятся домены | +| `TARGET_DIR` | `/opt/appdata/pihole/etc/dnsmasq.d` | Директория для установки конфигов в Pi-hole | +| `DOCKER_CONTAINER` | `pihole` | Имя контейнера Pi-hole | + +👉 В Forgejo workflow все эти переменные задаются в секции `env:`. + +--- + +## Пример работы + +Пример запроса к Chromium-сервису: + +```bash +curl "http://10.100.1.2:3000/domains?domain=pornhub.com" +``` + +Ответ: + +```json +{ + "domains": [ + "a.adtng.com", + "cdn1-smallimg.phncdn.com", + "ei.phncdn.com", + "ht-cdn2.adtng.com", + "media.trafficjunky.net", + "pix-cdn77.phncdn.com", + "pornhub.com", + "www.pornhub.com" + ] +} +``` + +В итоговые конфиги будут добавлены все эти домены. + +Если сайт недоступен (например, сервисный домен): + +```bash +curl "http://10.100.1.2:3000/domains?domain=bt1.t-ru.org" +``` + +Ответ: + +```json +{ + "error": "page.goto: net::ERR_NAME_NOT_RESOLVED at https://bt1.t-ru.org/" +} +``` + +Такой домен будет классифицирован как `service` и попадёт в конфиг без связанных. + +--- + +## Установка и запуск + +### Требования + +* Linux-система или self-hosted runner Forgejo +* [dnsmasq](http://www.thekelleys.org.uk/dnsmasq/doc.html) через [Pi-hole](https://pi-hole.net/) +* [jq](https://stedolan.github.io/jq/) для парсинга JSON +* make +* docker (для управления Pi-hole контейнером) +* доступ к сервису Chromium (по умолчанию: `http://10.100.1.2:3000/domains`) + +### Ручной запуск + +```bash +make clean # очистка временных файлов +make check # только отчёт по доменам +make test # генерация + превью файлов +make deploy # генерация + деплой на шлюз +``` + +### Автоматический запуск (Forgejo CI/CD) + +Workflow (`.forgejo/workflows/deploy.yml`) автоматически срабатывает при изменении `domains.txt`. +CI делает: + +1. Валидацию синтаксиса `domains.txt` +2. `make clean` +3. `make check` +4. `make all` (генерация + деплой) +5. Сохранение артефактов (`91-ipset-bbrkn.conf` и `92-resolve-bbrkn.conf`) + +--- + +## Пример отладочного отчёта + +``` +===== DEBUG REPORT ===== +Original domains file: 50 entries +Final unique domains: 135 + - Base domains: 50 + - Related domains: 85 + +auth.openai.com - site +cdn.oaistatic.com - site +oaistatic.com - site +ab.chatgpt.com - site +realtime.chatgpt.com - site +ws.chatgpt.com - site +chatgpt.com - site +byspotify.com - site +pscdn.co - service +... +======================== +``` + +--- + +## Траблшутинг + +### 1. Chromium-сервис недоступен + +* Проверь, что сервис слушает на `${API_URL}`. +* Убедись, что firewall не блокирует доступ с runner-а. +* Можно протестировать напрямую: + + ```bash + curl "${API_URL}example.com" + ``` + + Если ответа нет или ошибка — перезапусти сервис. + +### 2. В отчёте все домены помечены как `service` + +Это значит, что сервис не смог открыть страницы. Возможные причины: + +* Сайты блокируются провайдером → нужен обход (VPN/проксирование). +* Chromium-сервис работает без доступа к интернету. + +### 3. Конфиги пустые или слишком маленькие + +* Проверь содержимое `domains.txt` (убери комментарии, пустые строки). +* Убедись, что `jq` установлен (иначе парсинг JSON не сработает). +* В debug-отчёте будет видно, какие домены обработаны. + +### 4. Pi-hole не поднимается после деплоя + +* Запусти `docker logs ${DOCKER_CONTAINER}`, проверь ошибки. +* Откати конфиги из бэкапа (они создаются с суффиксом `.backup.YYYYMMDD-HHMMSS`). +* Убедись, что новые конфиги не содержат невалидных строк. + +### 5. Forgejo CI падает + +* Проверь, что runner имеет доступ к `/tmp` (для генерации файлов). +* Проверь, что установлены зависимости: `make`, `jq`, `docker`. +* Логи CI подскажут, на каком шаге сломалось (`check`, `generate`, `deploy`). + +--- + +## Зачем это нужно? + +* Автоматически отслеживать **скрытые зависимости сайтов** (CDN, API-сервера и т.п.). +* Поддерживать актуальные списки для маршрутизации/блокировки/разделения трафика. +* Исключить ручную рутину: всё обновление конфигов делается одной командой или автоматически через CI/CD. \ No newline at end of file diff --git a/scripts/deploy-to-gateway.sh b/scripts/deploy-to-gateway.sh index c5e67db..293d9a6 100644 --- a/scripts/deploy-to-gateway.sh +++ b/scripts/deploy-to-gateway.sh @@ -1,40 +1,39 @@ #!/bin/bash -set -e +set -euo pipefail -# Пути к конфигурационным файлам -TARGET_DIR="/opt/appdata/pihole/etc/dnsmasq.d" -IPSET_CONF="91-ipset-bbrkn.conf" -RESOLVE_CONF="92-resolve-bbrkn.conf" +# ============================== +# Конфигурация через переменные +# ============================== +TARGET_DIR="${TARGET_DIR:-/opt/appdata/pihole/etc/dnsmasq.d}" +IPSET_CONF="${IPSET_CONF:-91-ipset-bbrkn.conf}" +RESOLVE_CONF="${RESOLVE_CONF:-92-resolve-bbrkn.conf}" + +DOCKER_CONTAINER="${DOCKER_CONTAINER:-pihole}" echo "Deploying configuration files to $TARGET_DIR" -# Создаем резервные копии существующих файлов +# Бэкап существующих файлов if [ -f "$TARGET_DIR/$IPSET_CONF" ]; then cp "$TARGET_DIR/$IPSET_CONF" "$TARGET_DIR/$IPSET_CONF.backup.$(date +%Y%m%d-%H%M%S)" fi - if [ -f "$TARGET_DIR/$RESOLVE_CONF" ]; then cp "$TARGET_DIR/$RESOLVE_CONF" "$TARGET_DIR/$RESOLVE_CONF.backup.$(date +%Y%m%d-%H%M%S)" fi -# Копируем новые файлы +# Копирование новых файлов cp "/tmp/$IPSET_CONF" "$TARGET_DIR/$IPSET_CONF" cp "/tmp/$RESOLVE_CONF" "$TARGET_DIR/$RESOLVE_CONF" +# Перезапуск контейнера +echo "Restarting $DOCKER_CONTAINER container..." +docker restart "$DOCKER_CONTAINER" -# Перезапускаем dnsmasq через Pi-hole контейнер -echo "Restarting Pi-hole container..." -docker restart pihole - -# Проверяем успешность перезапуска sleep 5 -if ! docker ps | grep -q pihole; then - echo "Error: Pi-hole container failed to start" +if ! docker ps | grep -q "$DOCKER_CONTAINER"; then + echo "Error: $DOCKER_CONTAINER container failed to start" exit 1 fi echo "Deployment completed successfully" - -# Уведомляем о количестве обработанных доменов DOMAIN_COUNT=$(grep -c '^ipset=' "$TARGET_DIR/$IPSET_CONF" || echo "0") echo "Applied configuration for $DOMAIN_COUNT domains" diff --git a/scripts/generate-configs.sh b/scripts/generate-configs.sh index 56c1a4f..41e7d9c 100644 --- a/scripts/generate-configs.sh +++ b/scripts/generate-configs.sh @@ -1,24 +1,31 @@ #!/bin/bash set -euo pipefail -INPUT_FILE="domains.txt" -IPSET_CONF="/tmp/91-ipset-bbrkn.conf" -RESOLVE_CONF="/tmp/92-resolve-bbrkn.conf" -API_URL="http://10.100.1.2:3000/domains?domain=" +# ============================== +# Конфигурация через переменные +# ============================== +INPUT_FILE="${INPUT_FILE:-domains.txt}" + +IPSET_CONF="${IPSET_CONF:-/tmp/91-ipset-bbrkn.conf}" +RESOLVE_CONF="${RESOLVE_CONF:-/tmp/92-resolve-bbrkn.conf}" + +API_URL="${API_URL:-http://10.100.1.2:3000/domains?domain=}" +DNS_SERVER="${DNS_SERVER:-8.8.8.8}" DRY_RUN=false if [[ "${1:-}" == "--dry-run" ]]; then DRY_RUN=true fi +# Очистка файлов только если не dry-run if ! $DRY_RUN; then : > "$IPSET_CONF" : > "$RESOLVE_CONF" fi -declare -A DOM_ROLE # роли для исходных доменов: site/service -declare -A EXPANDED # все уникальные домены (ключи = домены) -declare -A SOURCES # источник: base или related +declare -A DOM_ROLE +declare -A EXPANDED +declare -A SOURCES normalize_domain() { local raw="$1" @@ -34,7 +41,7 @@ normalize_domain() { fi } -# Обработка доменов из входного списка +# Обработка доменов while IFS= read -r line || [ -n "$line" ]; do dom="$(normalize_domain "$line" || true)" [ -z "$dom" ] && continue @@ -60,25 +67,23 @@ while IFS= read -r line || [ -n "$line" ]; do fi done < "$INPUT_FILE" -# Сортировка доменов +# Сортировка mapfile -t ALL_DOMAINS < <(printf "%s\n" "${!EXPANDED[@]}" | sort -u) # Генерация конфигов if ! $DRY_RUN; then for d in "${ALL_DOMAINS[@]}"; do echo "ipset=/$d/bbrkn" >> "$IPSET_CONF" - echo "server=/$d/8.8.8.8" >> "$RESOLVE_CONF" + echo "server=/$d/$DNS_SERVER" >> "$RESOLVE_CONF" done fi # Подсчёты count_in=$(wc -l < "$INPUT_FILE") count_total=${#ALL_DOMAINS[@]} -count_base=$(printf "%s\n" "${!SOURCES[@]}" | grep -c '.*' || true) -count_related=$(printf "%s\n" "${!SOURCES[@]}" | grep -c '.*' || true) count_related=$(( count_total - count_in )) -# Отладочный вывод +# Отладочный отчёт echo echo "===== DEBUG REPORT =====" echo "Original domains file: $count_in entries"