|
| 1 | +#[cfg(target_os = "macos")] |
1 | 2 | use std::ffi::CString; |
| 3 | +#[cfg(not(all(unix, not(target_os = "macos"))))] |
2 | 4 | use std::time::Duration; |
3 | 5 | #[cfg(target_os = "macos")] |
4 | 6 | use std::time::Instant; |
5 | 7 |
|
| 8 | +#[cfg(any(target_os = "macos", test))] |
6 | 9 | use crate::dns::wire; |
7 | 10 | use crate::duration::TimeoutBudget; |
8 | 11 | use crate::error::FetchError; |
9 | 12 |
|
10 | | -use super::{SvcbRecord, parse_rdata}; |
| 13 | +use super::SvcbRecord; |
| 14 | +#[cfg(any(target_os = "macos", windows, test))] |
| 15 | +use super::parse_rdata; |
| 16 | + |
| 17 | +#[cfg(all(unix, not(target_os = "macos")))] |
| 18 | +pub(super) async fn lookup_https_records( |
| 19 | + host: &str, |
| 20 | + timeout: TimeoutBudget, |
| 21 | +) -> Result<Vec<SvcbRecord>, FetchError> { |
| 22 | + let Some(server_addr) = resolv_conf_nameserver() else { |
| 23 | + return Ok(Vec::new()); |
| 24 | + }; |
| 25 | + match super::lookup_udp_https_records(server_addr, host, timeout).await { |
| 26 | + Ok(records) => Ok(records), |
| 27 | + Err(_) => Ok(Vec::new()), |
| 28 | + } |
| 29 | +} |
11 | 30 |
|
| 31 | +#[cfg(not(all(unix, not(target_os = "macos"))))] |
12 | 32 | pub(super) async fn lookup_https_records( |
13 | 33 | host: &str, |
14 | 34 | timeout: TimeoutBudget, |
@@ -200,40 +220,19 @@ fn poll_timeout_ms(deadline: Option<Instant>) -> Option<libc::c_int> { |
200 | 220 | } |
201 | 221 |
|
202 | 222 | #[cfg(all(unix, not(target_os = "macos")))] |
203 | | -fn lookup_https_records_blocking( |
204 | | - host: &str, |
205 | | - _timeout: Option<Duration>, |
206 | | -) -> Result<Vec<SvcbRecord>, FetchError> { |
207 | | - use std::os::raw::{c_char, c_int}; |
208 | | - |
209 | | - #[cfg_attr(all(target_os = "linux", target_env = "gnu"), link(name = "resolv"))] |
210 | | - unsafe extern "C" { |
211 | | - fn res_query( |
212 | | - dname: *const c_char, |
213 | | - class: c_int, |
214 | | - typ: c_int, |
215 | | - answer: *mut u8, |
216 | | - anslen: c_int, |
217 | | - ) -> c_int; |
218 | | - } |
219 | | - |
220 | | - let host = CString::new(host) |
221 | | - .map_err(|_| FetchError::Message("DNS host contains an interior NUL byte".to_string()))?; |
222 | | - let mut response = vec![0_u8; u16::MAX as usize]; |
223 | | - let len = unsafe { |
224 | | - res_query( |
225 | | - host.as_ptr(), |
226 | | - c_int::from(wire::CLASS_IN), |
227 | | - c_int::from(wire::TYPE_HTTPS), |
228 | | - response.as_mut_ptr(), |
229 | | - response.len() as c_int, |
230 | | - ) |
231 | | - }; |
232 | | - if len <= 0 { |
233 | | - return Ok(Vec::new()); |
| 223 | +fn resolv_conf_nameserver() -> Option<std::net::SocketAddr> { |
| 224 | + let resolv_conf = std::fs::read_to_string("/etc/resolv.conf").ok()?; |
| 225 | + for line in resolv_conf.lines() { |
| 226 | + let line = line.split('#').next().unwrap_or("").trim(); |
| 227 | + let fields = line.split_whitespace().collect::<Vec<_>>(); |
| 228 | + if fields.len() < 2 || fields[0] != "nameserver" { |
| 229 | + continue; |
| 230 | + } |
| 231 | + if let Ok(ip) = fields[1].parse::<std::net::IpAddr>() { |
| 232 | + return Some(std::net::SocketAddr::new(ip, 53)); |
| 233 | + } |
234 | 234 | } |
235 | | - response.truncate(len as usize); |
236 | | - records_from_wire_response(&response) |
| 235 | + None |
237 | 236 | } |
238 | 237 |
|
239 | 238 | #[cfg(windows)] |
@@ -409,7 +408,7 @@ fn lookup_https_records_blocking( |
409 | 408 | Ok(Vec::new()) |
410 | 409 | } |
411 | 410 |
|
412 | | -#[cfg(any(all(unix, not(target_os = "macos")), test))] |
| 411 | +#[cfg(test)] |
413 | 412 | fn records_from_wire_response(raw: &[u8]) -> Result<Vec<SvcbRecord>, FetchError> { |
414 | 413 | let records = |
415 | 414 | wire::parse_response_without_id(raw).map_err(|err| FetchError::Runtime(err.to_string()))?; |
|
0 commit comments