UMGUM.COM (лучше) 

Reductor + Unbound ( Интеграция сервиса web-фильтрации "Carbon Reductor" с обслуживающим рекурсивные запросы DNS-сервером. )

6 октября 2017  (обновлено 4 декабря 2017)

OS: Linux Debian 9 Stretch, Linux Ubuntu 16 LTS.

Задача: наладить подстановку поддельных сопоставлений FQDN/IP серверу обслуживания рекурсивных DNS-запросов "Unbound", используя в качестве источника "списка блокировки" сервер сервиса фильтрации пользовательского web-трафика "Carbon Reductor".

В России считается возможным блокировать жителям доступ к информации по усмотрению непорядка. Специально для этого сочинили законы, выдали привилегию тотально поражать всех в правах федеральной организации "Роскомнадзор" и предписали провайдерам не пускать клиентов туда, куда нельзя. Наиболее полный запретительный список поддерживает "Роскомнадзор", но он не единственный - есть ещё запреты от министерства юстиции, а также блокировки по региональным и даже локальным судебным решениям. В итоге каждый провайдер вынужден эти списки регулярно (раз в пару-тройку часов) актуализировать, просматривать трафик своих клиентов и пресекать обращения к ресурсам-фигурантам (IP-адресам, FQDN и URL). Понятно, что это та ещё непродуктивная возня, да ещё и по меняющимся правилам игры, так что провайдеры по большей части предпочли бы купить готовое решение в виде сопровождаемого сервиса - один из которых как раз сервер "Carbon Reductor" от московской компании "Carbon Soft".

На самом деле трафик никто не фильтрует, конечно же - исходящие запросы к web-ресурсам просто дублируют (зеркалируют) серверу, который вылавливает среди них вхождения в запретительный список и предпринимает посильные меры к блокированию доступа. Распространённые методики блокирования:

1. Фальшивый ответ (DNS Local Zones) с подставным IP-адресом запрашиваемого ресурса.
2. Фальшивый ответ (DNS Spoofing) с подставным IP-адресом запрашиваемого ресурса.
3. Фальшивый ответ (TCP:SYN/RST/FIN) об отсутствии запрашиваемого ресурса.
4. Фальшивый маршрут (OSPF, BGR) с подставным шлюзом к запрашиваемому узлу.

Первый способ, интеграцию сервиса "Carbon Reductor" с обслуживающим клиентские запросы DNS-сервером, мы здесь и рассмотрим.


Принцип работы следующий:

1. Выгружаем запретительный список всех блокируемых FQDN, уже сформированный внутри "Carbon Reductor".
2. На основе списка генерируем набор подставных сопоставлений FQDN/IP в формате используемого DNS-сервера.
3. Тестируем файл описания подставных "локальных зон" и применяем её.
4. Повторяем процедуру по расписанию.

Запросы наших клиентов обрабатываются DNS-сервером "Unbound" (пример базовой настройки). Не смотря на то, что этот сервер предназначен для обслуживания рекурсивных запросов и кеширования таковых, у него всё же есть примитивный функционал для сопоставления доменных имён и IP-адресов, реализованная через параметры "local-zone" и "stub-zone" - нам нужно лишь подставить свои значения и они будут отданы клиенту вместо настоящих IP-адресов запрашиваемых сайтов:

server:
....
  local-zone: "example.net." transparent
    local-data: "www.example.net. 300 IN A 1.2.3.4"
    local-data: "ftp.example.net. 300 IN A 1.2.3.5"
....

Конечно, программное решение этой задачи разработчики сервиса уже предложили (https://github.com/carbonsoft/named_fakezone_generator), но меня оно не устроило, хотя бы и потому, что не заработало. Пришлось изучить код и переписать его, в результате чего получился простенький Bash-скрипт, делающий всё, что нужно в рамках решения поставленной задачи.

Итак, прежде всего нужно забрать файл со списком доменных имён с сервера фильтрации.

Месторасположение перечня блокируемых доменов в "Carbon Reductor v7":

/usr/local/Reductor/lists/https.resolv

Месторасположение перечня блокируемых доменов в "Carbon Reductor v8":

/app/reductor/var/lib/reductor/lists/tmp/domains.all

Для того, чтобы просто забирать с сервера файлы, генерируем специально для этого предназначенный SSH-ключ и добавляем его в набор разрешённых на сервере "Carbon Reductor":

root@ns:# mkdir -p /etc/unbound/.ssh/
root@ns:# ssh-keygen -t rsa -b 4096 -f /etc/unbound/.ssh/id_rsa_root_ns.example.net -C "root@ns.example.net"
root@ns:# ssh-copy-id -i /etc/unbound/.ssh/id_rsa_root_ns.example.net root@reductor.example.net
root@ns:# chown -R root:root /etc/unbound/.ssh/
root@ns:# chmod -R go-rwx /etc/unbound/.ssh/

В дальнейшем в скриптах будем использовать команды SSH с явным указанием идентификационного файла "-i /etc/unbound/.ssh/id_rsa_root_ns.example.net".

Современные доменные имена могут содержать символы национальных алфавитов, закодированные в соответствии со спецификацией IDN (Internationalized Domain Names). Устанавливаем утилиту перекодировки:

# aptitude install idn

Пишем рабочий скрипт как таковой:

# mkdir -p /etc/unbound/scripts
# vi /etc/unbound/scripts/crb-reductor-generator.sh
# chmod ug+x /etc/unbound/scripts/crb-reductor-generator.sh

#!/bin/bash

###
### Скрипт выгрузки перечня FQDN блокируемых "Carbon Reductor",
### генерирования конфигурации с набором "фейковых локальных зон"
### и применения такового в "Unbound".
###

# IP-адрес сервера "Carbon Reductor", предоставляющего перечня блокируемых FQDN
SRC_SRV="1.2.3.4"

# Имя исходного файла с перечнем блокируемых FQDN
SRC_LIST="/app/reductor/var/lib/reductor/lists/tmp/domains.all"

# IP-адрес web-сервера со страницей-заглушкой, показываемой вместо ресурса с блокируемым FQDN
PEG_IP="1.2.3.4"

# Имя финального файла набора подставных "локальных зон" DNS-сервера "Unbound"
TRG_CONF="/etc/unbound/conf.d/crb-reductor-fakezones.conf"

# Месторасположение журнала событий этапов работы скрипта
LOG="/var/log/crb-reductor-fakezones.log"

# Создаём и запоминаем временные файлы, используемые для последовательной обработки списков
TMP_F1=$(mktemp --tmpdir=/tmp); TMP_F2=$(mktemp --tmpdir=/tmp); TMP_F3=$(mktemp --tmpdir=/tmp)

# Пресекаем конкурентный запуск этого же скрипта
if [ `pgrep -f -c $(basename "$0")` -ne 1 ]
then
  echo "Обнаружен уже запущенный экземпляр этого генератора. Процедура прервана."
  exit 1
fi

# Загружаем перечень FQDN, предназначенных для блокировки
scp -q -i /etc/unbound/.ssh/id_rsa_root_ns.example.net root@${SRC_SRV}:${SRC_LIST} ${TMP_F1}

# Очищаем данные от пробельных символов, сортируем список, попутно исключая дубликаты, и конвертируем национальные символы IDN в "Punycode"
cat "${TMP_F1}" | sed 's/\.$//' | tr -d ' ' | sed -e 's/^www\.//' | idn | sort -u  > "${TMP_F2}"

# Генерируем конфигурационный файл в формате Unbound, подставляя адрес сервера со страницей-заглушкой
echo "server:" >> "${TMP_F3}"
while read FQDN; do
  echo "  domain-insecure: \"${FQDN}\"" >> "${TMP_F3}"
  echo "  local-zone: \"${FQDN}\" redirect" >> "${TMP_F3}"
  echo "    local-data: \"${FQDN} 300 IN A ${PEG_IP}\"" >> "${TMP_F3}"
done < "${TMP_F2}"

# Если итоговый файл не пустой, то копируем его в рабочую область, с последующим применением
if [ -s "${TMP_F3}" ]
then
  cat "${TMP_F3}" > "${TRG_CONF}"
  unbound-checkconf -f "${TRG_CONF}" > /dev/null 2>&1
  if [ "$?" -eq "0" ]
  then
    # Перезагружаем конфигурацию Unbound
    /etc/init.d/unbound reload > /dev/null 2>&1
    [ "$?" -eq "0" ] && echo "`date`: Ok" >> "${LOG}" || echo "`date`: Error reload!" >> "${LOG}"
  else
    # Ввиду обнаружения некорректной конфигурации удаляем таковую и прерываем процедуру
    echo "Зафиксирован сбой работы генератора: некорректное содержимое итогового конфигурационного файла. Процедура прервана."
    echo "`date`: Error generation!" >> "${LOG}"
    rm -f "${TRG_CONF}"
    exit 1
  fi
else
  echo "Зафиксирован сбой работы генератора: отсутствует содержимое итогового конфигурационного файла. Процедура прервана."
  exit 1
fi

# Удаляем временные файлы
rm -f "${TMP_F1}" "${TMP_F2}" "${TMP_F3}"

exit 0

# chown -R root:root /etc/unbound/scripts/
# chmod -R go-rwx /etc/unbound/scripts/

На практике 40000 (сорок тысяч) FQDN, спускаемых ныне "Роскомнадзор"-ом, обрабатываются скриптом менее чем за полминуты. Самим DNS-сервером "Unbound" конфигурация принимается в работу вообще мгновенно.

Ясное дело, что списки нужно регулярно обновлять. Если DNS-серверов несколько, то удобно сделать непересекающееся расписание, чтобы минимизировать возможность простоя сервисов (для своих двух серверов я делаю это каждые 15 и 23 минуты):

# vi /etc/crontab

....
# Run the "Carbon Reductor" fake-zone generator script
*/23 *  * * *  root  /etc/unbound/scripts/crb-reductor-generator.sh &

В журналы событий пишется немного, но для порядка всё же включим для них ротацию:

# vim /etc/logrotate.d/crb-reductor-generator

/var/log/crb-reductor-fakezones.log {
  monthly
  rotate 3
  size 10M
  missingok
  notifempty
  compress
  delaycompress
  copytruncate
  su root root
}

Вот так мы делаем мир чище.


Заметки и комментарии к публикации:


Оставьте свой комментарий ( выразите мнение относительно публикации, поделитесь дополнительными сведениями или укажите на ошибку )