Coverage Report

Created: 2025-08-11 06:51

/src/hickory-dns/crates/proto/src/error.rs
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2015-2020 Benjamin Fry <benjaminfry@me.com>
2
//
3
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4
// https://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5
// https://opensource.org/licenses/MIT>, at your option. This file may not be
6
// copied, modified, or distributed except according to those terms.
7
8
//! Error types for the crate
9
10
#![deny(missing_docs)]
11
12
use alloc::borrow::ToOwned;
13
use alloc::boxed::Box;
14
use alloc::string::{String, ToString};
15
use alloc::sync::Arc;
16
use alloc::vec::Vec;
17
use core::cmp::Ordering;
18
use core::fmt;
19
#[cfg(feature = "std")]
20
use std::{io, sync};
21
22
#[cfg(feature = "backtrace")]
23
pub use backtrace::Backtrace as ExtBacktrace;
24
use enum_as_inner::EnumAsInner;
25
#[cfg(feature = "backtrace")]
26
use once_cell::sync::Lazy;
27
use thiserror::Error;
28
use tracing::debug;
29
30
#[cfg(feature = "__dnssec")]
31
use crate::dnssec::Proof;
32
#[cfg(any(feature = "dnssec-aws-lc-rs", feature = "dnssec-ring"))]
33
use crate::dnssec::ring_like::Unspecified;
34
use crate::op::{Header, Query, ResponseCode};
35
use crate::rr::{Record, RecordType, rdata::SOA, resource::RecordRef};
36
use crate::serialize::binary::DecodeError;
37
use crate::xfer::DnsResponse;
38
39
/// Boolean for checking if backtrace is enabled at runtime
40
#[cfg(feature = "backtrace")]
41
pub static ENABLE_BACKTRACE: Lazy<bool> = Lazy::new(|| {
42
    use std::env;
43
    let bt = env::var("RUST_BACKTRACE");
44
    matches!(bt.as_ref().map(|s| s as &str), Ok("full") | Ok("1"))
45
});
46
47
/// Generate a backtrace
48
///
49
/// If RUST_BACKTRACE is 1 or full then this will return Some(Backtrace), otherwise, NONE.
50
#[cfg(feature = "backtrace")]
51
#[macro_export]
52
macro_rules! trace {
53
    () => {{
54
        use $crate::ExtBacktrace as Backtrace;
55
56
        if *$crate::ENABLE_BACKTRACE {
57
            Some(Backtrace::new())
58
        } else {
59
            None
60
        }
61
    }};
62
}
63
64
/// An alias for results returned by functions of this crate
65
pub(crate) type ProtoResult<T> = ::core::result::Result<T, ProtoError>;
66
67
/// The error kind for errors that get returned in the crate
68
0
#[derive(Debug, EnumAsInner, Error)]
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_bad_query_count
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_bad_query_count_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_bad_query_count
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_bad_query_count
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_busy
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_canceled
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_canceled_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_canceled
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_canceled
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_character_data_too_long
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_character_data_too_long_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_character_data_too_long
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_character_data_too_long
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_label_overlaps_with_other
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_label_overlaps_with_other_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_label_overlaps_with_other
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_label_overlaps_with_other
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_nsec
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_nsec_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_nsec
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_nsec
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_dns_key_protocol_not3
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_dns_key_protocol_not3_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_dns_key_protocol_not3
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_dns_key_protocol_not3
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_domain_name_too_long
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_domain_name_too_long_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_domain_name_too_long
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_domain_name_too_long
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_edns_name_not_root
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_edns_name_not_root_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_edns_name_not_root
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_edns_name_not_root
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_form_error
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_form_error_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_form_error
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_form_error
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_incorrect_r_data_length_read
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_incorrect_r_data_length_read_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_incorrect_r_data_length_read
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_incorrect_r_data_length_read
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_label_bytes_too_long
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_label_bytes_too_long_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_label_bytes_too_long
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_label_bytes_too_long
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_pointer_not_prior_to_label
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_pointer_not_prior_to_label_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_pointer_not_prior_to_label
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_pointer_not_prior_to_label
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_max_buffer_size_exceeded
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_max_buffer_size_exceeded_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_max_buffer_size_exceeded
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_max_buffer_size_exceeded
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_max_record_limit_exceeded
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_max_record_limit_exceeded_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_max_record_limit_exceeded
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_max_record_limit_exceeded
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_message
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_message_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_message
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_message
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_msg
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_msg_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_msg
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_msg
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_no_connections
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_not_all_records_written
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_not_all_records_written_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_not_all_records_written
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_not_all_records_written
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_no_records_found
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_no_records_found_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_no_records_found
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_no_records_found
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_unknown_algorithm_type_value
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_unknown_algorithm_type_value_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_unknown_algorithm_type_value
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_unknown_algorithm_type_value
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_unknown_digest_type_value
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_unknown_digest_type_value_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_unknown_digest_type_value
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_unknown_digest_type_value
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_unknown_dns_class_str
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_unknown_dns_class_str_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_unknown_dns_class_str
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_unknown_dns_class_str
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_unknown_dns_class_value
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_unknown_dns_class_value_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_unknown_dns_class_value
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_unknown_dns_class_value
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_unknown_record_type_str
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_unknown_record_type_str_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_unknown_record_type_str
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_unknown_record_type_str
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_unknown_record_type_value
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_unknown_record_type_value_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_unknown_record_type_value
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_unknown_record_type_value
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_unrecognized_label_code
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_unrecognized_label_code_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_unrecognized_label_code
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_unrecognized_label_code
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_unrecognized_nsec3_flags
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_unrecognized_nsec3_flags_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_unrecognized_nsec3_flags
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_unrecognized_nsec3_flags
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_unrecognized_csync_flags
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_unrecognized_csync_flags_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_unrecognized_csync_flags
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_unrecognized_csync_flags
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_io
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_io_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_io
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_io
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_poisoned
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_request_refused
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_response_code
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_response_code_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_response_code
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_response_code
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_ring
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_ring_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_ring
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_ring
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_timer
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_timeout
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_url_parsing
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_url_parsing_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_url_parsing
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_url_parsing
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_utf8
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_utf8_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_utf8
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_utf8
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_from_utf8
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_from_utf8_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_from_utf8
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_from_utf8
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_parse_int
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_parse_int_mut
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::as_parse_int
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::into_parse_int
Unexecuted instantiation: <hickory_proto::error::ProtoErrorKind>::is_query_case_mismatch
69
#[non_exhaustive]
70
pub enum ProtoErrorKind {
71
    /// Query count is not one
72
    #[error("there should only be one query per request, got: {0}")]
73
    BadQueryCount(usize),
74
75
    /// The underlying resource is too busy
76
    ///
77
    /// This is a signal that an internal resource is too busy. The intended action should be tried
78
    /// again, ideally after waiting for a little while for the situation to improve. Alternatively,
79
    /// the action could be tried on another resource (for example, in a name server pool).
80
    #[error("resource too busy")]
81
    Busy,
82
83
    /// An error caused by a canceled future
84
    #[error("future was canceled: {0:?}")]
85
    Canceled(futures_channel::oneshot::Canceled),
86
87
    /// Character data length exceeded the limit
88
    #[non_exhaustive]
89
    #[error("char data length exceeds {max}: {len}")]
90
    CharacterDataTooLong {
91
        /// Specified maximum
92
        max: usize,
93
        /// Actual length
94
        len: usize,
95
    },
96
97
    /// Overlapping labels
98
    #[non_exhaustive]
99
    #[error("overlapping labels name {label} other {other}")]
100
    LabelOverlapsWithOther {
101
        /// Start of the label that is overlaps
102
        label: usize,
103
        /// Start of the other label
104
        other: usize,
105
    },
106
107
    /// No Records and there is a corresponding DNSSEC Proof for NSEC
108
    #[cfg(feature = "__dnssec")]
109
    #[non_exhaustive]
110
    #[error("DNSSEC Negative Record Response for {query}, {proof}")]
111
    Nsec {
112
        /// Query for which the NSEC was returned
113
        query: Box<Query>,
114
        /// Response for which the NSEC was returned
115
        response: Box<DnsResponse>,
116
        /// DNSSEC proof of the record
117
        proof: Proof,
118
    },
119
120
    /// DNS protocol version doesn't have the expected version 3
121
    #[error("dns key value unknown, must be 3: {0}")]
122
    DnsKeyProtocolNot3(u8),
123
124
    /// A domain name was too long
125
    #[error("name label data exceed 255: {0}")]
126
    DomainNameTooLong(usize),
127
128
    /// EDNS resource record label is not the root label, although required
129
    #[error("edns resource record label must be the root label (.): {0}")]
130
    EdnsNameNotRoot(crate::rr::Name),
131
132
    /// Format error in Message Parsing
133
    #[error("message format error: {error}")]
134
    FormError {
135
        /// Header of the bad Message
136
        header: Header,
137
        /// Error that occurred while parsing the Message
138
        error: Box<ProtoError>,
139
    },
140
141
    /// The length of rdata read was not as expected
142
    #[non_exhaustive]
143
    #[error("incorrect rdata length read: {read} expected: {len}")]
144
    IncorrectRDataLengthRead {
145
        /// The amount of read data
146
        read: usize,
147
        /// The expected length of the data
148
        len: usize,
149
    },
150
151
    /// Label bytes exceeded the limit of 63
152
    #[error("label bytes exceed 63: {0}")]
153
    LabelBytesTooLong(usize),
154
155
    /// Pointer points to an index within or after the current name
156
    #[non_exhaustive]
157
    #[error("label points to data not prior to idx: {idx} ptr: {ptr}")]
158
    PointerNotPriorToLabel {
159
        /// index of the label containing this pointer
160
        idx: usize,
161
        /// location to which the pointer is directing
162
        ptr: u16,
163
    },
164
165
    /// The maximum buffer size was exceeded
166
    #[error("maximum buffer size exceeded: {0}")]
167
    MaxBufferSizeExceeded(usize),
168
169
    /// Maximum record limit was exceeded
170
    #[error("maximum record limit for {record_type} exceeded: {count} records")]
171
    MaxRecordLimitExceeded {
172
        /// number of records
173
        count: usize,
174
        /// The record type that triggered the error.
175
        record_type: RecordType,
176
    },
177
178
    /// An error with an arbitrary message, referenced as &'static str
179
    #[error("{0}")]
180
    Message(&'static str),
181
182
    /// An error with an arbitrary message, stored as String
183
    #[error("{0}")]
184
    Msg(String),
185
186
    /// No resolvers available
187
    #[error("no connections available")]
188
    NoConnections,
189
190
    /// Not all records were able to be written
191
    #[non_exhaustive]
192
    #[error("not all records could be written, wrote: {count}")]
193
    NotAllRecordsWritten {
194
        /// Number of records that were written before the error
195
        count: usize,
196
    },
197
198
    /// No records were found for a query
199
    #[error("no records found for {:?}", .0.query)]
200
    NoRecordsFound(NoRecords),
201
202
    /// An unknown algorithm type was found
203
    #[error("algorithm type value unknown: {0}")]
204
    UnknownAlgorithmTypeValue(u8),
205
206
    /// An unknown digest type was found
207
    #[error("digest type value unknown: {0}")]
208
    UnknownDigestTypeValue(u8),
209
210
    /// An unknown dns class was found
211
    #[error("dns class string unknown: {0}")]
212
    UnknownDnsClassStr(String),
213
214
    /// An unknown dns class value was found
215
    #[error("dns class value unknown: {0}")]
216
    UnknownDnsClassValue(u16),
217
218
    /// An unknown record type string was found
219
    #[error("record type string unknown: {0}")]
220
    UnknownRecordTypeStr(String),
221
222
    /// An unknown record type value was found
223
    #[error("record type value unknown: {0}")]
224
    UnknownRecordTypeValue(u16),
225
226
    /// An unrecognized label code was found
227
    #[error("unrecognized label code: {0:b}")]
228
    UnrecognizedLabelCode(u8),
229
230
    /// Unrecognized nsec3 flags were found
231
    #[error("nsec3 flags should be 0b0000000*: {0:b}")]
232
    UnrecognizedNsec3Flags(u8),
233
234
    /// Unrecognized csync flags were found
235
    #[error("csync flags should be 0b000000**: {0:b}")]
236
    UnrecognizedCsyncFlags(u16),
237
238
    // foreign
239
    /// An error got returned from IO
240
    #[cfg(feature = "std")]
241
    #[error("io error: {0}")]
242
    Io(Arc<io::Error>),
243
244
    /// Any sync poised error
245
    #[error("lock poisoned error")]
246
    Poisoned,
247
248
    /// A request was Refused due to some access check
249
    #[error("request refused")]
250
    RequestRefused,
251
252
    /// Received an error response code from the server
253
    #[error("error response: {0}")]
254
    ResponseCode(ResponseCode),
255
256
    /// A ring error
257
    #[cfg(feature = "__dnssec")]
258
    #[error("ring error: {0}")]
259
    Ring(#[from] Unspecified),
260
261
    /// A tokio timer error
262
    #[error("timer error")]
263
    Timer,
264
265
    /// A request timed out
266
    #[error("request timed out")]
267
    Timeout,
268
269
    /// An url parsing error
270
    #[error("url parsing error")]
271
    UrlParsing(#[from] url::ParseError),
272
273
    /// A utf8 parsing error
274
    #[error("error parsing utf8 string")]
275
    Utf8(#[from] core::str::Utf8Error),
276
277
    /// A utf8 parsing error
278
    #[error("error parsing utf8 string")]
279
    FromUtf8(#[from] alloc::string::FromUtf8Error),
280
281
    /// An int parsing error
282
    #[error("error parsing int")]
283
    ParseInt(#[from] core::num::ParseIntError),
284
285
    /// A Quinn (Quic) connection error occurred
286
    #[cfg(feature = "__quic")]
287
    #[error("error creating quic connection: {0}")]
288
    QuinnConnect(#[from] quinn::ConnectError),
289
290
    /// A Quinn (QUIC) connection error occurred
291
    #[cfg(feature = "__quic")]
292
    #[error("error with quic connection: {0}")]
293
    QuinnConnection(#[from] quinn::ConnectionError),
294
295
    /// A Quinn (QUIC) write error occurred
296
    #[cfg(feature = "__quic")]
297
    #[error("error writing to quic connection: {0}")]
298
    QuinnWriteError(#[from] quinn::WriteError),
299
300
    /// A Quinn (QUIC) read error occurred
301
    #[cfg(feature = "__quic")]
302
    #[error("error writing to quic read: {0}")]
303
    QuinnReadError(#[from] quinn::ReadExactError),
304
305
    /// A Quinn (QUIC) stream error occurred
306
    #[cfg(feature = "__quic")]
307
    #[error("referenced a closed QUIC stream: {0}")]
308
    QuinnStreamError(#[from] quinn::ClosedStream),
309
310
    /// A Quinn (QUIC) configuration error occurred
311
    #[cfg(feature = "__quic")]
312
    #[error("error constructing quic configuration: {0}")]
313
    QuinnConfigError(#[from] quinn::ConfigError),
314
315
    /// QUIC TLS config must include an AES-128-GCM cipher suite
316
    #[cfg(feature = "__quic")]
317
    #[error("QUIC TLS config must include an AES-128-GCM cipher suite")]
318
    QuinnTlsConfigError(#[from] quinn::crypto::rustls::NoInitialCipherSuite),
319
320
    /// Unknown QUIC stream used
321
    #[cfg(feature = "__quic")]
322
    #[error("an unknown quic stream was used")]
323
    QuinnUnknownStreamError,
324
325
    /// A quic message id should always be 0
326
    #[cfg(feature = "__quic")]
327
    #[error("quic messages should always be 0, got: {0}")]
328
    QuicMessageIdNot0(u16),
329
330
    /// A Rustls error occurred
331
    #[cfg(feature = "__tls")]
332
    #[error("rustls construction error: {0}")]
333
    RustlsError(#[from] rustls::Error),
334
335
    /// Case randomization is enabled, and a server did not echo a query name back with the same
336
    /// case.
337
    #[error("case of query name in response did not match")]
338
    QueryCaseMismatch,
339
}
340
341
impl From<NoRecords> for ProtoErrorKind {
342
0
    fn from(no_records: NoRecords) -> Self {
343
0
        Self::NoRecordsFound(no_records)
344
0
    }
345
}
346
347
/// Response where no records were found
348
#[derive(Clone, Debug)]
349
#[non_exhaustive]
350
pub struct NoRecords {
351
    /// The query for which no records were found.
352
    pub query: Box<Query>,
353
    /// If an SOA is present, then this is an authoritative response or a referral to another nameserver, see the negative_type field.
354
    pub soa: Option<Box<Record<SOA>>>,
355
    /// Nameservers may be present in addition to or in lieu of an SOA for a referral
356
    /// The tuple struct layout is vec[(Nameserver, [vec of glue records])]
357
    pub ns: Option<Arc<[ForwardNSData]>>,
358
    /// negative ttl, as determined from DnsResponse::negative_ttl
359
    ///  this will only be present if the SOA was also present.
360
    pub negative_ttl: Option<u32>,
361
    /// ResponseCode, if `NXDOMAIN`, the domain does not exist (and no other types).
362
    ///   If `NoError`, then the domain exists but there exist either other types at the same label, or subzones of that label.
363
    pub response_code: ResponseCode,
364
    /// Authority records from the query. These are important to preserve for DNSSEC validation.
365
    pub authorities: Option<Arc<[Record]>>,
366
}
367
368
impl NoRecords {
369
    /// Construct a new [`NoRecords`] from a query and a response code
370
0
    pub fn new(query: impl Into<Box<Query>>, response_code: ResponseCode) -> Self {
371
0
        Self {
372
0
            query: query.into(),
373
0
            soa: None,
374
0
            ns: None,
375
0
            negative_ttl: None,
376
0
            response_code,
377
0
            authorities: None,
378
0
        }
379
0
    }
380
}
381
382
impl From<AuthorityData> for NoRecords {
383
0
    fn from(value: AuthorityData) -> Self {
384
0
        let response_code = match value.is_nx_domain() {
385
0
            true => ResponseCode::NXDomain,
386
0
            false => ResponseCode::NoError,
387
        };
388
389
0
        Self {
390
0
            query: value.query,
391
0
            soa: value.soa,
392
0
            ns: None,
393
0
            negative_ttl: None,
394
0
            response_code,
395
0
            authorities: value.authorities,
396
0
        }
397
0
    }
398
}
399
400
/// Data from the authority section of a response.
401
#[derive(Clone, Debug)]
402
pub struct AuthorityData {
403
    /// Query
404
    pub query: Box<Query>,
405
    /// SOA
406
    pub soa: Option<Box<Record<SOA>>>,
407
    /// No records found?
408
    no_records_found: bool,
409
    /// IS nx domain?
410
    nx_domain: bool,
411
    /// Authority records
412
    pub authorities: Option<Arc<[Record]>>,
413
}
414
415
impl AuthorityData {
416
    /// Construct a new AuthorityData
417
0
    pub fn new(
418
0
        query: Box<Query>,
419
0
        soa: Option<Box<Record<SOA>>>,
420
0
        no_records_found: bool,
421
0
        nx_domain: bool,
422
0
        authorities: Option<Arc<[Record]>>,
423
0
    ) -> Self {
424
0
        Self {
425
0
            query,
426
0
            soa,
427
0
            no_records_found,
428
0
            nx_domain,
429
0
            authorities,
430
0
        }
431
0
    }
432
433
    /// are there records?
434
0
    pub fn is_no_records_found(&self) -> bool {
435
0
        self.no_records_found
436
0
    }
437
438
    /// is this nxdomain?
439
0
    pub fn is_nx_domain(&self) -> bool {
440
0
        self.nx_domain
441
0
    }
442
}
443
444
/// Data needed to process a NS-record-based referral.
445
#[derive(Clone, Debug)]
446
pub struct ForwardNSData {
447
    /// The referant NS record
448
    pub ns: Record,
449
    /// Any glue records associated with the referant NS record.
450
    pub glue: Arc<[Record]>,
451
}
452
453
/// The error type for errors that get returned in the crate
454
#[derive(Error, Clone, Debug)]
455
#[non_exhaustive]
456
pub struct ProtoError {
457
    /// Kind of error that occurred
458
    pub kind: ProtoErrorKind,
459
    /// Backtrace to the source of the error
460
    #[cfg(feature = "backtrace")]
461
    pub backtrack: Option<ExtBacktrace>,
462
}
463
464
impl ProtoError {
465
    /// Get the kind of the error
466
    #[inline]
467
3.13k
    pub fn kind(&self) -> &ProtoErrorKind {
468
3.13k
        &self.kind
469
3.13k
    }
<hickory_proto::error::ProtoError>::kind
Line
Count
Source
467
24
    pub fn kind(&self) -> &ProtoErrorKind {
468
24
        &self.kind
469
24
    }
<hickory_proto::error::ProtoError>::kind
Line
Count
Source
467
3.10k
    pub fn kind(&self) -> &ProtoErrorKind {
468
3.10k
        &self.kind
469
3.10k
    }
470
471
    /// If this is a ProtoErrorKind::Busy
472
    #[inline]
473
0
    pub fn is_busy(&self) -> bool {
474
0
        matches!(self.kind, ProtoErrorKind::Busy)
475
0
    }
476
477
    /// Returns true if this error represents NoConnections
478
    #[inline]
479
0
    pub fn is_no_connections(&self) -> bool {
480
0
        matches!(self.kind, ProtoErrorKind::NoConnections)
481
0
    }
482
483
    /// Returns true if the domain does not exist
484
    #[inline]
485
0
    pub fn is_nx_domain(&self) -> bool {
486
0
        matches!(
487
0
            self.kind,
488
            ProtoErrorKind::NoRecordsFound(NoRecords {
489
                response_code: ResponseCode::NXDomain,
490
                ..
491
            })
492
        )
493
0
    }
494
495
    /// Returns true if the error represents NoRecordsFound
496
    #[inline]
497
0
    pub fn is_no_records_found(&self) -> bool {
498
0
        matches!(self.kind, ProtoErrorKind::NoRecordsFound { .. })
499
0
    }
500
501
    /// Returns the SOA record, if the error contains one
502
    #[inline]
503
0
    pub fn into_soa(self) -> Option<Box<Record<SOA>>> {
504
0
        match self.kind {
505
0
            ProtoErrorKind::NoRecordsFound(NoRecords { soa, .. }) => soa,
506
0
            _ => None,
507
        }
508
0
    }
509
510
    /// Returns true if this is a std::io::Error
511
    #[inline]
512
    #[cfg(feature = "std")]
513
0
    pub fn is_io(&self) -> bool {
514
0
        matches!(self.kind, ProtoErrorKind::Io(..))
515
0
    }
516
517
    #[cfg(feature = "std")]
518
0
    pub(crate) fn as_dyn(&self) -> &(dyn std::error::Error + 'static) {
519
0
        self
520
0
    }
521
522
    /// A conversion to determine if the response is an error
523
0
    pub fn from_response(response: DnsResponse) -> Result<DnsResponse, Self> {
524
        use ResponseCode::*;
525
0
        debug!("response: {}", *response);
526
527
0
        match response.response_code() {
528
0
                Refused => Err(Self::from(ProtoErrorKind::RequestRefused)),
529
0
                code @ ServFail
530
0
                | code @ FormErr
531
0
                | code @ NotImp
532
0
                | code @ YXDomain
533
0
                | code @ YXRRSet
534
0
                | code @ NXRRSet
535
0
                | code @ NotAuth
536
0
                | code @ NotZone
537
0
                | code @ BADVERS
538
0
                | code @ BADSIG
539
0
                | code @ BADKEY
540
0
                | code @ BADTIME
541
0
                | code @ BADMODE
542
0
                | code @ BADNAME
543
0
                | code @ BADALG
544
0
                | code @ BADTRUNC
545
0
                | code @ BADCOOKIE => Err(Self::from(ProtoErrorKind::ResponseCode(code))),
546
                // Some NXDOMAIN responses contain CNAME referrals, that will not be an error
547
0
                code @ NXDomain |
548
                // No answers are available, CNAME referrals are not failures
549
0
                code @ NoError
550
0
                if !response.contains_answer() && !response.truncated() => {
551
                    // TODO: if authoritative, this is cacheable, store a TTL (currently that requires time, need a "now" here)
552
                    // let valid_until = if response.authoritative() { now + response.negative_ttl() };
553
0
                    let soa = response.soa().as_ref().map(RecordRef::to_owned);
554
0
555
0
                    // Collect any referral nameservers and associated glue records
556
0
                    let mut referral_name_servers = vec![];
557
0
                    for ns in response.authorities().iter().filter(|ns| ns.record_type() == RecordType::NS) {
558
0
                        let glue = response
559
0
                            .additionals()
560
0
                            .iter()
561
0
                            .filter_map(|record| {
562
0
                                if let Some(ns_data) = ns.data().as_ns() {
563
0
                                    if *record.name() == **ns_data &&
564
0
                                       (record.data().as_a().is_some() || record.data().as_aaaa().is_some()) {
565
0
                                           return Some(Record::to_owned(record));
566
0
                                       }
567
0
                                }
568
569
0
                                None
570
0
                            })
571
0
                            .collect::<Vec<Record>>();
572
0
                        referral_name_servers.push(ForwardNSData { ns: Record::to_owned(ns), glue: glue.into() })
573
                    }
574
575
0
                    let option_ns = if !referral_name_servers.is_empty() {
576
0
                        Some(referral_name_servers.into())
577
                    } else {
578
0
                        None
579
                    };
580
581
0
                    let authorities = if !response.authorities().is_empty() {
582
0
                        Some(response.authorities().to_owned().into())
583
                    } else {
584
0
                        None
585
                    };
586
587
0
                    let negative_ttl = response.negative_ttl();
588
0
                    let query = response.into_message().take_queries().drain(..).next().unwrap_or_default();
589
0
590
0
                    let error_kind = ProtoErrorKind::NoRecordsFound(NoRecords {
591
0
                        query: Box::new(query),
592
0
                        soa: soa.map(Box::new),
593
0
                        ns: option_ns,
594
0
                        negative_ttl,
595
0
                        response_code: code,
596
0
                        authorities,
597
0
                    });
598
0
599
0
                    Err(Self::from(error_kind))
600
                }
601
                NXDomain
602
                | NoError
603
0
                | Unknown(_) => Ok(response),
604
            }
605
0
    }
606
607
    /// Compare two errors to see if one contains a server response.
608
0
    pub fn cmp_specificity(&self, other: &Self) -> Ordering {
609
0
        let kind = self.kind();
610
0
        let other = other.kind();
611
0
612
0
        match (kind, other) {
613
            (ProtoErrorKind::NoRecordsFound { .. }, ProtoErrorKind::NoRecordsFound { .. }) => {
614
0
                return Ordering::Equal;
615
            }
616
0
            (ProtoErrorKind::NoRecordsFound { .. }, _) => return Ordering::Greater,
617
0
            (_, ProtoErrorKind::NoRecordsFound { .. }) => return Ordering::Less,
618
0
            _ => (),
619
0
        }
620
0
621
0
        match (kind, other) {
622
            #[cfg(feature = "std")]
623
0
            (ProtoErrorKind::Io { .. }, ProtoErrorKind::Io { .. }) => return Ordering::Equal,
624
            #[cfg(feature = "std")]
625
0
            (ProtoErrorKind::Io { .. }, _) => return Ordering::Greater,
626
            #[cfg(feature = "std")]
627
0
            (_, ProtoErrorKind::Io { .. }) => return Ordering::Less,
628
0
            _ => (),
629
0
        }
630
0
631
0
        match (kind, other) {
632
0
            (ProtoErrorKind::Timeout, ProtoErrorKind::Timeout) => return Ordering::Equal,
633
0
            (ProtoErrorKind::Timeout, _) => return Ordering::Greater,
634
0
            (_, ProtoErrorKind::Timeout) => return Ordering::Less,
635
0
            _ => (),
636
0
        }
637
0
638
0
        Ordering::Equal
639
0
    }
640
641
    /// Whether the query should be retried after this error
642
0
    pub fn should_retry(&self) -> bool {
643
0
        !matches!(
644
0
            self.kind(),
645
            ProtoErrorKind::NoConnections | ProtoErrorKind::NoRecordsFound { .. }
646
        )
647
0
    }
648
649
    /// Whether this error should count as an attempt
650
0
    pub fn attempted(&self) -> bool {
651
0
        !matches!(self.kind(), ProtoErrorKind::Busy)
652
0
    }
653
}
654
655
impl fmt::Display for ProtoError {
656
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
657
0
        cfg_if::cfg_if! {
658
0
            if #[cfg(feature = "backtrace")] {
659
0
                if let Some(backtrace) = &self.backtrack {
660
0
                    fmt::Display::fmt(&self.kind, f)?;
661
0
                    fmt::Debug::fmt(backtrace, f)
662
0
                } else {
663
0
                    fmt::Display::fmt(&self.kind, f)
664
0
                }
665
0
            } else {
666
0
                fmt::Display::fmt(&self.kind, f)
667
0
            }
668
0
        }
669
0
    }
670
}
671
672
impl<E: Into<ProtoErrorKind>> From<E> for ProtoError {
673
10.8k
    fn from(error: E) -> Self {
674
10.8k
        Self {
675
10.8k
            kind: error.into(),
676
10.8k
            #[cfg(feature = "backtrace")]
677
10.8k
            backtrack: trace!(),
678
10.8k
        }
679
10.8k
    }
<hickory_proto::error::ProtoError as core::convert::From<hickory_proto::error::ProtoErrorKind>>::from
Line
Count
Source
673
10.8k
    fn from(error: E) -> Self {
674
10.8k
        Self {
675
10.8k
            kind: error.into(),
676
10.8k
            #[cfg(feature = "backtrace")]
677
10.8k
            backtrack: trace!(),
678
10.8k
        }
679
10.8k
    }
Unexecuted instantiation: <hickory_proto::error::ProtoError as core::convert::From<url::parser::ParseError>>::from
<hickory_proto::error::ProtoError as core::convert::From<alloc::string::FromUtf8Error>>::from
Line
Count
Source
673
23
    fn from(error: E) -> Self {
674
23
        Self {
675
23
            kind: error.into(),
676
23
            #[cfg(feature = "backtrace")]
677
23
            backtrack: trace!(),
678
23
        }
679
23
    }
Unexecuted instantiation: <hickory_proto::error::ProtoError as core::convert::From<aws_lc_rs::error::Unspecified>>::from
Unexecuted instantiation: <hickory_proto::error::ProtoError as core::convert::From<core::num::error::ParseIntError>>::from
Unexecuted instantiation: <hickory_proto::error::ProtoError as core::convert::From<core::str::error::Utf8Error>>::from
Unexecuted instantiation: <hickory_proto::error::ProtoError as core::convert::From<std::io::error::Error>>::from
680
}
681
682
impl From<DecodeError> for ProtoError {
683
3.01k
    fn from(err: DecodeError) -> Self {
684
3.01k
        match err {
685
59
            DecodeError::PointerNotPriorToLabel { idx, ptr } => {
686
59
                ProtoErrorKind::PointerNotPriorToLabel { idx, ptr }
687
            }
688
0
            DecodeError::LabelBytesTooLong(len) => ProtoErrorKind::LabelBytesTooLong(len),
689
94
            DecodeError::UnrecognizedLabelCode(code) => ProtoErrorKind::UnrecognizedLabelCode(code),
690
2
            DecodeError::DomainNameTooLong(len) => ProtoErrorKind::DomainNameTooLong(len),
691
79
            DecodeError::LabelOverlapsWithOther { label, other } => {
692
79
                ProtoErrorKind::LabelOverlapsWithOther { label, other }
693
            }
694
2.78k
            _ => ProtoErrorKind::Msg(err.to_string()),
695
        }
696
3.01k
        .into()
697
3.01k
    }
698
}
699
700
impl From<&'static str> for ProtoError {
701
518
    fn from(msg: &'static str) -> Self {
702
518
        ProtoErrorKind::Message(msg).into()
703
518
    }
704
}
705
706
impl From<String> for ProtoError {
707
2.21k
    fn from(msg: String) -> Self {
708
2.21k
        ProtoErrorKind::Msg(msg).into()
709
2.21k
    }
710
}
711
712
#[cfg(feature = "std")]
713
impl From<io::Error> for ProtoErrorKind {
714
0
    fn from(e: io::Error) -> Self {
715
0
        match e.kind() {
716
0
            io::ErrorKind::TimedOut => Self::Timeout,
717
0
            _ => Self::Io(e.into()),
718
        }
719
0
    }
720
}
721
722
#[cfg(feature = "std")]
723
impl<T> From<sync::PoisonError<T>> for ProtoError {
724
0
    fn from(_e: sync::PoisonError<T>) -> Self {
725
0
        ProtoErrorKind::Poisoned.into()
726
0
    }
727
}
728
729
#[cfg(feature = "std")]
730
impl From<ProtoError> for io::Error {
731
0
    fn from(e: ProtoError) -> Self {
732
0
        match e.kind() {
733
0
            ProtoErrorKind::Timeout => Self::new(io::ErrorKind::TimedOut, e),
734
0
            _ => Self::other(e),
735
        }
736
0
    }
737
}
738
739
impl From<ProtoError> for String {
740
0
    fn from(e: ProtoError) -> Self {
741
0
        e.to_string()
742
0
    }
743
}
744
745
#[cfg(feature = "wasm-bindgen")]
746
impl From<ProtoError> for wasm_bindgen_crate::JsValue {
747
    fn from(e: ProtoError) -> Self {
748
        js_sys::Error::new(&e.to_string()).into()
749
    }
750
}
751
752
impl Clone for ProtoErrorKind {
753
0
    fn clone(&self) -> Self {
754
        use self::ProtoErrorKind::*;
755
0
        match *self {
756
0
            BadQueryCount(count) => BadQueryCount(count),
757
0
            Busy => Busy,
758
0
            Canceled(ref c) => Canceled(*c),
759
0
            CharacterDataTooLong { max, len } => CharacterDataTooLong { max, len },
760
0
            LabelOverlapsWithOther { label, other } => LabelOverlapsWithOther { label, other },
761
0
            DnsKeyProtocolNot3(protocol) => DnsKeyProtocolNot3(protocol),
762
0
            DomainNameTooLong(len) => DomainNameTooLong(len),
763
0
            EdnsNameNotRoot(ref found) => EdnsNameNotRoot(found.clone()),
764
0
            FormError { header, ref error } => FormError {
765
0
                header,
766
0
                error: error.clone(),
767
0
            },
768
0
            IncorrectRDataLengthRead { read, len } => IncorrectRDataLengthRead { read, len },
769
0
            LabelBytesTooLong(len) => LabelBytesTooLong(len),
770
0
            PointerNotPriorToLabel { idx, ptr } => PointerNotPriorToLabel { idx, ptr },
771
0
            MaxBufferSizeExceeded(max) => MaxBufferSizeExceeded(max),
772
0
            MaxRecordLimitExceeded { count, record_type } => {
773
0
                MaxRecordLimitExceeded { count, record_type }
774
            }
775
0
            Message(msg) => Message(msg),
776
0
            Msg(ref msg) => Msg(msg.clone()),
777
0
            NoConnections => NoConnections,
778
0
            NotAllRecordsWritten { count } => NotAllRecordsWritten { count },
779
0
            NoRecordsFound(ref inner) => NoRecordsFound(inner.clone()),
780
0
            RequestRefused => RequestRefused,
781
0
            ResponseCode(code) => ResponseCode(code),
782
            #[cfg(feature = "__dnssec")]
783
            Nsec {
784
0
                ref query,
785
0
                ref response,
786
0
                proof,
787
0
            } => Nsec {
788
0
                query: query.clone(),
789
0
                response: response.clone(),
790
0
                proof,
791
0
            },
792
0
            UnknownAlgorithmTypeValue(value) => UnknownAlgorithmTypeValue(value),
793
0
            UnknownDigestTypeValue(value) => UnknownDigestTypeValue(value),
794
0
            UnknownDnsClassStr(ref value) => UnknownDnsClassStr(value.clone()),
795
0
            UnknownDnsClassValue(value) => UnknownDnsClassValue(value),
796
0
            UnknownRecordTypeStr(ref value) => UnknownRecordTypeStr(value.clone()),
797
0
            UnknownRecordTypeValue(value) => UnknownRecordTypeValue(value),
798
0
            UnrecognizedLabelCode(value) => UnrecognizedLabelCode(value),
799
0
            UnrecognizedNsec3Flags(flags) => UnrecognizedNsec3Flags(flags),
800
0
            UnrecognizedCsyncFlags(flags) => UnrecognizedCsyncFlags(flags),
801
            #[cfg(feature = "std")]
802
0
            Io(ref e) => Io(e.clone()),
803
0
            Poisoned => Poisoned,
804
            #[cfg(feature = "__dnssec")]
805
0
            Ring(ref _e) => Ring(Unspecified),
806
0
            Timeout => Timeout,
807
0
            Timer => Timer,
808
0
            UrlParsing(ref e) => UrlParsing(*e),
809
0
            Utf8(ref e) => Utf8(*e),
810
0
            FromUtf8(ref e) => FromUtf8(e.clone()),
811
0
            ParseInt(ref e) => ParseInt(e.clone()),
812
            #[cfg(feature = "__quic")]
813
            QuinnConnect(ref e) => QuinnConnect(e.clone()),
814
            #[cfg(feature = "__quic")]
815
            QuinnConnection(ref e) => QuinnConnection(e.clone()),
816
            #[cfg(feature = "__quic")]
817
            QuinnWriteError(ref e) => QuinnWriteError(e.clone()),
818
            #[cfg(feature = "__quic")]
819
            QuicMessageIdNot0(val) => QuicMessageIdNot0(val),
820
            #[cfg(feature = "__quic")]
821
            QuinnReadError(ref e) => QuinnReadError(e.clone()),
822
            #[cfg(feature = "__quic")]
823
            QuinnStreamError(ref e) => QuinnStreamError(e.clone()),
824
            #[cfg(feature = "__quic")]
825
            QuinnConfigError(ref e) => QuinnConfigError(e.clone()),
826
            #[cfg(feature = "__quic")]
827
            QuinnTlsConfigError(ref e) => QuinnTlsConfigError(e.clone()),
828
            #[cfg(feature = "__quic")]
829
            QuinnUnknownStreamError => QuinnUnknownStreamError,
830
            #[cfg(feature = "__tls")]
831
            RustlsError(ref e) => RustlsError(e.clone()),
832
0
            QueryCaseMismatch => QueryCaseMismatch,
833
        }
834
0
    }
835
}