В этом посте я расскажу о своем коротком опыте использования 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% все заведется.
Итого ... мы запускаем 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 for Android (оф. сайт)
- DNScrypt proxy for Android install (тема на XDA Developers)
- [GUIDE] How to Change DNS in Android Device (8 methods)
- DNSCrypt (Wiki по OpenWRT, к Android эта статья имеет мало отношения, но во-первых она на русском, что многим поможет, во-вторых все-таки там описывается сам dnscrypt, ключи запуска и т.п., вообщем материал для ознакомления в любом случае полезный)
- dnscrypt-proxy.8.markdown - официальный man по dnscrypt-proxy в Git'е разработчика (jedisct1)
Итак, что мы имеем - 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
Перед тем как мы будем разбираться что это, давайте убедимся что все работает. Для этого установим приложение 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 браузера прямо с ПК:
Итог:
Здесь мы видим, что сайт определил что мы используем 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 в ней работает для всей системы в целом.
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 в ней работает для всей системы в целом.