rsip_dns/records/
mod.rs

1//! This module hosts all the DNS types that are used by the [Dnsclient](crate::DnsClient).
2
3mod addr_record;
4mod naptr_record;
5mod srv_record;
6
7pub use addr_record::AddrRecord;
8pub use naptr_record::{NaptrEntry, NaptrFlags, NaptrRecord, NaptrServices};
9pub use srv_record::{SrvEntry, SrvRecord};
10
11use rsip::{Domain, Error, Transport};
12use std::convert::TryFrom;
13
14/// Simple struct that holds the srv domain properties (namely actual domain, protocol and whether
15/// it's secure or not).
16#[derive(Debug, Clone, Hash, Eq, PartialEq)]
17pub struct SrvDomain {
18    pub domain: Domain,
19    pub protocol: Transport,
20    pub secure: bool,
21}
22
23impl SrvDomain {
24    pub fn transport(&self) -> Transport {
25        match (self.secure, self.protocol) {
26            (true, Transport::Tcp) => Transport::Tls,
27            (true, Transport::Sctp) => Transport::TlsSctp,
28            (true, Transport::Ws) => Transport::Wss,
29            _ => self.protocol,
30        }
31    }
32}
33
34//
35//TODO: here we skip NAPTR flags to convert to SrvDomain and take into account only the replacement
36//domain. We do that because otherwise, we might build a SrvDomain that on Display is different
37//than the NAPTR replacement. Probably not ideal and need improvement.
38//Maybe we could log something if we find a diff between the 2.
39impl TryFrom<NaptrEntry> for SrvDomain {
40    type Error = rsip::Error;
41
42    fn try_from(entry: NaptrEntry) -> Result<Self, Self::Error> {
43        match SrvDomain::try_from(entry.replacement.clone()) {
44            Ok(srv_domain) => Ok(srv_domain),
45            Err(_) => Err(Error::Unexpected(format!(
46                "Can't convert into SrvDomain for Naptr Entry with replacement {}",
47                entry.replacement
48            ))),
49        }
50    }
51}
52
53impl From<(Domain, Transport)> for SrvDomain {
54    fn from(tuple: (Domain, Transport)) -> Self {
55        Self { domain: tuple.0, protocol: tuple.1.protocol(), secure: false }
56    }
57}
58
59impl std::fmt::Display for SrvDomain {
60    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61        match self.secure {
62            true => {
63                write!(f, "_sips._{}.{}", self.protocol.to_string().to_lowercase(), self.domain)
64            }
65            false => {
66                write!(f, "_sip._{}.{}", self.protocol.to_string().to_lowercase(), self.domain)
67            }
68        }
69    }
70}
71
72impl TryFrom<Domain> for SrvDomain {
73    type Error = rsip::Error;
74
75    fn try_from(from: Domain) -> Result<Self, Self::Error> {
76        Self::try_from(from.to_string().as_str())
77    }
78}
79
80impl TryFrom<&str> for SrvDomain {
81    type Error = rsip::Error;
82
83    fn try_from(from: &str) -> Result<Self, Self::Error> {
84        use nom::{
85            bytes::complete::{tag, take_until},
86            error::VerboseError,
87            sequence::tuple,
88        };
89        use std::convert::TryInto;
90
91        let (rem, (_, scheme, _)) =
92            tuple::<_, _, VerboseError<&str>, _>((tag("_"), take_until("."), tag(".")))(from)
93                .map_err(|_| Error::tokenizer(("SrvDomain scheme", from)))?;
94        let scheme: rsip::Scheme =
95            rsip::common::uri::scheme::Tokenizer::from(scheme.as_bytes()).try_into()?;
96
97        let (domain, (_, transport, _)) =
98            tuple::<_, _, VerboseError<&str>, _>((tag("_"), take_until("."), tag(".")))(rem)
99                .map_err(|_| Error::tokenizer(("SrvDomain transport", from)))?;
100        let transport: rsip::Transport =
101            rsip::common::transport::Tokenizer::from(transport.as_bytes()).try_into()?;
102
103        Ok(Self {
104            secure: scheme.is_sips()?,
105            protocol: transport.protocol(),
106            domain: domain.into(),
107        })
108    }
109}