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}