domain routing
This commit is contained in:
parent
b4ac6c3b19
commit
0b8bae3ab0
10 changed files with 1261 additions and 0 deletions
63
.gigacode/plans/domain_routing_bird.md
Normal file
63
.gigacode/plans/domain_routing_bird.md
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
# План: Domain-Based Routing для BIRD BGP
|
||||||
|
|
||||||
|
## Задача
|
||||||
|
Переписать скрипт domain-based routing для интеграции с BIRD BGP вместо firewalld/ipset/dnsmasq.
|
||||||
|
|
||||||
|
## Текущее состояние
|
||||||
|
- Существует `get-ip.sh` - генерирует route statements для BIRD из IP-списков
|
||||||
|
- Существует `domain-routing.sh` - использует firewalld/ipset/dnsmasq для domain-based routing
|
||||||
|
- Требуется создать `domain-routing-bird.sh` - генерирует маршруты для BIRD на основе доменов
|
||||||
|
|
||||||
|
## План реализации
|
||||||
|
|
||||||
|
### 1. Создать domain-routing-bird.sh
|
||||||
|
- Считывает список доменов из DOMAINS_FILE
|
||||||
|
- Разрешает домены в IP-адреса через dig (A и AAAA записи)
|
||||||
|
- Генерирует конфигурационный файл для BIRD с route statements
|
||||||
|
- Создаёт systemd-сервис для автовосстановления при перезагрузке
|
||||||
|
- Поддерживает параметры командной строки
|
||||||
|
- Использует конфигурационный файл domain-routing-bird.env
|
||||||
|
|
||||||
|
### 2. Структура конфигурации BIRD
|
||||||
|
```
|
||||||
|
# Auto-generated domain routing config
|
||||||
|
# Generated: 2026-07-03
|
||||||
|
|
||||||
|
route 8.8.8.0/24 via 10.0.0.1 on eth0;
|
||||||
|
route 1.1.1.0/24 via 10.0.0.1 on eth0;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Переменные окружения (domain-routing-bird.env)
|
||||||
|
- DOMAINS_FILE - путь к файлу со списком доменов
|
||||||
|
- BIRD_CONF_DIR - директория для конфигов BIRD (/etc/bird/conf.d)
|
||||||
|
- BIRD_CONF_FILE - имя выходного файла (domain-routing.conf)
|
||||||
|
- ROUTE_GATEWAY - шлюз для маршрутов (10.0.0.1)
|
||||||
|
- ROUTE_INTERFACE - интерфейс для маршрутов (eth0)
|
||||||
|
- ENABLE_IPV6 - включить IPv6 маршруты (true/false)
|
||||||
|
- ENABLE_IPV4 - включить IPv4 маршруты (true/false)
|
||||||
|
- AGGREGATE_TO_24 - суммаризировать IPv4 до /24 (true/false)
|
||||||
|
|
||||||
|
### 4. systemd-сервис для автовосстановления
|
||||||
|
- Создаётся при первом запуске
|
||||||
|
- Восстанавливает конфиг BIRD при перезагрузке
|
||||||
|
- Должен быть включён в автозагрузку
|
||||||
|
|
||||||
|
### 5. Обновить документацию
|
||||||
|
- Обновить README_DOMAIN_ROUTING.md с новым разделом для BIRD
|
||||||
|
- Создать README_DOMAIN_ROUTING_BIRD.md
|
||||||
|
|
||||||
|
## Шаги выполнения
|
||||||
|
1. Создать domain-routing-bird.sh ✅
|
||||||
|
2. Создать domain-routing-bird.env.example ✅
|
||||||
|
3. Создать domains-bird.txt.example для BIRD ✅
|
||||||
|
4. Обновить README документацию ✅
|
||||||
|
5. Проверить синтаксис bash ✅
|
||||||
|
|
||||||
|
## Дополнительные требования
|
||||||
|
- Добавить суммаризацию маршрутов до /24 ✅
|
||||||
|
|
||||||
|
## Реализованные изменения
|
||||||
|
- Добавлена функция `aggregate_routes_ipv4()` для суммаризации IPv4 маршрутов до /24
|
||||||
|
- Добавлена переменная `AGGREGATE_TO_24` для управления суммаризацией
|
||||||
|
- Обновлена функция `generate_bird_config()` для использования суммаризированных сетей
|
||||||
|
- Обновлён конфигурационный файл с новой переменной AGGREGATE_TO_24
|
||||||
185
README_DOMAIN_ROUTING.md
Normal file
185
README_DOMAIN_ROUTING.md
Normal file
|
|
@ -0,0 +1,185 @@
|
||||||
|
# Domain-Based Routing для RHEL
|
||||||
|
|
||||||
|
Скрипт для настройки маршрутизации трафика на основе доменных имён с использованием `firewalld`, `ipset` и `dnsmasq`.
|
||||||
|
|
||||||
|
## Возможности
|
||||||
|
|
||||||
|
- Автоматическое разрешение доменных имён в IP-адреса
|
||||||
|
- Добавление IP-адресов в `ipset` для быстрой фильтрации
|
||||||
|
- Настройка правил `firewalld` для перенаправления трафика
|
||||||
|
- Интеграция с `dnsmasq` для локального DNS-кэширования
|
||||||
|
- Автовосстановление `ipset` при перезагрузке
|
||||||
|
|
||||||
|
## Требования
|
||||||
|
|
||||||
|
- RHEL/CentOS 8+ с `firewalld`, `ipset`, `dnsmasq`
|
||||||
|
- `dig` (пакет `bind-utils`)
|
||||||
|
- `root` права
|
||||||
|
|
||||||
|
## Установка
|
||||||
|
|
||||||
|
1. Скопируйте `domain-routing.sh` на сервер:
|
||||||
|
```bash
|
||||||
|
cp domain-routing.sh /usr/local/bin/
|
||||||
|
chmod +x /usr/local/bin/domain-routing.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Создайте конфигурационный файл:
|
||||||
|
```bash
|
||||||
|
cp domain-routing.env.example /opt/domain-routing/domain-routing.env
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Отредактируйте `domain-routing.env`:
|
||||||
|
```bash
|
||||||
|
DOMAINS_FILE="/opt/domain-routing/domains.txt"
|
||||||
|
DNSMASQ_CONF_DIR="/etc/dnsmasq.d"
|
||||||
|
IPSET_NAME="domain_routing"
|
||||||
|
FIREWALL_ZONE="domain_routing"
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Создайте файл со списком доменов:
|
||||||
|
```bash
|
||||||
|
cat > /opt/domain-routing/domains.txt << 'EOF'
|
||||||
|
google.com
|
||||||
|
amazon.com
|
||||||
|
cloudflare.com
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Запустите скрипт:
|
||||||
|
```bash
|
||||||
|
sudo /usr/local/bin/domain-routing.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Использование
|
||||||
|
|
||||||
|
### Базовое использование
|
||||||
|
```bash
|
||||||
|
sudo ./domain-routing.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### С параметрами командной строки
|
||||||
|
```bash
|
||||||
|
sudo ./domain-routing.sh \
|
||||||
|
--domains-file /path/to/domains.txt \
|
||||||
|
--ipset-name custom_ipset \
|
||||||
|
--firewall-zone custom_zone
|
||||||
|
```
|
||||||
|
|
||||||
|
### Просмотр справки
|
||||||
|
```bash
|
||||||
|
sudo ./domain-routing.sh --help
|
||||||
|
```
|
||||||
|
|
||||||
|
## Конфигурация
|
||||||
|
|
||||||
|
### Основные переменные в `domain-routing.env`
|
||||||
|
|
||||||
|
| Переменная | Описание | Обязательная |
|
||||||
|
|------------|----------|-------------|
|
||||||
|
| `DOMAINS_FILE` | Путь к файлу со списком доменов | Да |
|
||||||
|
| `IPSET_NAME` | Имя создаваемого ipset | Да |
|
||||||
|
| `FIREWALL_ZONE` | Имя зоны firewalld | Да |
|
||||||
|
| `DNSMASQ_CONF_DIR` | Директория для конфигов dnsmasq | Да |
|
||||||
|
| `RESOLV_CONF` | Путь к resolv.conf | Нет |
|
||||||
|
|
||||||
|
### Формат файла доменов
|
||||||
|
|
||||||
|
Один домен на строку, комментарии начинаются с `#`:
|
||||||
|
```
|
||||||
|
# Комментарий
|
||||||
|
google.com
|
||||||
|
www.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
## Как это работает
|
||||||
|
|
||||||
|
1. Скрипт читает список доменов из файла
|
||||||
|
2. Разрешает каждый домен в IP-адреса через `dig`
|
||||||
|
3. Создаёт `ipset` и добавляет в него IP-адреса
|
||||||
|
4. Настраивает `firewalld` для использования ipset
|
||||||
|
5. Генерирует конфиг для `dnsmasq`
|
||||||
|
6. Сохраняет ipset для автовосстановления при перезагрузке
|
||||||
|
|
||||||
|
## Управление ipset
|
||||||
|
|
||||||
|
### Просмотр ipset
|
||||||
|
```bash
|
||||||
|
ipset list domain_routing
|
||||||
|
```
|
||||||
|
|
||||||
|
### Удаление ipset
|
||||||
|
```bash
|
||||||
|
ipset destroy domain_routing
|
||||||
|
```
|
||||||
|
|
||||||
|
### Пересоздание ipset
|
||||||
|
```bash
|
||||||
|
sudo ./domain-routing.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Автовосстановление
|
||||||
|
|
||||||
|
При установке создаётся systemd-сервис `ipset-restore@domain_routing.service`, который восстанавливает ipset при каждом запуске системы.
|
||||||
|
|
||||||
|
### Управление сервисом
|
||||||
|
```bash
|
||||||
|
# Проверка статуса
|
||||||
|
systemctl status ipset-restore@domain_routing.service
|
||||||
|
|
||||||
|
# Запуск вручную
|
||||||
|
systemctl start ipset-restore@domain_routing.service
|
||||||
|
|
||||||
|
# Отключение автовосстановления
|
||||||
|
systemctl disable ipset-restore@domain_routing.service
|
||||||
|
```
|
||||||
|
|
||||||
|
## Устранение неполадок
|
||||||
|
|
||||||
|
### Ошибка: "Не удалось разрешить ни один домен"
|
||||||
|
- Проверьте доступность DNS: `dig google.com`
|
||||||
|
- Убедитесь, что в файле доменов нет опечаток
|
||||||
|
|
||||||
|
### Ошибка: "firewalld: no zone"
|
||||||
|
- Создайте зону вручную: `firewall-cmd --new-zone=test --permanent`
|
||||||
|
|
||||||
|
### Dnsmasq не перезагружается
|
||||||
|
- Убедитесь, что dnsmasq установлен: `dnsmasq --version`
|
||||||
|
- Запустите вручную: `systemctl start dnsmasq`
|
||||||
|
|
||||||
|
## Примеры
|
||||||
|
|
||||||
|
### Маршрутизация трафика Google через VPN
|
||||||
|
```bash
|
||||||
|
# В domain-routing.env
|
||||||
|
DOMAINS_FILE="/etc/domain-routing/google-domains.txt"
|
||||||
|
IPSET_NAME="google_via_vpn"
|
||||||
|
FIREWALL_ZONE="vpn_routing"
|
||||||
|
|
||||||
|
# В /etc/domain-routing/google-domains.txt
|
||||||
|
google.com
|
||||||
|
www.google.com
|
||||||
|
maps.google.com
|
||||||
|
```
|
||||||
|
|
||||||
|
### Маршрутизация рекламных доменов в "чёрную дыру"
|
||||||
|
```bash
|
||||||
|
# В domain-routing.env
|
||||||
|
DOMAINS_FILE="/etc/domain-routing/ads-domains.txt"
|
||||||
|
IPSET_NAME="ads_block"
|
||||||
|
FIREWALL_ZONE="ads_block"
|
||||||
|
|
||||||
|
# Добавьте правило в firewalld для блокировки
|
||||||
|
firewall-cmd --zone=ads_block --add-rich-rule='rule family="ipv4" source ipset="ads_block" drop' --permanent
|
||||||
|
firewall-cmd --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
## Безопасность
|
||||||
|
|
||||||
|
- Скрипт должен запускаться от имени `root`
|
||||||
|
- Файлы конфигурации содержат пути к системным ресурсам - храните их в защищённых местах
|
||||||
|
- ipset используется только для IPv4 (можно расширить для IPv6)
|
||||||
|
|
||||||
|
## Лицензия
|
||||||
|
|
||||||
|
MIT
|
||||||
223
README_DOMAIN_ROUTING_BIRD.md
Normal file
223
README_DOMAIN_ROUTING_BIRD.md
Normal file
|
|
@ -0,0 +1,223 @@
|
||||||
|
# Domain-Based Routing для BIRD BGP
|
||||||
|
|
||||||
|
Скрипт для настройки маршрутизации трафика на основе доменных имён с использованием `BIRD BGP`.
|
||||||
|
|
||||||
|
## Возможности
|
||||||
|
|
||||||
|
- Автоматическое разрешение доменных имён в IP-адреса (IPv4 и IPv6)
|
||||||
|
- Генерация конфигурационного файла для BIRD с route statements
|
||||||
|
- Автоматическая перезагрузка BIRD после изменения конфига
|
||||||
|
- MD5 хеш для отслеживания изменений
|
||||||
|
- Автовосстановление конфига при перезагрузке через systemd
|
||||||
|
|
||||||
|
## Требования
|
||||||
|
|
||||||
|
- RHEL/CentOS 8+ с `BIRD`
|
||||||
|
- `dig` (пакет `bind-utils`)
|
||||||
|
- `root` права
|
||||||
|
|
||||||
|
## Установка
|
||||||
|
|
||||||
|
1. Скопируйте `domain-routing-bird.sh` на сервер:
|
||||||
|
```bash
|
||||||
|
cp domain-routing-bird.sh /usr/local/bin/
|
||||||
|
chmod +x /usr/local/bin/domain-routing-bird.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Создайте конфигурационный файл:
|
||||||
|
```bash
|
||||||
|
cp domain-routing-bird.env.example /opt/domain-routing/domain-routing-bird.env
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Отредактируйте `domain-routing-bird.env`:
|
||||||
|
```bash
|
||||||
|
DOMAINS_FILE="/opt/domain-routing/domains.txt"
|
||||||
|
BIRD_CONF_DIR="/etc/bird/conf.d"
|
||||||
|
BIRD_CONF_FILE="domain-routing.conf"
|
||||||
|
ROUTE_GATEWAY="10.0.0.1"
|
||||||
|
ROUTE_INTERFACE="eth0"
|
||||||
|
ENABLE_IPV4="true"
|
||||||
|
ENABLE_IPV6="false"
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Создайте файл со списком доменов:
|
||||||
|
```bash
|
||||||
|
cat > /opt/domain-routing/domains.txt << 'EOF'
|
||||||
|
google.com
|
||||||
|
www.google.com
|
||||||
|
amazon.com
|
||||||
|
cloudflare.com
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Запустите скрипт:
|
||||||
|
```bash
|
||||||
|
sudo /usr/local/bin/domain-routing-bird.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Использование
|
||||||
|
|
||||||
|
### Базовое использование
|
||||||
|
```bash
|
||||||
|
sudo ./domain-routing-bird.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### С параметрами командной строки
|
||||||
|
```bash
|
||||||
|
sudo ./domain-routing-bird.sh \
|
||||||
|
--domains-file /path/to/domains.txt \
|
||||||
|
--bird-conf-dir /etc/bird/conf.d \
|
||||||
|
--bird-conf-file domain-routing.conf \
|
||||||
|
--gateway 10.0.0.1 \
|
||||||
|
--interface eth0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Просмотр справки
|
||||||
|
```bash
|
||||||
|
sudo ./domain-routing-bird.sh --help
|
||||||
|
```
|
||||||
|
|
||||||
|
## Конфигурация
|
||||||
|
|
||||||
|
### Основные переменные в `domain-routing-bird.env`
|
||||||
|
|
||||||
|
| Переменная | Описание | Обязательная |
|
||||||
|
|------------|----------|-------------|
|
||||||
|
| `DOMAINS_FILE` | Путь к файлу со списком доменов | Да |
|
||||||
|
| `BIRD_CONF_DIR` | Директория конфигов BIRD | Да |
|
||||||
|
| `BIRD_CONF_FILE` | Имя файла конфига | Да |
|
||||||
|
| `ROUTE_GATEWAY` | Шлюз для маршрутов | Да |
|
||||||
|
| `ROUTE_INTERFACE` | Интерфейс для маршрутов | Да |
|
||||||
|
| `ENABLE_IPV4` | Включить IPv4 (true/false) | Нет (по умолчанию true) |
|
||||||
|
| `ENABLE_IPV6` | Включить IPv6 (true/false) | Нет (по умолчанию false) |
|
||||||
|
|
||||||
|
### Формат файла доменов
|
||||||
|
|
||||||
|
Один домен на строку, комментарии начинаются с `#`:
|
||||||
|
```
|
||||||
|
# Комментарий
|
||||||
|
google.com
|
||||||
|
www.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
## Как это работает
|
||||||
|
|
||||||
|
1. Скрипт читает список доменов из файла
|
||||||
|
2. Разрешает каждый домен в IP-адреса через `dig` (A и AAAA записи)
|
||||||
|
3. Генерирует конфигурационный файл для BIRD с route statements
|
||||||
|
4. Перезагружает BIRD через `birdc configure`
|
||||||
|
5. Сохраняет MD5 хеш для отслеживания изменений
|
||||||
|
6. Создаёт systemd-сервис для автовосстановления при перезагрузке
|
||||||
|
|
||||||
|
## Структура конфига BIRD
|
||||||
|
|
||||||
|
```
|
||||||
|
# Auto-generated domain routing config
|
||||||
|
# Generated: 2026-07-03
|
||||||
|
# Source: /opt/domain-routing/domains.txt
|
||||||
|
|
||||||
|
route 8.8.8.0/24 via 10.0.0.1 on eth0;
|
||||||
|
route 1.1.1.0/24 via 10.0.0.1 on eth0;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Управление конфигом
|
||||||
|
|
||||||
|
### Просмотр конфига BIRD
|
||||||
|
```bash
|
||||||
|
cat /etc/bird/conf.d/domain-routing.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
### Просмотр маршрутов в BIRD
|
||||||
|
```bash
|
||||||
|
birdc show route all
|
||||||
|
```
|
||||||
|
|
||||||
|
### Перезагрузка BIRD вручную
|
||||||
|
```bash
|
||||||
|
sudo /usr/sbin/birdc configure
|
||||||
|
```
|
||||||
|
|
||||||
|
### Удаление конфига
|
||||||
|
```bash
|
||||||
|
rm /etc/bird/conf.d/domain-routing.conf
|
||||||
|
sudo /usr/sbin/birdc configure
|
||||||
|
```
|
||||||
|
|
||||||
|
## systemd-сервис
|
||||||
|
|
||||||
|
При установке создаётся systemd-сервис `bird-domain-routing.service`, который перезагружает BIRD при каждом запуске системы.
|
||||||
|
|
||||||
|
### Управление сервисом
|
||||||
|
```bash
|
||||||
|
# Проверка статуса
|
||||||
|
systemctl status bird-domain-routing.service
|
||||||
|
|
||||||
|
# Запуск вручную
|
||||||
|
systemctl start bird-domain-routing.service
|
||||||
|
|
||||||
|
# Отключение автовосстановления
|
||||||
|
systemctl disable bird-domain-routing.service
|
||||||
|
```
|
||||||
|
|
||||||
|
## Устранение неполадок
|
||||||
|
|
||||||
|
### Ошибка: "Не удалось разрешить ни один домен"
|
||||||
|
- Проверьте доступность DNS: `dig google.com`
|
||||||
|
- Убедитесь, что в файле доменов нет опечаток
|
||||||
|
|
||||||
|
### Ошибка: "birdc: connect: No such file or directory"
|
||||||
|
- Убедитесь, что BIRD запущен: `systemctl status bird`
|
||||||
|
- Запустите BIRD: `systemctl start bird`
|
||||||
|
|
||||||
|
### Ошибка: "route X.X.X.X: Invalid argument"
|
||||||
|
- Проверьте, что шлюз `ROUTE_GATEWAY` доступен на интерфейсе `ROUTE_INTERFACE`
|
||||||
|
- Проверьте маршруты: `ip route show`
|
||||||
|
|
||||||
|
### BIRD не применяет конфиг
|
||||||
|
- Проверьте синтаксис: `birdc check`
|
||||||
|
- Посмотрите логи: `journalctl -u bird`
|
||||||
|
|
||||||
|
## Примеры
|
||||||
|
|
||||||
|
### Маршрутизация трафика Google через VPN
|
||||||
|
```bash
|
||||||
|
# В domain-routing-bird.env
|
||||||
|
DOMAINS_FILE="/etc/domain-routing/google-domains.txt"
|
||||||
|
BIRD_CONF_FILE="google-routes.conf"
|
||||||
|
ROUTE_GATEWAY="10.8.0.1"
|
||||||
|
ROUTE_INTERFACE="tun0"
|
||||||
|
|
||||||
|
# В /etc/domain-routing/google-domains.txt
|
||||||
|
google.com
|
||||||
|
www.google.com
|
||||||
|
maps.google.com
|
||||||
|
```
|
||||||
|
|
||||||
|
### Маршрутизация рекламных доменов в "чёрную дыру" (через null0)
|
||||||
|
```bash
|
||||||
|
# В domain-routing-bird.env
|
||||||
|
ROUTE_GATEWAY="null0"
|
||||||
|
|
||||||
|
# Конфиг будет содержать:
|
||||||
|
route 8.8.8.0/24 via null0;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Сравнение с domain-routing.sh (firewalld/ipset)
|
||||||
|
|
||||||
|
| Функция | domain-routing.sh | domain-routing-bird.sh |
|
||||||
|
|---------|-------------------|------------------------|
|
||||||
|
| Технология | firewalld + ipset | BIRD BGP |
|
||||||
|
| Гибкость | Ограничена правилами firewalld | Полный контроль маршрутов |
|
||||||
|
| Поддержка IPv6 | Ограничена | Полная |
|
||||||
|
| Интеграция | Системный firewall | BGP routing |
|
||||||
|
| Сложность | Простая | Более сложная |
|
||||||
|
|
||||||
|
## Безопасность
|
||||||
|
|
||||||
|
- Скрипт должен запускаться от имени `root`
|
||||||
|
- Файлы конфигурации содержат пути к системным ресурсам - храните их в защищённых местах
|
||||||
|
- Рассмотрите использование `birdc check` для валидации конфига перед применением
|
||||||
|
|
||||||
|
## Лицензия
|
||||||
|
|
||||||
|
MIT
|
||||||
44
domain-routing-bird.env.example
Normal file
44
domain-routing-bird.env.example
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Конфигурационный файл для domain-based routing с BIRD BGP
|
||||||
|
# Скопируйте этот файл в domain-routing-bird.env и настройте под ваши нужды
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# ПУТИ И ФАЙЛЫ
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
# Файл со списком доменов для маршрутизации (один домен на строку)
|
||||||
|
# DOMAINS_FILE="/opt/domain-routing/domains.txt"
|
||||||
|
|
||||||
|
# Директория для конфигов BIRD
|
||||||
|
# BIRD_CONF_DIR="/etc/bird/conf.d"
|
||||||
|
|
||||||
|
# Имя выходного файла конфига BIRD
|
||||||
|
# BIRD_CONF_FILE="domain-routing.conf"
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# МАРШРУТИЗАЦИЯ
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
# Шлюз для маршрутов (IP-адрес шлюза на локальном интерфейсе)
|
||||||
|
# ROUTE_GATEWAY="10.0.0.1"
|
||||||
|
|
||||||
|
# Интерфейс для маршрутов
|
||||||
|
# ROUTE_INTERFACE="eth0"
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# IP VERSIONS
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
# Включить IPv4 маршруты (true/false)
|
||||||
|
# ENABLE_IPV4="true"
|
||||||
|
|
||||||
|
# Включить IPv6 маршруты (true/false)
|
||||||
|
# ENABLE_IPV6="false"
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# СУММАРИЗАЦИЯ МАРШРУТОВ
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
# Суммаризировать IPv4 маршруты до /24 (true/false)
|
||||||
|
# AGGREGATE_TO_24="true"
|
||||||
344
domain-routing-bird.sh
Executable file
344
domain-routing-bird.sh
Executable file
|
|
@ -0,0 +1,344 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Скрипт для domain-based routing под RHEL с BIRD BGP
|
||||||
|
# Направляет трафик определённых доменов через отдельный маршрут в BIRD
|
||||||
|
# С поддержкой суммаризации маршрутов до /24
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# КОНФИГУРАЦИЯ
|
||||||
|
# ============================================
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
CONFIG_FILE="$SCRIPT_DIR/domain-routing-bird.env"
|
||||||
|
|
||||||
|
# Загрузка конфигурации
|
||||||
|
if [[ ! -f "$CONFIG_FILE" ]]; then
|
||||||
|
echo "❌ Ошибка: не найден конфигурационный файл $CONFIG_FILE"
|
||||||
|
echo "Создайте файл на основе domain-routing-bird.env.example"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# shellcheck source=domain-routing-bird.env
|
||||||
|
source "$CONFIG_FILE"
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# ВАЛИДАЦИЯ ПЕРЕМЕННЫХ
|
||||||
|
# ============================================
|
||||||
|
required_vars=(
|
||||||
|
"DOMAINS_FILE"
|
||||||
|
"BIRD_CONF_DIR"
|
||||||
|
"BIRD_CONF_FILE"
|
||||||
|
"ROUTE_GATEWAY"
|
||||||
|
"ROUTE_INTERFACE"
|
||||||
|
)
|
||||||
|
|
||||||
|
for var in "${required_vars[@]}"; do
|
||||||
|
[[ -z "${!var:-}" ]] && { echo "❌ Переменная $var не установлена в $CONFIG_FILE"; exit 1; }
|
||||||
|
done
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# ФУНКЦИИ
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
log_info() {
|
||||||
|
echo "ℹ️ $1"
|
||||||
|
logger -t "domain-routing-bird" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error() {
|
||||||
|
echo "❌ $1"
|
||||||
|
logger -t "domain-routing-bird" "ERROR: $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_dependencies() {
|
||||||
|
log_info "Проверка зависимостей..."
|
||||||
|
|
||||||
|
local missing=()
|
||||||
|
|
||||||
|
for cmd in birdc dig; do
|
||||||
|
if ! command -v "$cmd" &> /dev/null; then
|
||||||
|
missing+=("$cmd")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ${#missing[@]} -gt 0 ]]; then
|
||||||
|
log_error "Отсутствуют команды: ${missing[*]}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Все зависимости установлены"
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_domains_to_ips() {
|
||||||
|
log_info "Разрешение доменов в IP-адреса..."
|
||||||
|
|
||||||
|
local temp_file=$(mktemp)
|
||||||
|
local ipv4_file=$(mktemp)
|
||||||
|
local ipv6_file=$(mktemp)
|
||||||
|
|
||||||
|
while IFS= read -r domain || [[ -n "$domain" ]]; do
|
||||||
|
# Пропускаем комментарии и пустые строки
|
||||||
|
[[ -z "$domain" ]] && continue
|
||||||
|
[[ "$domain" =~ ^[[:space:]]*# ]] && continue
|
||||||
|
|
||||||
|
# Очищаем домен от лишних символов
|
||||||
|
domain=$(echo "$domain" | tr -d '[:space:]')
|
||||||
|
|
||||||
|
# Разрешаем домен в IPv4
|
||||||
|
if [[ "${ENABLE_IPV4:-true}" == "true" ]]; then
|
||||||
|
local ipv4
|
||||||
|
ipv4=$(dig +short "$domain" A 2>/dev/null || true)
|
||||||
|
if [[ -n "$ipv4" ]]; then
|
||||||
|
echo "$ipv4" >> "$ipv4_file"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Разрешаем домен в IPv6
|
||||||
|
if [[ "${ENABLE_IPV6:-false}" == "true" ]]; then
|
||||||
|
local ipv6
|
||||||
|
ipv6=$(dig +short "$domain" AAAA 2>/dev/null || true)
|
||||||
|
if [[ -n "$ipv6" ]]; then
|
||||||
|
echo "$ipv6" >> "$ipv6_file"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done < "$DOMAINS_FILE"
|
||||||
|
|
||||||
|
# Объединяем результаты
|
||||||
|
if [[ "${ENABLE_IPV4:-true}" == "true" ]] && [[ -s "$ipv4_file" ]]; then
|
||||||
|
cat "$ipv4_file" >> "$temp_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${ENABLE_IPV6:-false}" == "true" ]] && [[ -s "$ipv6_file" ]]; then
|
||||||
|
cat "$ipv6_file" >> "$temp_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Удаляем дубликаты
|
||||||
|
local unique_file=$(mktemp)
|
||||||
|
sort -u "$temp_file" > "$unique_file"
|
||||||
|
|
||||||
|
local count=$(wc -l < "$unique_file")
|
||||||
|
log_info "Разрешено $count уникальных IP-адресов"
|
||||||
|
|
||||||
|
rm -f "$temp_file" "$ipv4_file" "$ipv6_file"
|
||||||
|
|
||||||
|
echo "$unique_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Функция для суммаризации IPv4 маршрутов по маске (до /24)
|
||||||
|
aggregate_routes_ipv4() {
|
||||||
|
local ip_file="$1"
|
||||||
|
local output_file="$2"
|
||||||
|
|
||||||
|
log_info "Суммаризация IPv4 маршрутов до /24..."
|
||||||
|
|
||||||
|
# Создаём временный файл для сетей
|
||||||
|
local network_file=$(mktemp)
|
||||||
|
|
||||||
|
# Преобразуем IP в сети /24
|
||||||
|
while read -r ip; do
|
||||||
|
if [[ -n "$ip" ]] && [[ "$ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||||
|
# Получаем сеть /24 для IP
|
||||||
|
local network=$(echo "$ip" | cut -d. -f1-3)
|
||||||
|
echo "${network}.0/24"
|
||||||
|
fi
|
||||||
|
done < "$ip_file" | sort -u > "$network_file"
|
||||||
|
|
||||||
|
local total_networks=$(wc -l < "$network_file")
|
||||||
|
log_info "Создано $total_networks сетей /24"
|
||||||
|
|
||||||
|
# Копируем в выходной файл
|
||||||
|
cp "$network_file" "$output_file"
|
||||||
|
local aggregated_count=$(wc -l < "$output_file")
|
||||||
|
log_info "После суммаризации: $aggregated_count сетей"
|
||||||
|
|
||||||
|
rm -f "$network_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_bird_config() {
|
||||||
|
local ip_file="$1"
|
||||||
|
local output_file="$BIRD_CONF_DIR/$BIRD_CONF_FILE"
|
||||||
|
|
||||||
|
log_info "Генерация конфига BIRD: $output_file"
|
||||||
|
|
||||||
|
mkdir -p "$BIRD_CONF_DIR"
|
||||||
|
|
||||||
|
# Создаём заголовок
|
||||||
|
echo "# Auto-generated domain routing config" > "$output_file"
|
||||||
|
echo "# Generated: $(date)" >> "$output_file"
|
||||||
|
echo "# Source: $DOMAINS_FILE" >> "$output_file"
|
||||||
|
echo "" >> "$output_file"
|
||||||
|
|
||||||
|
# Если включена суммаризация IPv4, используем агрегированные сети
|
||||||
|
if [[ "${ENABLE_IPV4:-true}" == "true" ]] && [[ "${AGGREGATE_TO_24:-true}" == "true" ]]; then
|
||||||
|
local aggregated_file=$(mktemp)
|
||||||
|
aggregate_routes_ipv4 "$ip_file" "$aggregated_file"
|
||||||
|
|
||||||
|
# Генерируем route statements для суммаризированных IPv4 сетей
|
||||||
|
while read -r network; do
|
||||||
|
if [[ -n "$network" ]]; then
|
||||||
|
echo "route $network via $ROUTE_GATEWAY on $ROUTE_INTERFACE;" >> "$output_file"
|
||||||
|
fi
|
||||||
|
done < "$aggregated_file"
|
||||||
|
|
||||||
|
rm -f "$aggregated_file"
|
||||||
|
else
|
||||||
|
# Без суммаризации - добавляем отдельные IP
|
||||||
|
while read -r ip; do
|
||||||
|
if [[ -n "$ip" ]]; then
|
||||||
|
# Определяем тип IP (IPv4 или IPv6)
|
||||||
|
if [[ "$ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||||
|
if [[ "${ENABLE_IPV4:-true}" == "true" ]]; then
|
||||||
|
if [[ "${AGGREGATE_TO_24:-true}" == "true" ]]; then
|
||||||
|
# Конвертируем в /24 сеть
|
||||||
|
local network=$(echo "$ip" | cut -d. -f1-3)
|
||||||
|
echo "route ${network}.0/24 via $ROUTE_GATEWAY on $ROUTE_INTERFACE;" >> "$output_file"
|
||||||
|
else
|
||||||
|
echo "route $ip via $ROUTE_GATEWAY on $ROUTE_INTERFACE;" >> "$output_file"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
elif [[ "$ip" =~ : ]]; then
|
||||||
|
if [[ "${ENABLE_IPV6:-false}" == "true" ]]; then
|
||||||
|
echo "route $ip via $ROUTE_GATEWAY on $ROUTE_INTERFACE;" >> "$output_file"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done < "$ip_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Конфиг BIRD сгенерирован: $output_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
reload_bird() {
|
||||||
|
log_info "Перезагрузка BIRD..."
|
||||||
|
|
||||||
|
if /usr/sbin/birdc configure; then
|
||||||
|
logger "BIRD domain routing reconfigured"
|
||||||
|
log_info "BIRD успешно перезагружен"
|
||||||
|
else
|
||||||
|
log_error "Ошибка при перезагрузке BIRD"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
save_config_hash() {
|
||||||
|
local output_file="$BIRD_CONF_DIR/$BIRD_CONF_FILE"
|
||||||
|
local hash_file="$BIRD_CONF_DIR/.${BIRD_CONF_FILE}.md5"
|
||||||
|
|
||||||
|
if [[ -f "$output_file" ]]; then
|
||||||
|
md5sum "$output_file" | cut -c1-32 > "$hash_file"
|
||||||
|
log_info "MD5 хеш сохранён: $hash_file"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
restore_config_on_boot() {
|
||||||
|
log_info "Настройка автовосстановления конфига BIRD..."
|
||||||
|
|
||||||
|
# Создаём systemd service для перезагрузки BIRD
|
||||||
|
local service_file="/etc/systemd/system/bird-domain-routing.service"
|
||||||
|
|
||||||
|
cat > "$service_file" << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=BIRD Domain Routing Configuration
|
||||||
|
After=network.target
|
||||||
|
Wants=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/sbin/birdc configure
|
||||||
|
RemainAfterExit=yes
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl enable bird-domain-routing.service
|
||||||
|
log_info "Systemd сервис создан и включён: bird-domain-routing.service"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# ОСНОВНАЯ ЛОГИКА
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
main() {
|
||||||
|
echo "=============================================="
|
||||||
|
echo "Domain-based Routing for BIRD BGP"
|
||||||
|
echo "=============================================="
|
||||||
|
|
||||||
|
# Проверка прав суперпользователя
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
log_error "Скрипт должен быть запущен от имени root"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Опции командной строки
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--domains-file)
|
||||||
|
DOMAINS_FILE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--bird-conf-dir)
|
||||||
|
BIRD_CONF_DIR="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--bird-conf-file)
|
||||||
|
BIRD_CONF_FILE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--gateway)
|
||||||
|
ROUTE_GATEWAY="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--interface)
|
||||||
|
ROUTE_INTERFACE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--help)
|
||||||
|
echo "Usage: $0 [OPTIONS]"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " --domains-file FILE Файл со списком доменов"
|
||||||
|
echo " --bird-conf-dir DIR Директория конфигов BIRD"
|
||||||
|
echo " --bird-conf-file FILE Имя файла конфига"
|
||||||
|
echo " --gateway GATEWAY Шлюз для маршрутов"
|
||||||
|
echo " --interface INTERFACE Интерфейс для маршрутов"
|
||||||
|
echo " --help Показать эту справку"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log_error "Неизвестный параметр: $1"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
log_info "Конфигурация:"
|
||||||
|
echo " Domains file: $DOMAINS_FILE"
|
||||||
|
echo " BIRD conf dir: $BIRD_CONF_DIR"
|
||||||
|
echo " BIRD conf file: $BIRD_CONF_FILE"
|
||||||
|
echo " Route gateway: $ROUTE_GATEWAY"
|
||||||
|
echo " Route interface: $ROUTE_INTERFACE"
|
||||||
|
echo " IPv4 enabled: ${ENABLE_IPV4:-true}"
|
||||||
|
echo " IPv6 enabled: ${ENABLE_IPV6:-false}"
|
||||||
|
echo " Aggregate to /24: ${AGGREGATE_TO_24:-true}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Шаги выполнения
|
||||||
|
check_dependencies
|
||||||
|
local ip_file
|
||||||
|
ip_file=$(resolve_domains_to_ips)
|
||||||
|
generate_bird_config "$ip_file"
|
||||||
|
reload_bird
|
||||||
|
save_config_hash
|
||||||
|
restore_config_on_boot
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
log_info "=========================================="
|
||||||
|
log_info "Domain-based routing для BIRD настроен!"
|
||||||
|
log_info "=========================================="
|
||||||
|
}
|
||||||
|
|
||||||
|
# Запуск основной функции
|
||||||
|
main "$@"
|
||||||
37
domain-routing.env.example
Normal file
37
domain-routing.env.example
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Конфигурационный файл для domain-based routing
|
||||||
|
# Скопируйте этот файл в domain-routing.env и настройте под ваши нужды
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# ПУТИ И ФАЙЛЫ
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
# Файл со списком доменов для маршрутизации (один домен на строку)
|
||||||
|
# Domains_FILE="/opt/domain-routing/domains.txt"
|
||||||
|
|
||||||
|
# Директория для конфигов dnsmasq
|
||||||
|
# DNSMASQ_CONF_DIR="/etc/dnsmasq.d"
|
||||||
|
|
||||||
|
# Файл резолва (для DNS)
|
||||||
|
# RESOLV_CONF="/etc/resolv.conf"
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# IPSET И FIREWALL
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
# Имя ipset (до<D0B4><D0BE>жно быть уникальным)
|
||||||
|
# IPSET_NAME="domain_routing"
|
||||||
|
|
||||||
|
# Имя зоны firewalld
|
||||||
|
# FIREWALL_ZONE="domain_routing"
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# ДОПОЛНИТЕЛЬНЫЕ НАСТРОЙКИ
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
# Дополнительные параметры ipset (hashsize, timeout и т.д.)
|
||||||
|
# IPSET_OPTIONS="hashsize 4096"
|
||||||
|
|
||||||
|
# Время жизни записей в ipset (в секундах, 0 = бесконечно)
|
||||||
|
# IPSET_TIMEOUT=0
|
||||||
303
domain-routing.sh
Executable file
303
domain-routing.sh
Executable file
|
|
@ -0,0 +1,303 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Скрипт для domain-based routing под RHEL с firewalld, ipset, dnsmasq
|
||||||
|
# Направляет трафик определённых доменов через отдельный интерфейс/IP-набор
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# КОНФИГУРАЦИЯ
|
||||||
|
# ============================================
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
CONFIG_FILE="$SCRIPT_DIR/domain-routing.env"
|
||||||
|
|
||||||
|
# Загрузка конфигурации
|
||||||
|
if [[ ! -f "$CONFIG_FILE" ]]; then
|
||||||
|
echo "❌ Ошибка: не найден конфигурационный файл $CONFIG_FILE"
|
||||||
|
echo "Создайте файл на основе domain-routing.env.example"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# shellcheck source=domain-routing.env
|
||||||
|
source "$CONFIG_FILE"
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# ВАЛИДАЦИЯ ПЕРЕМЕННЫХ
|
||||||
|
# ============================================
|
||||||
|
required_vars=(
|
||||||
|
"DOMAINS_FILE"
|
||||||
|
"IPSET_NAME"
|
||||||
|
"FIREWALL_ZONE"
|
||||||
|
"DNSMASQ_CONF_DIR"
|
||||||
|
"RESOLV_CONF"
|
||||||
|
)
|
||||||
|
|
||||||
|
for var in "${required_vars[@]}"; do
|
||||||
|
[[ -z "${!var:-}" ]] && { echo "❌ Переменная $var не установлена в $CONFIG_FILE"; exit 1; }
|
||||||
|
done
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# ФУНКЦИИ
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
log_info() {
|
||||||
|
echo "ℹ️ $1"
|
||||||
|
logger -t "domain-routing" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error() {
|
||||||
|
echo "❌ $1"
|
||||||
|
logger -t "domain-routing" "ERROR: $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_dependencies() {
|
||||||
|
log_info "Проверка зависимостей..."
|
||||||
|
|
||||||
|
local missing=()
|
||||||
|
|
||||||
|
for cmd in firewall-cmd ipset dnsmasq; do
|
||||||
|
if ! command -v "$cmd" &> /dev/null; then
|
||||||
|
missing+=("$cmd")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ${#missing[@]} -gt 0 ]]; then
|
||||||
|
log_error "Отсутствуют команды: ${missing[*]}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Все зависимости установлены"
|
||||||
|
}
|
||||||
|
|
||||||
|
create_ipset() {
|
||||||
|
log_info "Создание ipset '$IPSET_NAME'..."
|
||||||
|
|
||||||
|
# Удаляем старый ipset если есть
|
||||||
|
if ipset list "$IPSET_NAME" &> /dev/null; then
|
||||||
|
ipset destroy "$IPSET_NAME"
|
||||||
|
log_info "Удалён старый ipset '$IPSET_NAME'"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Создаём новый ipset (hash:net для IP-сетей)
|
||||||
|
ipset create "$IPSET_NAME" hash:net hashsize 4096 family inet
|
||||||
|
log_info "Создан ipset '$IPSET_NAME'"
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_domains_to_ips() {
|
||||||
|
log_info "Разрешение доменов в IP-адреса..."
|
||||||
|
|
||||||
|
local temp_file=$(mktemp)
|
||||||
|
local resolved_count=0
|
||||||
|
|
||||||
|
while IFS= read -r domain || [[ -n "$domain" ]]; do
|
||||||
|
# Пропускаем комментарии и пустые строки
|
||||||
|
[[ -z "$domain" ]] && continue
|
||||||
|
[[ "$domain" =~ ^[[:space:]]*# ]] && continue
|
||||||
|
|
||||||
|
# Очищаем домен от лишних символов
|
||||||
|
domain=$(echo "$domain" | tr -d '[:space:]')
|
||||||
|
|
||||||
|
# Разрешаем домен в IP
|
||||||
|
local ips
|
||||||
|
ips=$(dig +short "$domain" A 2>/dev/null || true)
|
||||||
|
|
||||||
|
if [[ -n "$ips" ]]; then
|
||||||
|
echo "$ips" | while read -r ip; do
|
||||||
|
if [[ -n "$ip" ]]; then
|
||||||
|
echo "$ip" >> "$temp_file"
|
||||||
|
((resolved_count++)) || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
log_error "Не удалось разрешить домен: $domain"
|
||||||
|
fi
|
||||||
|
done < "$DOMAINS_FILE"
|
||||||
|
|
||||||
|
# Добавляем IP в ipset
|
||||||
|
if [[ -s "$temp_file" ]]; then
|
||||||
|
while read -r ip; do
|
||||||
|
ipset add "$IPSET_NAME" "$ip"
|
||||||
|
done < "$temp_file"
|
||||||
|
|
||||||
|
log_info "Добавлено ${resolved_count} IP-адресов в ipset '$IPSET_NAME'"
|
||||||
|
else
|
||||||
|
log_error "Не удалось разрешить ни один домен"
|
||||||
|
rm -f "$temp_file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "$temp_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
configure_firewall() {
|
||||||
|
log_info "Настройка firewalld..."
|
||||||
|
|
||||||
|
# Проверяем зону
|
||||||
|
if ! firewall-cmd --query-zone="$FIREWALL_ZONE" &> /dev/null; then
|
||||||
|
log_info "Создание новой зоны '$FIREWALL_ZONE'..."
|
||||||
|
firewall-cmd --new-zone="$FIREWALL_ZONE" --permanent
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Добавляем ipset в зону
|
||||||
|
firewall-cmd --zone="$FIREWALL_ZONE" --add-ipset="$IPSET_NAME" --permanent
|
||||||
|
|
||||||
|
# Перезагружаем firewalld
|
||||||
|
firewall-cmd --reload
|
||||||
|
|
||||||
|
log_info "Firewalld настроен для ipset '$IPSET_NAME' в зоне '$FIREWALL_ZONE'"
|
||||||
|
}
|
||||||
|
|
||||||
|
configure_dnsmasq() {
|
||||||
|
log_info "Настройка dnsmasq..."
|
||||||
|
|
||||||
|
# Создаём конфиг для dnsmasq
|
||||||
|
local dnsmasq_config="$DNSMASQ_CONF_DIR/domain-routing.conf"
|
||||||
|
|
||||||
|
mkdir -p "$DNSMASQ_CONF_DIR"
|
||||||
|
|
||||||
|
# Очищаем старый конфиг
|
||||||
|
echo "# Auto-generated domain routing config" > "$dnsmasq_config"
|
||||||
|
echo "# Generated: $(date)" >> "$dnsmasq_config"
|
||||||
|
|
||||||
|
# Добавляем правила для каждого домена
|
||||||
|
while IFS= read -r domain || [[ -n "$domain" ]]; do
|
||||||
|
[[ -z "$domain" ]] && continue
|
||||||
|
[[ "$domain" =~ ^[[:space:]]*# ]] && continue
|
||||||
|
|
||||||
|
domain=$(echo "$domain" | tr -d '[:space:]')
|
||||||
|
|
||||||
|
# Генерируем IP для каждого домена
|
||||||
|
local ips
|
||||||
|
ips=$(dig +short "$domain" A 2>/dev/null || true)
|
||||||
|
|
||||||
|
if [[ -n "$ips" ]]; then
|
||||||
|
echo "$ips" | while read -r ip; do
|
||||||
|
if [[ -n "$ip" ]]; then
|
||||||
|
echo "server=/$domain/$ip" >> "$dnsmasq_config"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
done < "$DOMAINS_FILE"
|
||||||
|
|
||||||
|
log_info "Конфиг dnsmasq сгенерирован: $dnsmasq_config"
|
||||||
|
|
||||||
|
# Перезагружаем dnsmasq
|
||||||
|
if systemctl is-active --quiet dnsmasq; then
|
||||||
|
systemctl reload dnsmasq
|
||||||
|
log_info "Dnsmasq перезагружен"
|
||||||
|
else
|
||||||
|
log_info "Dnsmasq не запущен. Запустите: systemctl start dnsmasq"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
save_ipset() {
|
||||||
|
log_info "Сохранение ipset..."
|
||||||
|
|
||||||
|
local save_dir="/etc/ipset"
|
||||||
|
mkdir -p "$save_dir"
|
||||||
|
|
||||||
|
ipset save "$IPSET_NAME" -file "$save_dir/$IPSET_NAME.ipset"
|
||||||
|
log_info "Ipset сохранён в $save_dir/$IPSET_NAME.ipset"
|
||||||
|
}
|
||||||
|
|
||||||
|
restore_ipset_on_boot() {
|
||||||
|
log_info "Настройка автовосстановления ipset..."
|
||||||
|
|
||||||
|
# Создаём systemd service для восстановления ipset
|
||||||
|
local service_file="/etc/systemd/system/ipset-restore@$IPSET_NAME.service"
|
||||||
|
|
||||||
|
cat > "$service_file" << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Restore ipset $IPSET_NAME on boot
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/sbin/ipset restore < /etc/ipset/$IPSET_NAME.ipset
|
||||||
|
RemainAfterExit=yes
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl enable "ipset-restore@$IPSET_NAME.service"
|
||||||
|
log_info "Systemd сервис создан и включён"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# ОСНОВНАЯ ЛОГИКА
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
main() {
|
||||||
|
echo "=============================================="
|
||||||
|
echo "Domain-based Routing Setup Script"
|
||||||
|
echo "=============================================="
|
||||||
|
|
||||||
|
# Проверка прав суперпользователя
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
log_error "Скрипт должен быть запущен от имени root"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Опции командной строки
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--domains-file)
|
||||||
|
DOMAINS_FILE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--ipset-name)
|
||||||
|
IPSET_NAME="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--firewall-zone)
|
||||||
|
FIREWALL_ZONE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--dnsmasq-conf)
|
||||||
|
DNSMASQ_CONF_DIR="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--help)
|
||||||
|
echo "Usage: $0 [OPTIONS]"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " --domains-file FILE Файл со списком доменов"
|
||||||
|
echo " --ipset-name NAME Имя ipset (по умолчанию из config)"
|
||||||
|
echo " --firewall-zone ZONE Зона firewalld (по умолчанию из config)"
|
||||||
|
echo " --dnsmasq-conf DIR Директория конфигов dnsmasq"
|
||||||
|
echo " --help Показать эту справку"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log_error "Неизвестный параметр: $1"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
log_info "Конфигурация:"
|
||||||
|
echo " Domains file: $DOMAINS_FILE"
|
||||||
|
echo " IPset name: $IPSET_NAME"
|
||||||
|
echo " Firewall zone: $FIREWALL_ZONE"
|
||||||
|
echo " Dnsmasq conf: $DNSMASQ_CONF_DIR"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Шаги выполнения
|
||||||
|
check_dependencies
|
||||||
|
create_ipset
|
||||||
|
resolve_domains_to_ips
|
||||||
|
configure_firewall
|
||||||
|
configure_dnsmasq
|
||||||
|
save_ipset
|
||||||
|
restore_ipset_on_boot
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
log_info "=========================================="
|
||||||
|
log_info "Domain-based routing успешно настроен!"
|
||||||
|
log_info "=========================================="
|
||||||
|
}
|
||||||
|
|
||||||
|
# Запуск основной функции
|
||||||
|
main "$@"
|
||||||
11
domains-bird.txt.example
Normal file
11
domains-bird.txt.example
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
# Список доменов для domain-based routing с BIRD BGP
|
||||||
|
# Один домен на строку
|
||||||
|
# Строки, начинающиеся с # - комментарии
|
||||||
|
|
||||||
|
# Примеры доменов
|
||||||
|
google.com
|
||||||
|
www.google.com
|
||||||
|
amazon.com
|
||||||
|
cloudflare.com
|
||||||
|
github.com
|
||||||
|
# Добавьте свои домены здесь
|
||||||
11
domains.txt.example
Normal file
11
domains.txt.example
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
# Список доменов для domain-based routing
|
||||||
|
# Один домен на строку
|
||||||
|
# Строки, начинающиеся с # - комментарии
|
||||||
|
|
||||||
|
# Примеры доменов
|
||||||
|
google.com
|
||||||
|
www.google.com
|
||||||
|
amazon.com
|
||||||
|
cloudflare.com
|
||||||
|
github.com
|
||||||
|
# Пример списка доменов для конкретной цели
|
||||||
40
setup-example.sh
Executable file
40
setup-example.sh
Executable file
|
|
@ -0,0 +1,40 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Пример использования скрипта domain-routing.sh
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Создаём конфигурационный файл
|
||||||
|
cat > domain-routing.env << 'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Пути и файлы
|
||||||
|
DOMAINS_FILE="/opt/domain-routing/domains.txt"
|
||||||
|
DNSMASQ_CONF_DIR="/etc/dnsmasq.d"
|
||||||
|
RESOLV_CONF="/etc/resolv.conf"
|
||||||
|
|
||||||
|
# IPset и firewall
|
||||||
|
IPSET_NAME="domain_routing"
|
||||||
|
FIREWALL_ZONE="domain_routing"
|
||||||
|
|
||||||
|
# Дополнительные настройки
|
||||||
|
IPSET_OPTIONS="hashsize 4096"
|
||||||
|
IPSET_TIMEOUT=0
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Создаём файл со списком доменов
|
||||||
|
cat > domains.txt << 'EOF'
|
||||||
|
# Список доменов для маршрутизации
|
||||||
|
google.com
|
||||||
|
www.google.com
|
||||||
|
amazon.com
|
||||||
|
cloudflare.com
|
||||||
|
github.com
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "✅ Примеры конфигурационных файлов созданы"
|
||||||
|
echo ""
|
||||||
|
echo "Далее:"
|
||||||
|
echo "1. Отредактируйте domain-routing.env под ваши нужды"
|
||||||
|
echo "2. Отредактируйте domains.txt со списком доменов"
|
||||||
|
echo "3. Запустите скрипт: sudo ./domain-routing.sh"
|
||||||
Loading…
Reference in a new issue