Skip to main content

scion_stack/
resolver.rs

1// Copyright 2026 Anapaya Systems
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//   http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//! DNS resolution helpers for SCION addresses.
15
16pub mod txt;
17
18use async_trait::async_trait;
19use scion_proto::address::ScionAddr;
20use thiserror::Error;
21
22/// DNS resolver trait for SCION address discovery.
23///
24/// Implementations return zero or more `ScionAddr` values for a given domain
25/// name. The resolver is expected to be async and safe to share across tasks.
26///
27/// # Error handling
28///
29/// Implementations SHOULD return `ResolveError::NoValidEntries` only when a
30/// lookup succeeds but yields no valid SCION TXT entries. Partial failures
31/// SHOULD return the valid addresses and log warnings for invalid entries.
32#[async_trait]
33pub trait ScionDnsResolver: Send + Sync {
34    /// Resolve a domain into SCION addresses.
35    ///
36    /// Implementations SHOULD return only valid addresses and log warnings for
37    /// invalid TXT entries. Errors are reserved for lookup failures or when no
38    /// valid addresses can be produced.
39    async fn resolve(&self, domain: &str) -> Result<Vec<ScionAddr>, ResolveError>;
40}
41
42/// Errors returned by SCION DNS resolution.
43#[derive(Debug, Error, PartialEq)]
44pub enum ResolveError {
45    /// DNS lookup failed.
46    #[error("dns lookup failed: {0}")]
47    DnsLookup(String),
48    /// No valid TSAR entries were found.
49    #[error("no valid TSAR TXT entries for {domain}")]
50    NoValidEntries {
51        /// Domain name that was looked up.
52        domain: String,
53        /// Invalid entries encountered during parsing or TXT decoding.
54        invalid_entries: Vec<InvalidEntry>,
55    },
56}
57
58/// Metadata for a TXT entry that could not be parsed.
59#[derive(Debug, Clone, PartialEq)]
60pub struct InvalidEntry {
61    raw: String,
62    reason: String,
63}
64
65impl InvalidEntry {
66    pub(crate) fn new(raw: impl Into<String>, reason: impl Into<String>) -> Self {
67        Self {
68            raw: raw.into(),
69            reason: reason.into(),
70        }
71    }
72
73    /// Return the raw TXT entry that failed parsing.
74    pub fn raw(&self) -> &str {
75        &self.raw
76    }
77
78    /// Return the reason this TXT entry failed parsing.
79    pub fn reason(&self) -> &str {
80        &self.reason
81    }
82}