ValdikSS / blockcheck

Russian ISP blocking type checker NOTE: NOT WORKING CURRENTLY. ВНИМАНИЕ: НЕ РАБОТАЕТ НА ТЕКУЩИЙ МОМЕНТ
MIT License
1.37k stars 143 forks source link

ESNI #80

Open 4ndv opened 5 years ago

4ndv commented 5 years ago

Возможно ли для сайтов, использующих cloudflare, добавить проверку с использованием ESNI? Как для заблокированных, так и для незаблокированных, ибо мой провайдер, по всем признакам, не пропускает вообще ничего с ESNI.

ValdikSS commented 5 years ago

Думаю, проблема не в наличии ESNI, а в отсутствии SNI в пакетах с ESNI. DPI не может определить, к какому домену производится доступ, и блокирует соединение.

4ndv commented 5 years ago

Да, думаю, в этом и есть причина на самом деле. Но было бы интересно видеть и такую проверку (на реакцию при отсутствующем SNI), если оно не сильно трудозатратно. ESNI пока все равно рано реализовывать, он еще не готов толком.

ValdikSS commented 5 years ago

Думаю, нужно переделывать Blockcheck на использование низкоуровневых библиотек работы с сетью и шифрованием.

ValdikSS commented 5 years ago

@4ndv см. https://github.com/ValdikSS/blockcheck/issues/84 Попробуйте, пожалуйста. Теста ESNI там нет, зато есть тест запроса без SNI, что даст некоторое представление о работе разных DPI с ESNI.

4ndv commented 5 years ago

Спс, попробую вечером, как доберусь до виндовой машины

4ndv commented 5 years ago

Результаты для моего провайдера:

[O] Тестируем обход DPI (HTTPS)
     Пробуем Обычный запрос на dailymotion.com
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello без SNI на dailymotion.com
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello с большим padding на dailymotion.com
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello с большим padding и SNI только в конце padding на dailymotion.com
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello с большим padding, поддельным SNI в начале и правильным до padding на dailymotion.com
[✓] Сайт открывается
     Пробуем ClientHello с большим padding, поддельным SNI в начале и правильным после padding на dailymotion.com
[✓] Сайт открывается
     Пробуем Обычный запрос на danbooru.donmai.us
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello без SNI на danbooru.donmai.us
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello с большим padding на danbooru.donmai.us
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello с большим padding и SNI только в конце padding на danbooru.donmai.us
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello с большим padding, поддельным SNI в начале и правильным до padding на danbooru.donmai.us
[☠] Ошибка (TLS): SSLError(1, '[SSL: TLSV1_ALERT_DECODE_ERROR] tlsv1 alert decode error (_ssl.c:1076)')
     Пробуем ClientHello с большим padding, поддельным SNI в начале и правильным после padding на danbooru.donmai.us
[☠] Ошибка (TLS): SSLError(1, '[SSL: TLSV1_ALERT_DECODE_ERROR] tlsv1 alert decode error (_ssl.c:1076)')
     Пробуем Обычный запрос на e621.net
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello без SNI на e621.net
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello с большим padding на e621.net
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello с большим padding и SNI только в конце padding на e621.net
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello с большим padding, поддельным SNI в начале и правильным до padding на e621.net
[☠] Ошибка (TLS): SSLError(1, '[SSL: TLSV1_ALERT_DECODE_ERROR] tlsv1 alert decode error (_ssl.c:1076)')
     Пробуем ClientHello с большим padding, поддельным SNI в начале и правильным после padding на e621.net
[☠] Ошибка (TLS): SSLError(1, '[SSL: TLSV1_ALERT_DECODE_ERROR] tlsv1 alert decode error (_ssl.c:1076)')
     Пробуем Обычный запрос на gelbooru.com
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello без SNI на gelbooru.com
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello с большим padding на gelbooru.com
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello с большим padding и SNI только в конце padding на gelbooru.com
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello с большим padding, поддельным SNI в начале и правильным до padding на gelbooru.com
[☠] Ошибка (TLS): SSLError(1, '[SSL: TLSV1_ALERT_DECODE_ERROR] tlsv1 alert decode error (_ssl.c:1076)')
     Пробуем ClientHello с большим padding, поддельным SNI в начале и правильным после padding на gelbooru.com
[☠] Ошибка (TLS): SSLError(1, '[SSL: TLSV1_ALERT_DECODE_ERROR] tlsv1 alert decode error (_ssl.c:1076)')
     Пробуем Обычный запрос на rutracker.org
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello без SNI на rutracker.org
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello с большим padding на rutracker.org
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello с большим padding и SNI только в конце padding на rutracker.org
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello с большим padding, поддельным SNI в начале и правильным до padding на rutracker.org
[✓] Сайт открывается
     Пробуем ClientHello с большим padding, поддельным SNI в начале и правильным после padding на rutracker.org
[✓] Сайт открывается
     Пробуем Обычный запрос на zello.com
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello без SNI на zello.com
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello с большим padding на zello.com
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello с большим padding и SNI только в конце padding на zello.com
[☠] Ошибка (TLS): ConnectionResetError(10054, 'Удаленный хост принудительно разорвал существующее подключение', None, 10054, None)
     Пробуем ClientHello с большим padding, поддельным SNI в начале и правильным до padding на zello.com
[☠] Ошибка (TLS): SSLError(1, '[SSL: TLSV1_ALERT_DECODE_ERROR] tlsv1 alert decode error (_ssl.c:1076)')
     Пробуем ClientHello с большим padding, поддельным SNI в начале и правильным после padding на zello.com
[☠] Ошибка (TLS): SSLError(1, '[SSL: TLSV1_ALERT_DECODE_ERROR] tlsv1 alert decode error (_ssl.c:1076)')
ValdikSS commented 5 years ago

Ваш провайдер блокирует пакеты без SNI. Включение ESNI приведет к недоступности части сайтов, которые были доступны без ESNI.

4ndv commented 5 years ago

А проверяется ли, провайдер блокирует вообще все сайты без SNI, или только на заблокированных айпишниках?

ValdikSS commented 5 years ago

Это не проверяется. Можно проверить самостоятельно, скачав OpenSSL и запустив, например: openssl s_client -host yandex.ru -port 443 -noservername

4ndv commented 5 years ago

Судя по всему, в отсутствие SNI мой провайдер блокирует по IP:

  1. openssl s_client -host yandex.ru -port 443 - ок (на моей версии openssl он не понимал опцию -noservername, но судя по всему, ей нужно наоборот принудительно передавать -servername, проверял по вайршарку)
  2. ▲ ~ openssl s_client -host e621.net -port 443
    CONNECTED(00000006)
    write:errno=54
    ---
    no peer certificate available
    ---
    No client certificate CA names sent
    ---
    SSL handshake has read 0 bytes and written 0 bytes
    ---
    New, (NONE), Cipher is (NONE)
    Secure Renegotiation IS NOT supported
    Compression: NONE
    Expansion: NONE
    No ALPN negotiated
    SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : 0000
    Session-ID:
    Session-ID-ctx:
    Master-Key:
    Start Time: 1569272449
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    ---

То же самое, соответственно, и с openssl s_client -host e621.net -port 443 -servername e621.net

  1. openssl s_client -host e621.net -port 443 -servername cloudflare.com - ок

А дальше - лучше.

В голову приходит следующее:

  1. openssl s_client -host cloudflare.com -port 443 -servername e621.net

Ииии... оно успешно соединяется о_О

dig a cloudflare.com + 198.41.214.162 e621.net в /etc/hosts => успешно открывающийся глутамат в хроме (причем, ff игнорировал hosts, видимо, по причине включенного doh, или потому что я его не перезапустил, или хрен его знает почему)

И это все при том, что blockcheck выдает "у вашего провайдера полный DPI"

ValdikSS commented 5 years ago

Ииии... оно успешно соединяется о_О

Да, такая особенность у CloudFlare. Он не позволяет делать полноценный Domain Fronting, зато можно подключаться к любому IP-адресу CloudFlare.

4ndv commented 5 years ago

Да, но разве глутамат (e621.net) не заблокирован по домену?

4ndv commented 5 years ago

То есть, я беру ip от cloudflare.com, и, совершенно не стеснясь и не скрывая, по SNI запрашиваю e621.net, который успешно открывается в хроме.

изображение

изображение

Соответственно, как только я в хостах комментирую эту запись и перезапускаю хром, открываться он перестаёт

ValdikSS commented 5 years ago

И это все при том, что blockcheck выдает "у вашего провайдера полный DPI"

Это означает, что ваш провайдер обнаруживает HTTP-запрос на любом IP-адресе и порту, а не только на 80.

[O] Тестируем HTTP
    Открываем  http://a.putinhuylo.com/
[✓] Сайт открывается
    Открываем  http://furry.booru.org/
[✓] Сайт открывается
    Открываем  http://furry.booru.org/index.php?page=post&s=view&id=111173
[☠] Сайт не открывается, пробуем через прокси
[☠] Сайт не открывается через прокси
    Проверяем доступность через isup.me
[☠] Сайт доступен, проблемы только у нас
    Открываем  http://pbooru.com/
[✓] Сайт открывается
    Открываем  http://pbooru.com/index.php?page=post&s=view&id=303026
[☠] Сайт не открывается, пробуем через прокси
[☠] Сайт не открывается через прокси
    Проверяем доступность через isup.me
[☠] Сайт доступен, проблемы только у нас
    Открываем  http://rutracker.org/forum/index.php
[☠] Сайт не открывается, пробуем через прокси
[☠] Сайт не открывается через прокси
    Проверяем доступность через isup.me
[☠] Сайт доступен, проблемы только у нас

Сайт не открылся даже через прокси антизапрета. DPI обнаружил попытку доступа к заблокированному URL даже через незаблокированный IP-адрес и порт 3128 прокси-сервера, и перенаправил на заглушку. Это я называю полным DPI.

ValdikSS commented 5 years ago

То есть, я беру ip от cloudflare.com, и, совершенно не стеснясь и не скрывая, по SNI запрашиваю e621.net, который успешно открывается в хроме.

Да, всё верно. Скорее всего, анализу SNI в DPI подвергаются только IP-адреса из реестра, а те, которых нет в реестре, не проходят через DPI, поэтому сайт открывается.

Что, вообще говоря, странно, раз это «полный DPI», выполняющий HTTP-обнаружение независимо от IP-адреса. Возможно, на пути следования пакета есть ещё и DPI вышестоящего провайдера, и блокирует именно он.

l29ah commented 5 years ago

Интересно, насколько работоспособным вариантом будет запихивание пустоты в SNI и корректного хостнейма в HTTP?

4ndv commented 5 years ago

Интересно, насколько работоспособным вариантом будет запихивание пустоты в SNI и корректного хостнейма в HTTP?

SNI там не от хорошей жизни, это сработает только если у всех сайтов на этом айпишнике один сертификат

fox0 commented 5 years ago

Небольшое пожелание: добавьте в программу (или в её следующую версию) следующую проверку: openssl s_client -host derpibooru.org -port 443 (не работает, провайдер блокирует по SNI) openssl s_client -host derpibooru.org -port 443 -noservername (работает, можно подключиться, если использовать ESNI)

ValdikSS commented 5 years ago

@fox0, такая проверка уже есть в экспериментальной версии. Тест обхода DPI HTTPS включает в том числе отправку ClientHello без SNI.

fox0 commented 5 years ago

Ты крут! Тогда ждём патченый openSSL и/или инструкций как собрать и запустить экспериментальную версию кода,