net4people / bbs

Forum for discussing Internet censorship circumvention
3.23k stars 75 forks source link

Blocking of HTTP/3 (QUIC) in Russia #108

Open wkrp opened 2 years ago

wkrp commented 2 years ago

A thread on NTC says that HTTP/3 connections (QUIC; UDP to port 443) to foreign sites are blocked in several ISPs in Russia. I don't know a precise time of onset. It has been tested on the ISPs Yota, Megafon, MTS, Rnet, and Beeline. HTTP/3 to sites located in Russia, for example vk.com, still works. The technical symptom of the blocking is that there is no reply to the Initial Packet.

https://ntc.party/t/http-3-quic/1823

There are web pages where you can test for yourself whether HTTP/3 is accessible. (You may have to refresh the page a few times.) Technical users can use the browser console to check HTTP/3 on other sites.

@bol-van offers a recipe for circumventing the block using zapret (English docs):

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-fooling=badsum --dpi-desync-cutoff=d4

@bol-van cautions that the --dpi-desync-ttl option does not work well when using Chrome, but it works with Firefox. Chrome looks for ICMP "TTL exceeded in transit" messages and will tear down the connection if it sees them, while Firefox ignores such packets.

The QUIC Initial Packet typically contains the TLS ClientHello, including the SNI. It might seem that the censor would do selective blocking of QUIC, only for specific hostnames, as with HTTP/1 and HTTP/2 over TLS. But this block appears to be of all HTTP/3, regardless of destination. The reason may be that Initial Packets are obfuscated, encrypted using a key that is sent in plaintext. The censor would have to do extra decryption work to recover the SNI, or maybe their hardware does not support it.

wkrp commented 2 years ago

Kathrin Elmenhorst et al., in cooperation with OONI, wrote a paper and a blog post about using ooni-probe to measure HTTP/3 censorship:

But I don't know if such measurements are still being run regularly, or how to access them. I've sent an email to the authors to ask.

wkrp commented 2 years ago

But I don't know if such measurements are still being run regularly, or how to access them. I've sent an email to the authors to ask.

I got a reply from Kathrin with instructions. To find HTTP/3 measurements in OONI Explorer, you have to choose the URL Getter network test, and uncheck the "Hide failed measurements" box. Like so:

https://explorer.ooni.org/search?since=2022-02-02&until=2022-03-05&test_name=urlgetter

You have to dig into the https measurements to see which ones are HTTP/3. In the JSON, look for "HTTP3Enabled=true" in the .options array, and QUIC-related events (like "operation": "quic_handshake_start") in .test_keys.network_events.

However, the URL Getter test is experimental and is not being run regularly. I did not find any recent test results from Russia.

bol-van commented 2 years ago

@bol-van cautions that the --dpi-desync-ttl option does not work well when using Chrome, but it works with Firefox. Chrome looks for ICMP "TTL exceeded in transit" messages and will tear down the connection if it sees them, while Firefox ignores such packets.

The best option seem to omit desync fooling. When an UDP packet with zero or trash payload arrives to QUIC server it simply ignores it. No any harm occurs. Incoming badsums are often dropped on home routers with stock linux based firmware and by mediatek ethernet hardware

ValdikSS commented 2 years ago

The filter applies only on packets with UDP-payload larger than 1001 byte (including) Filter seeks for "00 00 00 01" (hex, QUIC version) in the UDP payload starting from the second byte. It is applied only for UDP packets with destination port == 443. Source port doesn't matter (the filter is not applies for source port == 443).

Pseudo YARA rule:

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

Minimalistic payload for which the filter is applied: quic_tspu_filtered.bin.zip

nping --udp -p 443 -c 1 --data "$(xxd -ps -c 999999 quic_tspu_filtered.bin)"
wkrp commented 2 years ago

@kelmenhorst has a thread with some interesting observations from OONI HTTP/3 measurements in Russia.

https://github.com/kelmenhorst/quic-censorship/issues/4

On the ISP Yota (AS 31213), there appears to be a two-layer filter. One layer blocks all QUIC version 1, except to specific servers; and a second layer blocks QUIC version 1 with with specific SNI values, no matter the server. This is interesting because the second layer means they must be decrypting the initial packet protection on the packet containing the Client Hello.

The evidence for this comes from observing what happens when accessing different servers using different SNI values.

condition result
Access foreign server with correct SNI blocked
Access foreign server with vk.com SNI blocked
Access vk.com server with vk.com SNI works
Access vk.com server with ww[]()w.facebook.com SNI blocked
fortuna commented 2 years ago

The new HTTPS DNS resource record has a way to specify the port number for a service.

Publishers could leverage that to run HTTP/3 on a port other than 443 and bypass the filtering.

Kudos to @daniellacosse for the idea.

ValdikSS commented 2 years ago

Alt-svc HTTP header could point to another port as well.