Skip to content

Commit 3752c95

Browse files
committed
test(proxy): cover QUIC DNS suppression boundaries
Strengthen the focused DNS coverage for the block_quic HTTPS/SVCB suppression path. The new tests verify that the local empty-answer response preserves the client recursion-desired bit, clears additional-record state instead of echoing EDNS-style trailing data, rejects compressed question names, and ignores non-IN classes. These cases keep the helper intentionally narrow: only ordinary single-question IN queries for HTTPS or SVCB are answered locally. Clarify the guide note to state that ordinary A/AAAA DNS questions are unchanged by this policy.
1 parent e6b6f38 commit 3752c95

2 files changed

Lines changed: 40 additions & 1 deletion

File tree

docs/guide.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ Memory footprint ~15–20 MB resident — fine on anything ≥128 MB RAM. No UI
317317
- **`mhrv-rs test-sni`** — parallel TLS probe of every SNI name in your rotation pool against `google_ip`. Tells you which front-domain names pass through your ISP's DPI. UI has same thing in **SNI pool…** window with checkboxes, per-row **Test** buttons, and **Keep ✓ only** to auto-trim.
318318
- **Periodic stats** logged every 60 s at `info` level (relay calls, cache hit rate, bytes relayed, active vs blacklisted scripts). UI shows live.
319319

320-
When `block_quic = true`, the SOCKS5 UDP relay drops UDP/443 datagrams and answers DNS HTTPS/SVCB (type 65/64) questions with an empty successful response. Browsers then skip HTTP/3 advertisement and fall back to TCP/HTTPS sooner, without forwarding those QUIC discovery packets through the relay.
320+
When `block_quic = true`, the SOCKS5 UDP relay drops UDP/443 datagrams and answers DNS HTTPS/SVCB (type 65/64) questions with an empty successful response. Ordinary A/AAAA DNS questions are unchanged. Browsers then skip HTTP/3 advertisement and fall back to TCP/HTTPS sooner, without forwarding those QUIC discovery packets through the relay.
321321

322322
### SNI pool editor
323323

src/proxy_server.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3600,6 +3600,13 @@ mod tests {
36003600
q
36013601
}
36023602

3603+
fn dns_query_with_class(qtype: u16, qclass: u16) -> Vec<u8> {
3604+
let mut q = dns_query(qtype);
3605+
let n = q.len();
3606+
q[n - 2..n].copy_from_slice(&qclass.to_be_bytes());
3607+
q
3608+
}
3609+
36033610
#[test]
36043611
fn dns_https_question_gets_empty_success_response() {
36053612
let query = dns_query(DNS_TYPE_HTTPS);
@@ -3612,6 +3619,20 @@ mod tests {
36123619
assert_eq!(&response[12..], &query[12..]);
36133620
}
36143621

3622+
#[test]
3623+
fn dns_https_response_preserves_rd_and_clears_additional_records() {
3624+
let mut query = dns_query(DNS_TYPE_HTTPS);
3625+
// Pretend the client included one additional record after the
3626+
// question. The local policy answer must not echo that section.
3627+
query[11] = 1;
3628+
query.extend_from_slice(&[0, 0, 41, 16, 0, 0, 0, 0, 0, 0, 0]);
3629+
3630+
let response = dns_empty_response_for_https_or_svcb(&query).unwrap();
3631+
assert_eq!(response[2] & 0x01, 0x01);
3632+
assert_eq!(&response[10..12], &[0, 0]);
3633+
assert!(response.len() < query.len());
3634+
}
3635+
36153636
#[test]
36163637
fn dns_svcb_question_gets_empty_success_response() {
36173638
let query = dns_query(DNS_TYPE_SVCB);
@@ -3631,6 +3652,24 @@ mod tests {
36313652
assert!(dns_empty_response_for_https_or_svcb(&query).is_none());
36323653
}
36333654

3655+
#[test]
3656+
fn dns_compressed_question_name_is_not_suppressed() {
3657+
let mut query = Vec::new();
3658+
query.extend_from_slice(&[0x12, 0x34, 0x01, 0x00]);
3659+
query.extend_from_slice(&[0x00, 0x01, 0x00, 0x00]);
3660+
query.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]);
3661+
query.extend_from_slice(&[0xc0, 0x0c]);
3662+
query.extend_from_slice(&DNS_TYPE_HTTPS.to_be_bytes());
3663+
query.extend_from_slice(&1u16.to_be_bytes());
3664+
assert!(dns_empty_response_for_https_or_svcb(&query).is_none());
3665+
}
3666+
3667+
#[test]
3668+
fn dns_non_in_question_is_not_suppressed() {
3669+
let query = dns_query_with_class(DNS_TYPE_HTTPS, 3);
3670+
assert!(dns_empty_response_for_https_or_svcb(&query).is_none());
3671+
}
3672+
36343673
#[test]
36353674
fn doh_default_list_exact_matches() {
36363675
let extra: Vec<String> = vec![];

0 commit comments

Comments
 (0)