std_embedded_nal_async/
dns.rs

1//! DNS implementation based on `getaddrinfo` and `getnameinfo`
2
3use core::net::{IpAddr, SocketAddr};
4use embedded_nal_async::AddrType;
5
6/// An std::io::Error compatible error type constructable when to_socket_addrs comes up empty
7/// (because it does not produce an error of its own)
8#[derive(Debug)]
9struct NotFound;
10
11impl core::fmt::Display for NotFound {
12    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
13        write!(f, "Not found")
14    }
15}
16
17impl std::error::Error for NotFound {}
18
19/// An std::io::Error compatible error type expressing that a name doesn't fit in the
20/// provided response buffer.
21#[derive(Debug)]
22struct TooLong;
23
24impl core::fmt::Display for TooLong {
25    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
26        write!(f, "Name too long")
27    }
28}
29
30impl std::error::Error for TooLong {}
31
32impl embedded_nal_async::Dns for crate::Stack {
33    type Error = std::io::Error;
34
35    async fn get_host_by_name(
36        &self,
37        hostname: &str,
38        addr_type: AddrType,
39    ) -> Result<IpAddr, Self::Error> {
40        let accept_v4 = addr_type != AddrType::IPv6;
41        let accept_v6 = addr_type != AddrType::IPv4;
42
43        // We don't need a port, but the interface of to_socket_addrs (like getaddrinfo) insists on
44        // ports being around.
45        let fake_port = 1234u16;
46
47        for addr in async_net::resolve((hostname, fake_port)).await? {
48            match addr {
49                SocketAddr::V4(v) if accept_v4 => {
50                    return Ok(v.ip().octets().into());
51                }
52                SocketAddr::V6(v) if accept_v6 => {
53                    return Ok(v.ip().octets().into());
54                }
55                _ => continue,
56            }
57        }
58
59        Err(Self::Error::new(std::io::ErrorKind::NotFound, NotFound))
60    }
61
62    async fn get_host_by_address(
63        &self,
64        addr: IpAddr,
65        result: &mut [u8],
66    ) -> Result<usize, Self::Error> {
67        let fakesocketaddr = std::net::SocketAddr::new(addr, 1234);
68
69        let (name, _service) =
70            blocking::unblock(move || dns_lookup::getnameinfo(&fakesocketaddr, 0)).await?;
71
72        if name.parse::<IpAddr>().is_ok() {
73            // embedded_nal requires a host name to be returned and is not content with stringified
74            // IP addresses
75            return Err(Self::Error::new(std::io::ErrorKind::NotFound, NotFound));
76        }
77
78        if let Some(result) = result.get_mut(..name.len()) {
79            result.copy_from_slice(name.as_bytes());
80            Ok(result.len())
81        } else {
82            Err(Self::Error::new(std::io::ErrorKind::OutOfMemory, TooLong))
83        }
84    }
85}