DNSCrypt for Android: защита DNS-запросов

В этом посте я расскажу о своем коротком опыте использования DNSCrypt для Android. Для тех кто не в курсе что это такое, рекомендую прочитать, например, вот это: Protect: защита DNS-запросов. Речь там правда идет про технологию DNSCrypt, используемую в Яндекс.Браузере, но общий смысл того как защищаются DNS запросы - думаю из нее понятен. Так вот примерно то же самое мы будем делать для нашего смартфона на Android, но не для какого-то определенного приложения, а для всей операционной системы в целом. При этом, я не рассматриваю вопрос использования DNSCrypt на стоковых прошивках, так как зачастую он может потребовать от вас дополнительных действий для того чтобы все это работало автоматически, например, как минимум, получения root-прав, модификации ядра для поддержки init.d или использования приложения Universal Init.d. Вообщем этот путь несколько сложноват ... гораздо проще использовать любую CyanogenMod-based прошивку, в моем случае ей оказалась LineageOS 14, которую я собрал для Tele2 Maxi LTE. Перед тем как мы начнем, давайте ознакомимся со следующими статьями и материалами:


Итак, что мы имеем - Tele2 Maxi LTE с LineageOS 14 и желание попробовать dnscrypt в действии. Я не стал собирать ничего из исходников, а зашел на страницу Downloads проекта dnscrypt и скачал оттуда архив dnscrypt-proxy-android-armv7-a-1.9.4.zip . Она расчитан на armv7a архитектуру, у меня в аппарате правда используется 64-bit'ная ОС, но т.к. CPU, естественно, "понимает" armv7a, то собранный 32-bit'ный бинарник также будет работать. Перед тем как установить этот архив через TWRP или другой кастомный recovery я предлагаю вам открыть его и посмотреть из чего он состоит, т.е. сами бинарники, конфиги и скрипты инициализации которые кладутся в addon.d и init.d. Напомню что CM / Lineage у нас полностью подготовлен для установки этого архива, т.е. после его прошивки с вероятность 99% все заведется.

Посмотрим на скрипт инициализации 99dnscrypt в init.d, последними строками в нем мы видим:

dnscrypt-proxy \
--daemonize \
--loglevel=3 \
--resolver-name="$RESOLVER_NAME" \
--resolvers-list=/system/etc/dnscrypt-proxy/dnscrypt-resolvers.csv && \
iptables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to-destination 127.0.0.1 && \
iptables -t nat -A OUTPUT -p tcp --dport 53 -j DNAT --to-destination 127.0.0.1

Итого ... мы запускаем dnscrypt-proxy в качестве "демона" с резольвером $RESOLVER_NAME (по-умолчанию кстати в скрипте инициализации прописаны dnscrypt.org-fr и okturtles, я бы заменил их на cisco и yandex, первый использует OpenDNS, ну а Yandex в представлении не нуждается), плюс добавляем правила iptables для редиректа всех DNS запросов на наш dnscrypt-proxy.

Перед тем как мы будем разбираться что это, давайте убедимся что все работает. Для этого установим приложение DNS Lookup из Play Market, добавим туда DNS сервер 127.0.0.1 (наш
dnscrypt-proxy) и попробуем разрешить любое имя, например www.decker.su . Если все установлено и работает правильно, то вы получите ответ следующего вида:


Это значит, что вся наша схема работает и DNS Crypt успешно передает шифрованный DNS запрос и отдает нам ответ. Если у вас это так - то поздравляю, если нет - то, печально, и вам нужно разбираться что именно у вас не работает. А я сейчас попытаюсь рассказать как оно должно работать. Для этого я зайду в adb shell и с помощью kill завершу работающий процесс dnscrypt-proxy, чтобы дальше нам уже можно было запустить его вручную с логами и т.п. Т.е. чтобы все было видно наглядно:


Здесь мы запустили dnscrypt-proxy уже в ручную с выбором резольвера "cisco", который использует Cisco OpenDNS. Для проверки того что у нас используется именно этот резольвер и именно OpenDNS откроем страницу теста - http://www.opendns.com/welcome/ в браузере телефона, я запустил Activity браузера прямо с ПК:

adb shell am start -a android.intent.action.VIEW -d http://www.opendns.com/welcome/

Итог:


Здесь мы видим, что сайт определил что мы используем OpenDNS (как я понял резольвер cisco описанный в dnscrypt-resolvers.csv использует именно OpenDNS) в результате чего у нас видна галочка на первом скрине вместо надписи "You aren’t using OpenDNS yet", а второй тест с internetbadguys.com показал нам что защита от фишинговых ресурсов, встроенная в OpenDNS у нас работает на ура. Если вы были внимательны, то наверняка зададите резонный вопрос. Подождите, понятно что dnscrypt-proxy у нас отвечает на 127.0.0.1:53 в телефоне, но почему запросы резольвятся именно через него, а не через DNS серверы вашего WiFi или мобильного подключения? Все дело в тех самых правилах iptables в 99dnscrypt. Давайте посмотрим таблицу NAT:

Как видно, любые DNS запросы на всех интерфейсах у нас заворачиваются на 127.0.0.1 ... счетчик показывает что через правило прошло 145 пакетов. Т.е. было уже 145 обращений к DNS серверам со стороны ОС и все они были пропущены через dnscrypt-proxy. Другими словами, если например какое-то приложение, например, ваш браузер, запрашивает резольвинг имени сервера www.decker.su у дефолтного DNS сервера вашего интернет подключения, то вне зависимости от того какой DNS сервер использует ваше интернет подключение запрос будет перенаправлен к dnscrypt-proxy. Вот такое вот прозрачное "проксирование DNS" и в результате все наши DNS запросы защищены.

Надеюсь после небольшого объяснения и приведенных картинок смысл того что происходит в системе более понятен.

Вообщем-то и все. Единственное что я еще сделал дополнительно, это в файле system/etc/init.d/99dnscrypt изменил два резольвера, которые dnscrypt-proxy пытается использовать по-умолчанию:


p.s. Если прочитав бегло этот пост вы почему-то не захотели вдаваться в технические подробности, а просто установили архив dnscrypt-proxy-android-armv7-a-1.9.4.zip через TWRP и хотите понять работает оно у вас или нет, то просто установите приложение DNS Lookup, как показано выше, и проверьте что сервер 127.0.0.1 отдает у вас имена. Либо воспользуйтесь любым онлайн DNS Leak тестом, например https://www.grc.com/dns/dns.htm или http://dnsleak.com/ :


При этом ни наш интернет-провайдер (если мы подключены через WiFi), ни оператор сотовой связи не видят наших DNS запросов, т.к. они передаются на DNS-сервер с поддержкой DNSCrypt по защищенному каналу. Ну вот как-то так ...

В завершении рекомендую вам прочитать еще одну статью, на этот раз уже на Хабре - Решаем проблему перехвата и подмены DNS-запросов. DNSCrypt в Яндекс.Браузере. Речь в ней опять же идет про Яндекс.Браузер, но у нас как вы понимаете, все описанное в статье, относится не только к браузеру, а к нашей ОС Android полностью, т.к. DNSCrypt в ней работает для всей системы в целом. 
Share This :



sentiment_satisfied Emoticon