embassy_net/
dns.rs

1//! DNS client compatible with the `embedded-nal-async` traits.
2//!
3//! This exists only for compatibility with crates that use `embedded-nal-async`.
4//! Prefer using [`Stack::dns_query`](crate::Stack::dns_query) directly if you're
5//! not using `embedded-nal-async`.
6
7use heapless::Vec;
8pub use smoltcp::socket::dns::{DnsQuery, Socket};
9pub(crate) use smoltcp::socket::dns::{GetQueryResultError, StartQueryError};
10pub use smoltcp::wire::{DnsQueryType, IpAddress};
11
12use crate::Stack;
13
14/// Errors returned by DnsSocket.
15#[derive(Debug, PartialEq, Eq, Clone, Copy)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub enum Error {
18    /// Invalid name
19    InvalidName,
20    /// Name too long
21    NameTooLong,
22    /// Name lookup failed
23    Failed,
24}
25
26impl From<GetQueryResultError> for Error {
27    fn from(_: GetQueryResultError) -> Self {
28        Self::Failed
29    }
30}
31
32impl From<StartQueryError> for Error {
33    fn from(e: StartQueryError) -> Self {
34        match e {
35            StartQueryError::NoFreeSlot => Self::Failed,
36            StartQueryError::InvalidName => Self::InvalidName,
37            StartQueryError::NameTooLong => Self::NameTooLong,
38        }
39    }
40}
41
42/// DNS client compatible with the `embedded-nal-async` traits.
43///
44/// This exists only for compatibility with crates that use `embedded-nal-async`.
45/// Prefer using [`Stack::dns_query`](crate::Stack::dns_query) directly if you're
46/// not using `embedded-nal-async`.
47pub struct DnsSocket<'a> {
48    stack: Stack<'a>,
49}
50
51impl<'a> DnsSocket<'a> {
52    /// Create a new DNS socket using the provided stack.
53    ///
54    /// NOTE: If using DHCP, make sure it has reconfigured the stack to ensure the DNS servers are updated.
55    pub fn new(stack: Stack<'a>) -> Self {
56        Self { stack }
57    }
58
59    /// Make a query for a given name and return the corresponding IP addresses.
60    pub async fn query(
61        &self,
62        name: &str,
63        qtype: DnsQueryType,
64    ) -> Result<Vec<IpAddress, { smoltcp::config::DNS_MAX_RESULT_COUNT }>, Error> {
65        self.stack.dns_query(name, qtype).await
66    }
67}
68
69impl<'a> embedded_nal_async::Dns for DnsSocket<'a> {
70    type Error = Error;
71
72    async fn get_host_by_name(
73        &self,
74        host: &str,
75        addr_type: embedded_nal_async::AddrType,
76    ) -> Result<core::net::IpAddr, Self::Error> {
77        use core::net::IpAddr;
78
79        use embedded_nal_async::AddrType;
80
81        let (qtype, secondary_qtype) = match addr_type {
82            AddrType::IPv4 => (DnsQueryType::A, None),
83            AddrType::IPv6 => (DnsQueryType::Aaaa, None),
84            AddrType::Either => {
85                #[cfg(not(feature = "proto-ipv6"))]
86                let v6_first = false;
87                #[cfg(feature = "proto-ipv6")]
88                let v6_first = self.stack.config_v6().is_some();
89                match v6_first {
90                    true => (DnsQueryType::Aaaa, Some(DnsQueryType::A)),
91                    false => (DnsQueryType::A, Some(DnsQueryType::Aaaa)),
92                }
93            }
94        };
95        let mut addrs = self.query(host, qtype).await?;
96        if addrs.is_empty() {
97            if let Some(qtype) = secondary_qtype {
98                addrs = self.query(host, qtype).await?
99            }
100        }
101        if let Some(first) = addrs.get(0) {
102            Ok(match first {
103                #[cfg(feature = "proto-ipv4")]
104                IpAddress::Ipv4(addr) => IpAddr::V4(*addr),
105                #[cfg(feature = "proto-ipv6")]
106                IpAddress::Ipv6(addr) => IpAddr::V6(*addr),
107            })
108        } else {
109            Err(Error::Failed)
110        }
111    }
112
113    async fn get_host_by_address(&self, _addr: core::net::IpAddr, _result: &mut [u8]) -> Result<usize, Self::Error> {
114        todo!()
115    }
116}
117
118fn _assert_covariant<'a, 'b: 'a>(x: DnsSocket<'b>) -> DnsSocket<'a> {
119    x
120}