Ограничение HTTP/3 (QUIC)

Не устанавливается соединение по QUIC для зарубежных сайтов. Не приходит ответ от сервера на Initial пакет.

Проверял на сайтах google (в том числе youtube), cloudflare-quic.com и quic.nginx.org.
При этом vk.com продолжает работать по HTTP/3.

Заметил на операторах Yota, Мегафон и проводном МТС.

Быстрая проверка показывает, что:

Провайдер RNet (СПб):

image

image

Мобильный Билайн:

image

image

При этом аналогичная картинка на обоих провайдерах с включенным впн:

image

image

Действительно, ответа на QUIC initial нет. Проверено на cloudflare-quic.com и ipv4.google.com
Но на vk.com QUIC не заблокирован

Лечится вот так :

iptables -t mangle -I POSTROUTING -p udp --dport 443 -m mark ! --mark 0x40000000/0x40000000 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:3 -j NFQUEUE --queue-num 205 --queue-bypass
nfqws --qnum=205 ---dpi-desync=fake --dpi-desync-any-protocol --dpi-desync-cutoff=d4

Заодно и проверил работу nfqws на десинхронизацию UDP. Вполне успешно справилось
Как и ожидалось, фильтр не способен вычленить из QUIC имя хоста, поскольку ему пришлось бы применять сложный алгоритм расшифровки. Потому QUIC банится. Вероятно по white list
Так же ожидаемо DPI отстает от потока UDP , если 1-й пакет ему не показался похожим на QUIC. Либо ищется только QUIC initial. Не проверял

UPDATE. Как оказалось, движок QUIC от chromium ловит не только UDP, но и ICMP ttl expired in transit, связанные со своими UDPшками. Они приходят от фейк-пакетов с низким TTL. Как только броузер славливает такой ICMP, сеанс считает порванным, дальше ничего не проходит. Mozilla этим НЕ страдает.
Лечение : либо резать ttl expired in transit (нехорошо, поломаете трейсилки), либо отказаться от ttl fooling и заменить на любой другой, который сработает. Например, badsum.
А можно вообще убрать fooling. В этом случае фейки будут доходить до сервера, но поскольку там трэш, они будут отбрасываться процессом веб сервера.
Но если вы вдруг используете badsum и что-то на пути будет дропать пакеты с badsum (роутеры mediatek, заводские прошивки с linux), то обход не сработает
Проще и надежнее убрать fooling

есть аналогичные команды под windows и goodbye dpi?

Насколько мне известно, goodbye пока не поддерживает udp

Подозреваю, что протокол отключили из-за проблем с блокировкой веб-сайтов? Поддерживает ли HTTP/3 подключение только по QUIC, без TCP-соединения вовсе? Насколько понимаю, ему в любом случае нужен TCP, а уведомление о поддержке QUIC передаётся в TLS ALPN или в HTTP Alt-Svc, или я что-то упустил?

Технически нет никаких проблем сначала пытаться установить quic handshake, и это сработало бы аналогично ESNI, обойдя все блокировки.
Другое дело, что броузеры этого не делают. Они действительно сначала лезут по TLS, и только потом в результате процедуры апгрейда лезут по h3.
Получается, вся защита основывается лишь на “инструментальной беспомощности”. Нет элементарной функции. Но это дело поправимое. Внести небольшую правку в код, добавить переменную в about:config
Умелец выпустит модифицированный броузер, и дальше результат понятен

Обнаружил, что Firefox можно заставить лезть сразу по h3, задав alt-svc для нужных хостов через преф:
network.http.http3.alt-svc-mapping-for-testing

Установив его в:
facebook.com;h3=:443,www.facebook.com;h3=:443,static.xx.fbcdn.net;h3=:443

удалось открыть страницу facebook.com

При обновлении без кеша (ctrl+f5 или shift+клик по иконке обновления) Firefox снова пытается открыть его через TLS, простое F5 перезагружает его через h3 без проблем.

Немедленное рукопожатие HTTP/3 (для одного хоста) также возможно в Chrome/Chromium, запустив браузер из командной строки:

  1. Введите следующую команду:
    Chromium: chromium --enable-quic --origin-to-force-quic-on=www.facebook.com:443
    Chrome: chrome --enable-quic --origin-to-force-quic-on=www.facebook.com:443
  2. Введите адрес веб-сайта в адресную строку (используйте точное доменное имя, указанное в команде).

Фильтр работает только для пакетов с UDP-нагрузкой больше 1001 байтов (включительно).
Фильтр ищет “00 00 00 01” (hex, QUIC version) в UDP-нагрузке, начиная со второго байта.
Применяется только к UDP-пакетам на порт назначения 443. Исходящий порт значения не имеет (может быть также 443, фильтр не применится).

Псевдо-yara-правило фильтра:

rule QUIC_block_Russia_TSPU_04_mar_2022
{
    condition:
        filesize > 1000 and dport == 443 and int32be(1) == 0x00000001
}

Минимальный пакет, на который срабатывает фильтр:
quic_tspu_filtered.bin (1001 Bytes)

nping --udp -p 443 -c 1 --data "$(xxd -ps -c 999999 quic_tspu_filtered.bin)"

Подтверждаю. Добавлю к этому, что к входящим пакетам фильтрация не применяется и используется stateful фильтр. Если первый пакет между src_ip:src_port dst_ip:dst_port не распознан как QUIC, остальные не проверяют. Потому и работает desync=fake в nfqws

desync=ipfrag2 тоже работает , если тестировать с помощью nping со своей VPSкой или девайсом на другом российском провайдере, но на большинстве сайтов не работает, потому что сеть крайне враждебна к ip фрагментам. но все же обмануть ТСПУ этим можно, если речь пойдет о подключении к своему сервису (не обязательно веб, может быть wireguard). Естественно, ipfrag убивается первым же NAT на пути. Если от провайдера серый ип и ТСПУ находится после NAT или из-за своего роутера - неприменимо

Проверил еще хождение между 2 российскими провайдерами. Тоже заблокировано
Значит, гипотеза про white list на ВК подтверждается

С 12 часов на Yota и Megafon наблюдаю проблемы с доступом на домены google com / google ru. Соединение устанавливается, но после получения некоторого объема данных пакеты перестаю ходить.
Странно, что такое только с доменами .google., с ютубом все ок.

google_quic_yota.pcapng (79.8 KB)
IP адрес 142.250.186.196 для google com прописан через /etc/hosts

На мобильном билайне с nfqws всё работает без проблем, как и на проводном Net By Net.

UPD:
Проблема с Firefox, с Chromium все загружается.

В firefox можно отключить quic version 1, установив network.http.http3.support_version1 в false, тогда в QUIC Version будет светиться “FF 00 00 1D” (draft-29) и фильтр пропустит его. В alt-svc преф нужно писать h3-29=:443 в этом случае.

Обход через смену версии на draft-29 больше не работает, по крайней мере с instagram и facebook:
Следующий пакет не пропускает фильтр:
instagram_quic_initial.bin (1.3 KB)
Хотя такой же пакет для домена гугла доходит до сервера.

C nfqws все также работает.

Ваш пакет доходит до facebook.com (157.240.201.35), на провайдере с ТСПУ.

$ nping --udp -p 443 -c 1 --data "$(xxd -ps -c 999999 instagram_quic_inital.bin)" 157.240.201.35

Starting Nping 0.7.91 ( https://nmap.org/nping ) at 2022-03-20 00:31 MSK
SENT (0.0022s) UDP packet with 1357 bytes to 157.240.201.35:443
RCVD (0.0394s) UDP packet with 1232 bytes from 157.240.201.35:443
 
Max rtt: 37.137ms | Min rtt: 37.137ms | Avg rtt: 37.137ms
UDP packets sent: 1 | Rcvd: 1 | Lost: 0 (0.00%)
Nping done: 1 IP address pinged in 0.04 seconds

Как минимум у части провайдеров заблокированы часть адресов Instagram. Попробуйте порезолвить домены через разные публичные резолверы и попробовать разные IP-адреса.

Я проверял с DigitalOcean AMS. Оператор Yota.

Тесты с 157.240.201.35:
Initial с server_name www.google.com:

$ nping --udp -p 443 -c 1 --data "$(xxd -ps -c 999999 google_quic_initial.bin)" 157.240.201.35    

Starting Nping 0.7.92 ( https://nmap.org/nping ) at 2022-03-20 11:18 MSK
SENT (0.0016s) UDP packet with 1357 bytes to 157.240.201.35:443
RCVD (0.2062s) UDP packet with 1232 bytes from 157.240.201.35:443

Max rtt: 204.642ms | Min rtt: 204.642ms | Avg rtt: 204.642ms
UDP packets sent: 1 | Rcvd: 1 | Lost: 0 (0.00%)
Nping done: 1 IP address pinged in 0.21 seconds

Initial с server_name www.instagram.com:

$ nping --udp -p 443 -c 1 --data "$(xxd -ps -c 999999 instagram_quic_inital.bin)" 157.240.201.35  

Starting Nping 0.7.92 ( https://nmap.org/nping ) at 2022-03-20 11:18 MSK
SENT (0.0015s) UDP packet with 1357 bytes to 157.240.201.35:443

Max rtt: N/A | Min rtt: N/A | Avg rtt: N/A
UDP packets sent: 1 | Rcvd: 0 | Lost: 1 (100.00%)
Nping done: 1 IP address pinged in 1.00 seconds

Тоже самое происходит и с www.facebook.com. При использовании nfqws оба server_name доходят.

Через Tele2 instagram отвечает почти всегда, но не каждый раз. На личный сервер этот пакет доходит всегда.

На Yota, действительно, есть фильтр, и на первый взгляд, он декодирует QUIC-пакет и выявляет имя домена.

На моем провайдере с ТСПУ начались непонятные и хаотичные отрубы QUIC сессий, пробитых с помощью nfqws --dpi-desync=fake. Пейлоад пробовал разный. Разницы никакой.

Тест : с firefox с вычищенным кэшем заходим на https://ipv4.google.com
через раз получается как на картинке
По паре ip:port перестают ходить пакеты, как если бы DPI занес UDP поток в черный список. Точно так же, как если первым пакетом пошел бы QUIC initial. Но здесь происходит отруб внезапно в середине сеанса. Всовывание фейков перед каждым пакетом не помогает.
Пробовал завертывать UDP через свой сервер. Тоже самое. Если пропустить через VPN - проблема уходит
Пробовал взять первые 2 пакета от клиента и от сервера (initial) и долбиться ими nping-ом по одной паре ip:port с сервера и клиента после начального пробития фейком. Не отрубает.
nping по блокированной паре ip:port с ограниченным TTL показывает, что блок идет на 5-хопе. Там стоит как раз ТСПУ и блокировщик сайтов
Эвристика - статистика какая-то ?

У домру недавно наблюдались блокировки QUIC на youtube, facebook, в отличие от VK. Сейчас проверил, пока QUIC заработал на них. Тестят наверно…

Крайний раз, когда тестил домру около месяца назад, у них наблюдался лоад балансинг.
Часть трафика уходит через ТСПУ, а часть нет. Где нет - там простой пассивный DPI.
Потому может то работать QUIC, то не работать. По какому критерию балансируется трафик я не изучал, возможно по IP. Учитывая прыгающий характер ip от крупных сервисов, может так и получиться, что когда-то запросы идут через ТСПУ, а когда-то нет

Почему после включения nfqws может совсем переставать работать http3? Если отключить nfqws, то через curl работает http3, но в хроме только http2. Проверял на quic.nginx.org и cloudflare-quic.com, ютубе и др. Если включить VPN, то в хроме начинает полноценно работать http3. В firefox работает http3 и без vpn, но частично, только cloudflare-quic.com, а на quic.nginx.org не работает, на других сайтах чаще тоже работает. В Safari совсем ситуация странная, буквально пару дней назад http3 работал везде даже лучше, чем в firefox, а сегодня даже через vpn не работает.

nfqws --dpi-desync-fwmark=0x40000000 --qnum=210 --dpi-desync=fake --debug

curl -4ILv --max-time 5 --http3 https://vk.com                                                                                                                                                                                                    28 ↵
*   Trying 87.240.190.72:443...
* Connect socket 5 over QUIC to 87.240.190.72:443
* Sent QUIC client Initial, ALPN: h3-29,h3-28,h3-27
* After 2498ms connect time, move on!
* connect to 87.240.190.72 port 443 failed: Connection timed out
*   Trying 87.240.190.67:443...
* Connect socket 6 over QUIC to 87.240.190.67:443
* Sent QUIC client Initial, ALPN: h3-29,h3-28,h3-27
* After 1249ms connect time, move on!
* connect to 87.240.190.67 port 443 failed: Connection timed out
*   Trying 87.240.190.78:443...
* Connect socket 5 over QUIC to 87.240.190.78:443
* Sent QUIC client Initial, ALPN: h3-29,h3-28,h3-27
* After 624ms connect time, move on!
* connect to 87.240.190.78 port 443 failed: Connection timed out
*   Trying 87.240.137.158:443...
* Connect socket 6 over QUIC to 87.240.137.158:443
* Sent QUIC client Initial, ALPN: h3-29,h3-28,h3-27
* After 313ms connect time, move on!
* connect to 87.240.137.158 port 443 failed: Connection timed out
*   Trying 87.240.139.194:443...
* Connect socket 5 over QUIC to 87.240.139.194:443
* Sent QUIC client Initial, ALPN: h3-29,h3-28,h3-27
* After 156ms connect time, move on!
* connect to 87.240.139.194 port 443 failed: Connection timed out
*   Trying 93.186.225.208:443...
* Connect socket 6 over QUIC to 93.186.225.208:443
* Sent QUIC client Initial, ALPN: h3-29,h3-28,h3-27
* After 78ms connect time, move on!
* connect to 93.186.225.208 port 443 failed: Connection timed out
* Failed to connect to vk.com port 443: Connection timed out
* Closing connection 0
curl: (28) Failed to connect to vk.com port 443: Connection timed out
IP4: 192.168.1.113 => 87.240.137.158 proto=udp sport=61894 dport=443
UDP: CF FF 00 00 1D 10 2C 20 B7 21 87 58 81 F7 7C 35 DD 53 A2 C5 3E 53 14 B9 69 39 3D BA 50 CD 16 54 ... : ......, .!.X..|5.S..>S..i9=.P..T ...
packet contains QUIC initial
hostname: vk.com
dpi desync src=192.168.1.113:61894 dst=87.240.137.158:443
sending fake request : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... : ................................ ...
reinjecting original packet. len=1228 len_payload=1200
packet: id=30 drop
packet: id=31 len=1228
IP4: 192.168.1.113 => 87.240.139.194 proto=udp sport=61598 dport=443
UDP: C2 FF 00 00 1D 10 38 DB 6E CE F1 CB 56 79 07 F0 93 1A 44 1A F7 B7 14 D2 BD E2 80 6C A9 B3 09 58 ... : ......8.n...Vy....D........l...X ...
packet contains QUIC initial
hostname: vk.com
dpi desync src=192.168.1.113:61598 dst=87.240.139.194:443
sending fake request : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... : ................................ ...
reinjecting original packet. len=1228 len_payload=1200
packet: id=31 drop
packet: id=32 len=1228
IP4: 192.168.1.113 => 93.186.225.208 proto=udp sport=60154 dport=443
UDP: CF FF 00 00 1D 10 2D F6 2E 56 03 F9 77 77 84 84 EA E7 CE D4 48 AF 14 EF E5 4F 88 92 50 04 C4 1F ... : ......-..V..ww......H....O..P... ...
packet contains QUIC initial
hostname: vk.com
dpi desync src=192.168.1.113:60154 dst=93.186.225.208:443
sending fake request : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... : ................................ ...
reinjecting original packet. len=1228 len_payload=1200
packet: id=32 drop