mirror of
https://github.com/Runnin4ik/dpi-detector.git
synced 2026-10-19 17:33:18 +00:00
Three things the column could not say, and one it said wrongly. **A timeout has one badge.** The QUIC Initial that never got an answer wore `DROP` while every other window that ran out wears `TIMEOUT`, so the same finding read as two different ones across the columns; a reader comparing HTTP/TLS/QUIC had to know that. The badge is now `TIMEOUT` and the details column carries no line for it — the badge names the column and the cause — while `--json` keeps `quic_drop`, so no consumer's key moves. The legend, the README table and the QUIC stand's own notes follow the badge. **The details cell names the legs that share a reason.** It used to print one line per failing protocol, repeating a shared reason once per name; the core now groups the failures by their detail and hands the renderer the names that share it (`HTTP,TLS13:→ m.megafonpro.ru`), and a row whose only reason is that one carries no names at all, because the badges already say which columns are not OK. The certificate mark is the exception that made the rule explicit: it draws no badge, so its line is always named (`TLS:`/`TLS12:`/`TLS13:`). **Answers we cannot read are named in our words.** rustls spells one sentence — `peer is incompatible: …` — for twenty-one different variants, and the whole family read as `NO TLS1.3`, which said the opposite of what happened: measured on `aliexpress.ru`, whose TLS 1.2 column read `no_tls13` while the answer was a ServerHello for a version the leg never offered. The variant that names a version carries none in its message — it covers a peer picking a version above our offer and one picking below it — so the classifier leaves the direction to the pin (`peer_version_mismatch`): the TLS-1.2 leg, which offered 1.2 alone, can only have been answered with 1.3, and reads `TLS SPOOF`/`response_spoofing_wrong_version`, while the TLS-1.3 leg meeting the same message met a host without TLS 1.3 and keeps `NO TLS1.3`. Everything else in the family is a capability mismatch (`TLS ERR`, `peer_incompatible`), and hyper's parse failures — `invalid HTTP version parsed` in a censorship report — now say `not_http_response`, «Ответ не разбирается: это не HTTP», with the status where it was. **The certificate the answer came with is marked.** The probes hand rustls an insecure profile on purpose: a certificate a censor's middlebox presents is evidence, and the answer behind it — the registry blockpage, the redirect target — is the finding, so a verifying handshake would abort before either could be read. `net::tls::verify_peer_chain` therefore judges the chain the handshake already collected, against the same bundled Mozilla roots and the same classifier a verifying leg uses, and the row carries the verdict as a mark: `TlsCheck.cert`, a named line in the details cell that outlives the branches reducing a cell to a timing, and `cert_detail` in `--json` (additive, so `SCHEMA_VERSION` stands). No column's status moves: a site that answered `OK` with a foreign certificate still reads `OK`, and the mark says whose certificate it was shown. Measured live: `aliexpress.ru` and `mvideo.ru` under `--fingerprint chrome146` and `firefox147` read `tls_spoof`/`response_spoofing_wrong_version` on TLS 1.2 (where the same hosts read `no_tls13` before), `unknown`/`tls_decrypt_error` or an RST on TLS 1.3, and `not_http_response` on HTTP; the base `rustls` hello the same box meets with silence. `self-signed.badssl.com`, `expired.badssl.com` and `wrong.host.badssl.com` mark `no_root_certificates`, `cert_expired` and `hostname_mismatch` in the cell, and the two GGC node rows mark `hostname_mismatch` — `*.googlevideo.com` does not cover `r1.<cluster>.googlevideo.com`, which the README now says beside the GGC paragraph so a mark on a synthetic row is not read as interception. Tests: the version-naming answer resolved against both pins and passed through untouched, the other variants, hyper's parse failure named and a message the table does not know still quoted, the certificate line named on a row whose only line it is and alongside a failure that keeps its own name, the mark outliving the timing branches and absent on a chain the roots accept, and `verify_peer_chain` rejecting the fixture chains that reach no bundled root. |
||
|---|---|---|
| .. | ||
| quic | ||
| bench-strategies.sh | ||
| vendor-advisories.sh | ||