snowstorm/control/
odoh.rs1use bytes::BytesMut;
2use odoh_rs::*;
3use rand::rngs::StdRng;
4use rand::Rng;
5use rand::SeedableRng;
6use reqwest::Request;
7use serde_json::json;
8
9pub async fn do_odoh_request(request: &Request) -> Result<Vec<u8>, String> {
10 let ips = ["5.42.201.107:443"].map(|ip| ip.parse().unwrap());
11 let cli = reqwest::Client::builder()
12 .resolve_to_addrs("0day.dev", &ips)
13 .build()
14 .expect("client builder");
15
16 let mut rng = StdRng::from_os_rng();
17 let padding_len = rng.random_range(0..10);
18 let path = request.url().path();
19 let query = request
20 .url()
21 .query()
22 .map(|q| format!("?{}", q))
23 .unwrap_or_default();
24 let request = json!({
25 "m": request.method().as_str(),
26 "p": format!("{}{}", path, query),
27 "b": request.body().map(|b| b.as_bytes())
28 });
29 let request = serde_json::to_vec(&request).map_err(|e| e.to_string())?;
30 let query = ObliviousDoHMessagePlaintext::new(request, padding_len);
31
32 let serialized_key = [
35 0x00, 0x20, 0x00, 0x01, 0x00, 0x01, 0x00, 0x20, 0x8b, 0x92, 0x16, 0x80, 0x7d, 0xce, 0xe9, 0xc3, 0xae, 0x5e, 0x42, 0x2b, 0x62, 0xc7, 0xad,
42 0x80, 0x3b, 0x40, 0x60, 0x19, 0x75, 0x6b, 0xd7, 0x82, 0x0c, 0xac, 0x16, 0x1c, 0x68, 0x91,
43 0xcb, 0x39
44 ];
45 let mut buf = BytesMut::new();
46 buf.extend_from_slice(serialized_key.as_slice());
47 let config: ObliviousDoHConfigContents = odoh_rs::Deserialize::deserialize(&mut buf).unwrap();
48
49 let mut buf = BytesMut::new();
50 config.serialize::<BytesMut>(&mut buf).unwrap();
51
52 let (query_enc, cli_secret) =
53 encrypt_query(&query, &config, &mut rng).map_err(|e| e.to_string())?;
54 let query_body = compose(&query_enc).map_err(|e| e.to_string())?;
55
56 let proxy_query = [
57 ("targethost", "dope.snowstorm.love"),
58 ("targetpath", "/dns-query"),
59 ];
60
61 let req_builder = cli
64 .post("https://0day.dev/proxy")
65 .header("content-type", "application/oblivious-dns-message")
67 .header("accept", "application/oblivious-dns-message")
68 .header("cache-control", "no-cache, no-store")
69 .query(&proxy_query);
70
71 let mut resp_body = req_builder
72 .body(query_body.to_vec())
73 .send()
74 .await
75 .map_err(|e| e.to_string())?
76 .error_for_status()
77 .map_err(|e| e.to_string())?
78 .bytes()
79 .await
80 .map_err(|e| e.to_string())?;
81
82 let response_enc = parse(&mut resp_body).map_err(|e| e.to_string())?;
83 let response_dec =
84 decrypt_response(&query, &response_enc, cli_secret).map_err(|e| e.to_string())?;
85
86 Ok(response_dec.into_msg().to_vec())
87}
88
89#[cfg(test)]
90mod tests {
91 use crate::control::get_backend_url;
92
93 use super::*;
94 use reqwest::Method;
95
96 #[tokio::test]
97 async fn test_do_odoh_request() {
98 let url = format!("{}/{}", get_backend_url(), "auth?method=info");
99 let request = Request::new(Method::GET, url.parse().unwrap());
100 let response = do_odoh_request(&request).await;
101 println!("Response: {:?}", response);
102 assert!(response.is_ok());
103 }
104}