Предыстория


Прожорливый Bind9


Пришлось мне пару лет назад покинуть свой родной дом и переехать в другой город. В результате свой самосборный медиа-центр пришлось оставить, а на новом месте купить телеприставку AuraHD Plus. Весьма не плохой девайс за свои деньги, особенно если учесть, что в нем встроены приложения для доступа к сервисам с фильмами и т.п.


Все бы ничего, но реклама там крутится на каждый чих. Пришлось изобретать, как же ее "порезать". Первая мысль была — поднять свой DNS сервер и отправлять все неугодные домены в /dev/null на 127.0.0.1. К этому моменту мой домашний серверок вернулся ко мне и занял свое почетное место на шкафу в качестве NAS сервера.


Сказано — сделано. Поднят Bind9, прописаны конфиги для нескольких доменов, все отлично. Летим.


Спустя пару недель пришла мысль в голову, а почему бы не использовать этот метод для фильтрации рекламы для всех устройств дома? Дело не хитрое же.


Поиск списков с рекламными доменами привел меня к нескольким урлам и я взялся их парсить. Где-то на просторах Хабра была статья, которая помогла мне с парсингом и написанием скриптов для генерации конфигов для Bind9 (спасибо автору, но я не смог найти ссылку, пусть меня простит).


Все сделано и пришло время запускать Bind9. Старт и все отлично. Кроме одного. Этот прожорливый монстр съел всю оперативку и попросил своп. 5 гигабайт памяти на 400 тысяч доменов!


По-мучая таким образом свой бедный сервер на Intel Atom я решил, что это не дело.


Миграция на PowerDNS


Погуглив и поизучав другие варианты, я пришел к выводу, что Bind9 не совсем то, что нужно. Нужен более легкий по ресурсам DNS сервер, который смог бы лопатить такое количество доменов.


PowerDNS подошел как нельзя к стати, т.к. он умеет сам читать конфиги Bind9 и использовать их в работе. Поставил, настроил (собственно в этом нет никакой сложности) backend Bind9 запустил.


Результат превзошел все ожидания — 700 MB потребляемой памяти после 5 гигабайт! Это ли не мечта? Особенно при наличии всего 4 GB в сервере. :)


Несколько месяцев так все и проработало, пока я не задумался, что конфиги Bind9 это конечно хорошо, но старт PowerDNS какой-то ну совсем медленный. Время на "всасывание" всех доменов до неприличия большое и стоит как-то оптимизировать этот процесс.


Из оптимизации оставалось влить только все эти домены с рекламой в MySQL. Это дало бы возможность более гибко управлять списком доменов, добавлять, удалять, поддерживать свои внутренние домены.


Закатали рукава и приступили. Оказалось все довольно просто — zone2sql решает все проблемы :) Оставалось завернуть все это в доккер и поднять. Сделал довольно быстро и без особых проблем.


Так оно летит уже с полгода дома и радует. Но сегодня вышла статья на Хабре о блокировщике рекламы для смартфонов Samsung и мне предложили в комментариях выдать мое поделие в открытый доступ.


Что ж, делюсь.


Зависимости


docker


Поскольку все это крутится внутри контейнеров docker, то эта штука нам 100% понадобится. Все действия относятся к Ubuntu Linux, т.к. именно его я использую дома и в работе.


Устанавливается она согласно документации достаточно просто:


curl -sSL https://get.docker.com/ | sh

После завершения работы скрипта docker будет готов и им можно пользоваться.


Если вы предпочитаете другой метод установки, то всегда можно обратиться к документации и выбрать то, что вам будет по душе.


docker-compose


Docker Compose предназначен для планирования и организации процессов в контейнерах Docker (запуска, отключения, создания межконтейнерных соединений и томов, и т.п.).


Установка не сложнее самого докера:


curl -L "https://github.com/docker/compose/releases/download/1.8.1/docker-compose-$(uname -s)-$(uname -m)" > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

Запуск собственного фильтра рекламы


Клонируем репозиторий


Логичное действие и не нуждается, наверное, в пояснениях, зачем это делать. :)


sudo mkdir /opt/docker
sudo chown <user> /opt/docker
git clone https://github.com/DmitriyLyalyuev/powerdns-no-ads /opt/docker/pdns
cd /opt/docker/pdns

Создаем базу данных


docker-compose up -d mysql

Пользователь базы данных


Для доступа к консоли MySQL сервера нужно выполнить:


docker exec -ti pdns_mysql_1 mysql -u root -p

Пароль по умолчанию для пользователя root — 12345.


Создаем пользователя и базу:


CREATE USER 'powerdns_user'@'%' IDENTIFIED BY 'powerdns';
GRANT ALL PRIVILEGES ON powerdns.* TO 'powerdns_user'@'%';
CREATE DATABASE powerdns;
exit

Стартуем DNS сервер


docker-compose up -d

Обновление списков рекламных доменов


Для обновления списков запускаем:


docker exec -ti pdns_pdns_1 bash
cd /etc/powerdns/bind
./getnewlist.sh && ./import.sh && ./clean.sh
exit

White listing


Список для исключения доменов содержится в начале файла /opt/docker/pdns/powerdns-server/bind/getnewlist.sh.


Пользуйтесь, экспериментируйте и давайте сделаем интернет чище. Хотя бы у себя дома. ;)

Поделиться с друзьями
-->

Комментарии (33)


  1. Dreyk
    02.11.2016 14:16
    +1

    Спасибо!


    Создание базы можно подсунуть в скрипт


        volumes:
          - /opt/docker/mysql/data:/var/lib/mysql
          - /opt/docker/mysql/structure/:/docker-entrypoint-initdb.d

    тогда база будет создаваться сама.


    UPD: а, у вас maria, надо посмотреть, умеет ли их image такую штуку
    UPD2: да, умеет, тут у них с mysql совместимость


    1. dmitriylyalyuev
      02.11.2016 14:17

      Спасибо, посмотрю в эту сторону. :)


  1. 776166
    02.11.2016 14:29
    -4

    когда вы повыедетесь уже! :) ©


    1. 4dmonster
      02.11.2016 15:35
      +2

      Глупость, повторенная дважды, не становиться шуткой.


      1. 776166
        02.11.2016 15:36
        -1

        Блокировка рекламы — это вам не шутки.


        1. 4dmonster
          02.11.2016 15:37
          +6

          Да, это вынужденная необходимость.


          1. 776166
            02.11.2016 19:00
            -1

            Не думаю, что это вынужденная необходимость: блокировать всю рекламу скопом.


            1. 4dmonster
              04.11.2016 12:59

              Поскольку в настоящее время, это решение работает лучше, чем решение с «приемлемой» рекламой, мы вынуждены блокировать всю рекламу.
              Пока нет возможности отфильтровать только порнуху, мошенников и неприемлемые форматы, блокироваться будет всё.


      1. romxx
        03.11.2016 12:26

        Она становится мемом, судя по тому, что творится в интернетиках на этот счет.


        1. 4dmonster
          04.11.2016 12:59
          +1

          Даже если её форсят, не всякая глупость может стать мемом.


  1. lolipop
    02.11.2016 14:53
    +1

    dnsmasq потребляет память в килобайтах, делает всё то же самое, работает даже на роутерах с 16мб оперативки.
    зачем этот велосипед было городить — непонятно.


    1. dmitriylyalyuev
      02.11.2016 14:58
      +2

      Вы в него пробовали запихнуть 400 тысяч доменов?
      Пробовали управлять всем этим делом?
      Как быстро он стартует с таким багажом?

      Сомневаюсь, что он сможет это все адекватно переваривать.


      1. lolipop
        02.11.2016 15:43

        root@router:/etc/dnsmasq.d# cat ad* | wc -l
        635317
        стартует минуту на слабом железе.


        1. dmitriylyalyuev
          02.11.2016 16:15
          +1

          Рад, что он так отлично работает. Надо будет посмотреть в его сторону.


          1. acmnu
            02.11.2016 16:41

            На самом деле причина такой колосальной разницы между «настоящими» DNS и dnsmaq в том, что большие DNS сделаны для того, чтобы обслуживать крупные авторитативные DNS в интернете. Поэтому они сразу тащат все в память, предполагая, что производительность важнее и хостер с 400к доменов уж может себе позволить 5G памяти.

            А dnsmasq сделан именно как прокладка между локальным компом или максимум локальной сеткой и большим миром, поэтому логика его работы совсем другая. Если не пытаться разом обратится ко все 600К доменам, то и память он не должен так кушать.


            1. lolipop
              02.11.2016 22:36

              там вроде как хэш-таблица используется.


        1. tony
          02.11.2016 16:34

          поделитесь роскошным файликом)


          1. wmlex
            02.11.2016 16:49
            +1

            Тоже использую dnsmasq для блокировки рекламы.
            # cat /etc/dnsmasq.hosts | wc -l
            48306

            Базы обновляю при помощи скрипта в cron.

            #!/bin/bash
            #
            if test -s /tmp/hosts_list.*
            then
                rm -f /tmp/hosts_list.*
            fi
            wget --no-check-certificate -O /tmp/hosts_list.1 http://hosts-file.net/ad_servers.txt &&
            wget --no-check-certificate -O /tmp/hosts_list.2 https://adaway.org/hosts.txt &&
            cat /tmp/hosts_list.* | grep -v ^# | sort -u > /etc/dnsmasq.hosts &&
            rm -f /tmp/hosts_list.* &&
            /bin/systemctl reload dnsmasq
            


    1. neumeika
      02.11.2016 16:46

      так же быстр nsd, хотя да, dnsmasq есть во всех роутерах,
      А уж цеплять скуль к днс — сильное снижение времени ответа


      1. dmitriylyalyuev
        02.11.2016 16:47
        -1

        $ dig @127.0.0.1 ya.ru
        
        ; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> @127.0.0.1 ya.ru
        ; (1 server found)
        ;; global options: +cmd
        ;; Got answer:
        ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30975
        ;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
        
        ;; OPT PSEUDOSECTION:
        ; EDNS: version: 0, flags:; udp: 512
        ;; QUESTION SECTION:
        ;ya.ru.             IN  A
        
        ;; ANSWER SECTION:
        ya.ru.          6685    IN  A   213.180.193.3
        ya.ru.          6685    IN  A   93.158.134.3
        ya.ru.          6685    IN  A   213.180.204.3
        
        ;; Query time: 44 msec
        ;; SERVER: 127.0.0.1#53(127.0.0.1)
        ;; WHEN: Wed Nov 02 15:46:33 EET 2016
        ;; MSG SIZE  rcvd: 82

        Да вроде не сильно снижает время ответа. ;)


        1. neumeika
          02.11.2016 17:01

          Это, прошу прощения, в сравнении с чем?
          у меня вафлероутер (на атоме вроде) говорит за 1(кеш) и 4 (not cached) msec, т.е. в 11 раз быстрее, что всё-таки является показателем, имхо.
          Про unbound забыл, тоже очень быстрое/простое поделие, но сие для диких нагрузок


          1. dmitriylyalyuev
            02.11.2016 17:04
            +1

            Вот и я говорю — в сравнении с чем… Меня это время ответа устраивает. Я из дома не устраиваю гонки на бирже. Меня больше волнует отсутствие рекламы дома.


            На работе я не использую PowerDNS, само собой. Там все по другому.


          1. dmitriylyalyuev
            03.11.2016 23:56

            Сделал вот на dnsmasq — https://github.com/DmitriyLyalyuev/dnsmasq-no-ads
            Но статью писать по этому делу, думаю, не стоит. :)


  1. sena
    02.11.2016 16:38
    +1

    Вроде бы squid для этого раньше применяли.


    1. dmitriylyalyuev
      02.11.2016 16:38
      +1

      Прокси мне дома только и не хватало.


      1. sena
        02.11.2016 17:53

        Зато он не только просто DNS, а по URL блокировать может.


  1. Ivan_83
    02.11.2016 21:36

    Капетанская тема.

    бинд — тот ещё кусок мамонта.
    700 метров поверднса тоже перебор.

    Докер тут лишний, как и база: там конфигов полторы штуки компактно лежат в одной папке, ради этого использовать докер, созданный в качестве костыля для горе погромистов у которых прога работает только на компе на котором написана или горе админов, которые не в силах осилить повторную настройку софтины.

    Нафига держать список из ххх тыщ доменов не понятно, когда хватает от силы пары сотен чтобы не видеть 99% рекламы, ибо она в основном в популярных сетях крутится а их мало.

    Юзаю unbound, он занимается рекурсией (те ни провайдерские днс ни 8.8.8.8 мне ну нужны вообще), навесил на него ещё и фильтрацию: для доменов из списка он возвращает NX — те типа домена нет, это лучше чем 127.0.0.0 или прочее.
    Вот блок для гугла:
    ### Google
    local-zone: «doubleclick.net» static
    local-zone: «fonts.googleapis.com» static
    local-zone: «google-analytics.com» static
    local-zone: «google-analyzing.com» static
    local-zone: «googleadservices.com» static
    local-zone: «googlesyndication.com» static
    local-zone: «safebrowsing-cache.google.com» static
    local-zone: «safebrowsing.clients.google.com» static
    local-zone: «safebrowsing.google.com» static
    local-zone: «video-stats.video.google.com» static

    2 lolipop
    Днсмаск как днс — фуфло полное.
    Он не умеет рекурсию, кеш там посредственный, про DNSec молчу, ибо не нужен.

    2 sena
    Раньше да.
    Потом я применял nginx для проксирования с целью фильтрации, потом стало много https и такое проксирование стало практически бесполезно.
    С приходом блокировок я вернул nginx, он теперь автоматом проксирует сайты которые напрямую открыть не может.

    2 acmnu
    бинд сделан чтобы соотвествовать тому что написано в RFC, это основная цель работы его создателей — ISC, производительность и пр для них глубоко вторичны.

    2 neumeika
    анбоунд далеко не прост.
    Там и рекурсер и кеш и валидатор и пр, собирается он далеко не моментально с исходников.


    1. neumeika
      02.11.2016 21:56

      Проще чем bind, ни вьюх, ни плагинов, бэкенд не поменяешь для зон.
      Из исходников? я подобным только на проектах с BSD занимаюсь, а там j4, минимум.


  1. SlavikF
    03.11.2016 00:39

    Снизойдите ко мне, если я совсем в танке…
    Я, в общем знаю, что такое DNS, а вот Bind и прочее — не сильно.

    Из статьи я понял, как настроить сёрвис, нокак вот сделать так, чтобы мои устройства дома использовали этот сёрвис?
    — нужно ли будет в каждом устройстве прописывать DNS server, указывая на мой?
    — или это каким-то образом надо будет сделать на роутере, чтобы он всем раздавал это в настройках сети через DHCP?


    1. strelkan
      03.11.2016 08:31

      dhcp в стандартных прошивках роутеров обычно указывает себя в качестве днс-сервера, всё зависит от модели


      1. SlavikF
        03.11.2016 08:35

        Ну да. Поэтому я и спрашиваю — как заставить это всё работать?
        Нужно чтобы роутер умел указывать на нужный DNS? Или он указывает на себя, а сам смотрит на поставленный PowerDNS вместо провайдера?
        Или надо на конечных устройствах указывать на свой PowerDNS сервер?


        1. kav4ik
          03.11.2016 09:28

          В роутере указать свой DNS в настройках WAN.


  1. nickon
    03.11.2016 23:00

    Есть ещё вариант из коробки, на малинке — pi-hole.net