rsip_dns/lookup/
mod.rs

1use crate::{records::SrvDomain, resolvables::*, Context, DnsClient, Target};
2use async_trait::async_trait;
3use rsip::{Domain, Host, Port, Transport};
4use std::net::IpAddr;
5
6#[derive(Debug, Clone)]
7pub enum Lookup<C>
8where
9    C: DnsClient,
10{
11    IpAddr(ResolvableIpAddr),
12    DomainWithPort(ResolvableAddrRecord<C>),
13    //This variant uses only the given transport as RFC says, but I have a feeling that we should
14    //add an exhaustive variant that apart from the given transport, tries AddrRecords for the given
15    //available transports.
16    DomainWithTransport(ResolvableVec<ResolvableEnum<C>, Target>),
17    JustDomain(ResolvableVec<ResolvableEnum<C>, Target>),
18}
19
20#[async_trait]
21impl<C> ResolvableExt<Target> for Lookup<C>
22where
23    C: DnsClient,
24{
25    fn state(&self) -> ResolvableState {
26        match self {
27            Self::IpAddr(inner) => inner.state(),
28            Self::DomainWithPort(inner) => inner.state(),
29            Self::DomainWithTransport(inner) => inner.state(),
30            Self::JustDomain(inner) => inner.state(),
31        }
32    }
33
34    async fn resolve_next(&mut self) -> Option<Target> {
35        match self {
36            Self::IpAddr(inner) => inner.resolve_next().await,
37            Self::DomainWithPort(inner) => inner.resolve_next().await,
38            Self::DomainWithTransport(inner) => inner.resolve_next().await,
39            Self::JustDomain(inner) => inner.resolve_next().await,
40        }
41    }
42}
43
44impl<C> From<Context<C>> for Lookup<C>
45where
46    C: DnsClient,
47{
48    fn from(ctx: Context<C>) -> Self {
49        match ctx.host {
50            Host::IpAddr(ip_addr) => ip_addr_lookup(ip_addr, ctx),
51            Host::Domain(ref domain) => match (ctx.port, ctx.transport) {
52                (Some(port), _) => domain_with_port_lookup(domain.clone(), port, ctx),
53                (None, Some(transport)) => {
54                    domain_with_transport_lookup(domain.clone(), transport, ctx)
55                }
56                (None, None) => just_domain_lookup(domain.clone(), ctx),
57            },
58        }
59    }
60}
61
62fn ip_addr_lookup<C: DnsClient>(ip_addr: IpAddr, ctx: Context<C>) -> Lookup<C> {
63    Lookup::IpAddr(ResolvableIpAddr::new(
64        ip_addr,
65        ctx.default_transport().default_port(),
66        ctx.default_transport(),
67    ))
68}
69
70fn domain_with_port_lookup<C: DnsClient>(domain: Domain, port: Port, ctx: Context<C>) -> Lookup<C> {
71    Lookup::DomainWithPort(ResolvableAddrRecord::new(
72        ctx.dns_client.clone(),
73        domain,
74        port,
75        ctx.default_transport(),
76    ))
77}
78
79fn domain_with_transport_lookup<C: DnsClient>(
80    domain: Domain,
81    transport: Transport,
82    ctx: Context<C>,
83) -> Lookup<C> {
84    let mut lookups: Vec<ResolvableEnum<C>> = vec![];
85
86    let srv_domain = SrvDomain { secure: ctx.secure, protocol: transport.protocol(), domain };
87    lookups.push(ResolvableSrvRecord::new(ctx.dns_client.clone(), srv_domain.clone()).into());
88    lookups.push(
89        ResolvableAddrRecord::new(
90            ctx.dns_client,
91            srv_domain.domain.clone(),
92            srv_domain.transport().default_port(),
93            srv_domain.transport(),
94        )
95        .into(),
96    );
97
98    Lookup::DomainWithTransport(ResolvableVec::non_empty(lookups))
99}
100
101fn just_domain_lookup<C: DnsClient>(domain: Domain, ctx: Context<C>) -> Lookup<C> {
102    let mut lookups: Vec<ResolvableEnum<C>> = vec![ResolvableNaptrRecord::new(
103        ctx.dns_client.clone(),
104        domain.clone(),
105        ctx.available_transports(),
106    )
107    .into()];
108
109    ctx.available_protocols().into_iter().for_each(|transport| {
110        let srv_domain = SrvDomain {
111            secure: ctx.secure,
112            protocol: transport.protocol(),
113            domain: domain.clone(),
114        };
115
116        lookups.push(ResolvableSrvRecord::new(ctx.dns_client.clone(), srv_domain).into());
117    });
118
119    let default_transport = match ctx.secure {
120        true => Transport::default_secure_transport(),
121        false => Transport::default_insecure_transport(),
122    };
123    lookups.push(
124        ResolvableAddrRecord::new(
125            ctx.dns_client,
126            domain,
127            default_transport.default_port(),
128            default_transport,
129        )
130        .into(),
131    );
132
133    Lookup::JustDomain(ResolvableVec::non_empty(lookups))
134}
135
136/*
137fn srv_domains_from(secure: bool, transports: Vec<Transport>, domain: Domain) -> Vec<SrvDomain> {
138    transports
139        .into_iter()
140        .map(|transport| SrvDomain {
141            secure,
142            transport,
143            domain: domain.clone(),
144        })
145        .collect::<Vec<_>>()
146}*/