"""The other side: the two evasions a client uses, both given. Each evasion takes one record and returns a new record: the same visit, sent the way an evading client would send it. They copy the record rather than change it, and they change only what the client controls. The site is still the same site, so experiments.py still counts the visit as targeted. hide_sni is Encrypted Client Hello and use_doh is DNS over HTTPS; via_proxy is the third, for the escalation part. Read them before you measure: part C asks what each one hides. """ from __future__ import annotations import corpus def hide_sni(record): """Encrypted Client Hello (ECH): hide the real server name. With ECH the ClientHello's visible server name is the provider's public name, and the real one is encrypted inside. Only providers that offer ECH can do this: corpus.ECH_PUBLIC_NAME maps an address to its provider's public name. Plain HTTP (port 80) has no ClientHello, and a site whose provider does not offer ECH cannot use it; in both cases return an unchanged copy. Everything else about the record stays as it was. """ out = dict(record) if record["port"] == 443 and record["ip"] in corpus.ECH_PUBLIC_NAME: out["sni"] = corpus.ECH_PUBLIC_NAME[record["ip"]] return out def use_doh(record): """DNS over HTTPS: look the name up inside an encrypted connection to a public resolver. The censor no longer sees a DNS query for this visit. Everything else stays as it was. """ out = dict(record) out["dns"] = None return out def via_proxy(record, proxy=corpus.PROXY): """Send the visit through an encrypted proxy: a relay the censor has not blocked. To the censor the connection now looks like an ordinary HTTPS visit to the proxy (proxy["host"] at proxy["ip"]): that is the name looked up, the address, and the server name. The whole original visit, readable or not, travels encrypted inside, so the payload must no longer be readable. The new record keeps `id` and follows the port 443 format in corpus.py. """ size = len(record["payload"]) // 2 + 40 return {"id": record["id"], "port": 443, "dns": proxy["host"], "ip": proxy["ip"], "sni": proxy["host"], "hello_bytes": record["hello_bytes"] or 512, "payload": "0" * (2 * size)} EVASIONS = {"hide_sni": hide_sni, "use_doh": use_doh, "via_proxy": via_proxy}