c_ares_resolver/
blockingresolver.rs

1use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
2
3use crate::error::Error;
4use crate::host::HostResults;
5use crate::nameinfo::NameInfoResult;
6use crate::resolver::{Options, Resolver};
7
8#[cfg(cares1_24)]
9use c_ares::AresString;
10
11#[cfg(cares1_29)]
12use c_ares::ServerStateFlags;
13
14use std::sync::mpsc;
15
16/// A blocking DNS resolver.
17pub struct BlockingResolver {
18    inner: Resolver,
19}
20
21// Most query implementations follow the same pattern: call through to the `Resolver`, arranging
22// that the callback sends the result down a channel.
23macro_rules! blockify {
24    ($resolver:expr, $query:ident, $question:expr) => {{
25        let (tx, rx) = mpsc::sync_channel(1);
26        $resolver.$query($question, move |result| tx.send(result).unwrap());
27        rx.recv().unwrap()
28    }};
29}
30
31impl BlockingResolver {
32    /// Create a new `BlockingResolver`, using default `Options`.
33    pub fn new() -> Result<Self, Error> {
34        let options = Options::default();
35        Self::with_options(options)
36    }
37
38    /// Create a new `BlockingResolver`, with the given `Options`.
39    pub fn with_options(options: Options) -> Result<Self, Error> {
40        let inner = Resolver::with_options(options)?;
41        let resolver = Self { inner };
42        Ok(resolver)
43    }
44
45    /// Reinitialize a channel from system configuration.
46    #[cfg(cares1_22)]
47    pub fn reinit(&self) -> c_ares::Result<&Self> {
48        self.inner.reinit()?;
49        Ok(self)
50    }
51
52    /// Set the list of servers to contact, instead of the servers specified in resolv.conf or the
53    /// local named.
54    ///
55    /// String format is `host[:port]`.  IPv6 addresses with ports require square brackets eg
56    /// `[2001:4860:4860::8888]:53`.
57    pub fn set_servers(&self, servers: &[&str]) -> c_ares::Result<&Self> {
58        self.inner.set_servers(servers)?;
59        Ok(self)
60    }
61
62    /// Retrieves the list of servers in comma delimited format.
63    #[cfg(cares1_24)]
64    pub fn get_servers(&self) -> AresString {
65        self.inner.get_servers()
66    }
67
68    /// Set the local IPv4 address from which to make queries.
69    pub fn set_local_ipv4(&self, ipv4: Ipv4Addr) -> &Self {
70        self.inner.set_local_ipv4(ipv4);
71        self
72    }
73
74    /// Set the local IPv6 address from which to make queries.
75    pub fn set_local_ipv6(&self, ipv6: &Ipv6Addr) -> &Self {
76        self.inner.set_local_ipv6(ipv6);
77        self
78    }
79
80    /// Set the local device from which to make queries.
81    pub fn set_local_device(&self, device: &str) -> &Self {
82        self.inner.set_local_device(device);
83        self
84    }
85
86    /// Initializes an address sortlist configuration, so that addresses returned by
87    /// `get_host_by_name()` are sorted according to the sortlist.
88    ///
89    /// Each element of the sortlist holds an IP-address/netmask pair. The netmask is optional but
90    /// follows the address after a slash if present. For example: "130.155.160.0/255.255.240.0",
91    /// or "130.155.0.0".
92    pub fn set_sortlist(&self, sortlist: &[&str]) -> c_ares::Result<&Self> {
93        self.inner.set_sortlist(sortlist)?;
94        Ok(self)
95    }
96
97    /// Set a callback function to be invoked whenever a query on the channel completes.
98    ///
99    /// `callback(server, success, flags)` will be called when a query completes.
100    ///
101    /// - `server` indicates the DNS server that was used for the query.
102    /// - `success` indicates whether the query succeeded or not.
103    /// - `flags` is a bitmask of flags describing various aspects of the query.
104    #[cfg(cares1_29)]
105    pub fn set_server_state_callback<F>(&self, callback: F) -> &Self
106    where
107        F: FnMut(&str, bool, ServerStateFlags) + Send + 'static,
108    {
109        self.inner.set_server_state_callback(callback);
110        self
111    }
112
113    /// Look up the A records associated with `name`.
114    pub fn query_a(&self, name: &str) -> c_ares::Result<c_ares::AResults> {
115        blockify!(self.inner, query_a, name)
116    }
117
118    /// Search for the A records associated with `name`.
119    pub fn search_a(&self, name: &str) -> c_ares::Result<c_ares::AResults> {
120        blockify!(self.inner, search_a, name)
121    }
122
123    /// Look up the AAAA records associated with `name`.
124    pub fn query_aaaa(&self, name: &str) -> c_ares::Result<c_ares::AAAAResults> {
125        blockify!(self.inner, query_aaaa, name)
126    }
127
128    /// Search for the AAAA records associated with `name`.
129    pub fn search_aaaa(&self, name: &str) -> c_ares::Result<c_ares::AAAAResults> {
130        blockify!(self.inner, search_aaaa, name)
131    }
132
133    /// Look up the CAA records associated with `name`.
134    #[cfg(cares1_17)]
135    pub fn query_caa(&self, name: &str) -> c_ares::Result<c_ares::CAAResults> {
136        blockify!(self.inner, query_caa, name)
137    }
138
139    /// Search for the CAA records associated with `name`.
140    #[cfg(cares1_17)]
141    pub fn search_caa(&self, name: &str) -> c_ares::Result<c_ares::CAAResults> {
142        blockify!(self.inner, search_caa, name)
143    }
144
145    /// Look up the CNAME records associated with `name`.
146    pub fn query_cname(&self, name: &str) -> c_ares::Result<c_ares::CNameResults> {
147        blockify!(self.inner, query_cname, name)
148    }
149
150    /// Search for the CNAME records associated with `name`.
151    pub fn search_cname(&self, name: &str) -> c_ares::Result<c_ares::CNameResults> {
152        blockify!(self.inner, search_cname, name)
153    }
154
155    /// Look up the MX records associated with `name`.
156    pub fn query_mx(&self, name: &str) -> c_ares::Result<c_ares::MXResults> {
157        blockify!(self.inner, query_mx, name)
158    }
159
160    /// Search for the MX records associated with `name`.
161    pub fn search_mx(&self, name: &str) -> c_ares::Result<c_ares::MXResults> {
162        blockify!(self.inner, search_mx, name)
163    }
164
165    /// Look up the NAPTR records associated with `name`.
166    pub fn query_naptr(&self, name: &str) -> c_ares::Result<c_ares::NAPTRResults> {
167        blockify!(self.inner, query_naptr, name)
168    }
169
170    /// Search for the NAPTR records associated with `name`.
171    pub fn search_naptr(&self, name: &str) -> c_ares::Result<c_ares::NAPTRResults> {
172        blockify!(self.inner, search_naptr, name)
173    }
174
175    /// Look up the NS records associated with `name`.
176    pub fn query_ns(&self, name: &str) -> c_ares::Result<c_ares::NSResults> {
177        blockify!(self.inner, query_ns, name)
178    }
179
180    /// Search for the NS records associated with `name`.
181    pub fn search_ns(&self, name: &str) -> c_ares::Result<c_ares::NSResults> {
182        blockify!(self.inner, search_ns, name)
183    }
184
185    /// Look up the PTR records associated with `name`.
186    pub fn query_ptr(&self, name: &str) -> c_ares::Result<c_ares::PTRResults> {
187        blockify!(self.inner, query_ptr, name)
188    }
189
190    /// Search for the PTR records associated with `name`.
191    pub fn search_ptr(&self, name: &str) -> c_ares::Result<c_ares::PTRResults> {
192        blockify!(self.inner, search_ptr, name)
193    }
194
195    /// Look up the SOA records associated with `name`.
196    pub fn query_soa(&self, name: &str) -> c_ares::Result<c_ares::SOAResult> {
197        blockify!(self.inner, query_soa, name)
198    }
199
200    /// Search for the SOA records associated with `name`.
201    pub fn search_soa(&self, name: &str) -> c_ares::Result<c_ares::SOAResult> {
202        blockify!(self.inner, search_soa, name)
203    }
204
205    /// Look up the SRV records associated with `name`.
206    pub fn query_srv(&self, name: &str) -> c_ares::Result<c_ares::SRVResults> {
207        blockify!(self.inner, query_srv, name)
208    }
209
210    /// Search for the SRV records associated with `name`.
211    pub fn search_srv(&self, name: &str) -> c_ares::Result<c_ares::SRVResults> {
212        blockify!(self.inner, search_srv, name)
213    }
214
215    /// Look up the TXT records associated with `name`.
216    pub fn query_txt(&self, name: &str) -> c_ares::Result<c_ares::TXTResults> {
217        blockify!(self.inner, query_txt, name)
218    }
219
220    /// Search for the TXT records associated with `name`.
221    pub fn search_txt(&self, name: &str) -> c_ares::Result<c_ares::TXTResults> {
222        blockify!(self.inner, search_txt, name)
223    }
224
225    /// Look up the URI records associated with `name`.
226    pub fn query_uri(&self, name: &str) -> c_ares::Result<c_ares::URIResults> {
227        blockify!(self.inner, query_uri, name)
228    }
229
230    /// Search for the URI records associated with `name`.
231    pub fn search_uri(&self, name: &str) -> c_ares::Result<c_ares::URIResults> {
232        blockify!(self.inner, search_uri, name)
233    }
234
235    /// Perform a host query by address.
236    ///
237    /// This method is one of the very few places where this library performs strictly more
238    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
239    /// prefer to use the analogous method on the `Resolver`.
240    pub fn get_host_by_address(&self, address: &IpAddr) -> c_ares::Result<HostResults> {
241        let (tx, rx) = mpsc::sync_channel(1);
242        self.inner.get_host_by_address(address, move |result| {
243            tx.send(result.map(Into::into)).unwrap()
244        });
245        rx.recv().unwrap()
246    }
247
248    /// Perform a host query by name.
249    ///
250    /// This method is one of the very few places where this library performs strictly more
251    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
252    /// prefer to use the analogous method on the `Resolver`.
253    pub fn get_host_by_name(
254        &self,
255        name: &str,
256        family: c_ares::AddressFamily,
257    ) -> c_ares::Result<HostResults> {
258        let (tx, rx) = mpsc::sync_channel(1);
259        self.inner.get_host_by_name(name, family, move |result| {
260            tx.send(result.map(Into::into)).unwrap()
261        });
262        rx.recv().unwrap()
263    }
264
265    /// Address-to-nodename translation in protocol-independent manner.
266    ///
267    /// This method is one of the very few places where this library performs strictly more
268    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
269    /// prefer to use the analogous method on the `Resolver`.
270    pub fn get_name_info<F>(
271        &self,
272        address: &SocketAddr,
273        flags: c_ares::NIFlags,
274    ) -> c_ares::Result<NameInfoResult> {
275        let (tx, rx) = mpsc::sync_channel(1);
276        self.inner.get_name_info(address, flags, move |result| {
277            tx.send(result.map(Into::into)).unwrap()
278        });
279        rx.recv().unwrap()
280    }
281
282    /// Initiate a single-question DNS query for `name`.  The class and type of the query are per
283    /// the provided parameters, taking values as defined in `arpa/nameser.h`.
284    ///
285    /// This method is one of the very few places where this library performs strictly more
286    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
287    /// prefer to use the analogous method on the `Resolver`.
288    ///
289    /// This method is provided so that users can query DNS types for which `c-ares` does not
290    /// provide a parser; or in case a third-party parser is preferred.  Usually, if a suitable
291    /// `query_xxx()` is available, that should be used.
292    pub fn query(&self, name: &str, dns_class: u16, query_type: u16) -> c_ares::Result<Vec<u8>> {
293        let (tx, rx) = mpsc::sync_channel(1);
294        self.inner
295            .query(name, dns_class, query_type, move |result| {
296                tx.send(result.map(std::borrow::ToOwned::to_owned)).unwrap()
297            });
298        rx.recv().unwrap()
299    }
300
301    /// Initiate a series of single-question DNS queries for `name`.  The class and type of the
302    /// query are per the provided parameters, taking values as defined in `arpa/nameser.h`.
303    ///
304    /// This method is one of the very few places where this library performs strictly more
305    /// allocation than the underlying `c-ares` code.  If this is a problem for you, you should
306    /// prefer to use the analogous method on the `Resolver`.
307    ///
308    /// This method is provided so that users can search DNS types for which `c-ares` does not
309    /// provide a parser; or in case a third-party parser is preferred.  Usually, if a suitable
310    /// `search_xxx()` is available, that should be used.
311    pub fn search(&self, name: &str, dns_class: u16, query_type: u16) -> c_ares::Result<Vec<u8>> {
312        let (tx, rx) = mpsc::sync_channel(1);
313        self.inner
314            .search(name, dns_class, query_type, move |result| {
315                tx.send(result.map(std::borrow::ToOwned::to_owned)).unwrap()
316            });
317        rx.recv().unwrap()
318    }
319}