hickory_proto/op/
dns_request.rs1use core::ops::{Deref, DerefMut};
11#[cfg(feature = "std")]
12use core::time::Duration;
13
14#[cfg(feature = "std")]
15use super::{DEFAULT_RETRY_FLOOR, Edns};
16use super::{Message, Query, edns::DEFAULT_MAX_PAYLOAD_LEN};
17
18#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20#[non_exhaustive]
21pub struct DnsRequestOptions {
22 pub use_edns: bool,
25 pub edns_payload_len: u16,
35 pub edns_set_dnssec_ok: bool,
37 pub max_request_depth: usize,
39 pub recursion_desired: bool,
41 #[cfg(feature = "std")]
43 pub case_randomization: bool,
44 #[cfg(feature = "std")]
48 pub retry_interval: Duration,
49}
50
51impl Default for DnsRequestOptions {
52 fn default() -> Self {
53 Self {
54 max_request_depth: 26,
55 use_edns: true,
56 edns_payload_len: DEFAULT_MAX_PAYLOAD_LEN,
57 edns_set_dnssec_ok: false,
58 recursion_desired: true,
59 #[cfg(feature = "std")]
60 case_randomization: false,
61 #[cfg(feature = "std")]
63 retry_interval: DEFAULT_RETRY_FLOOR,
64 }
65 }
66}
67
68#[derive(Clone, PartialEq, Eq)]
72pub struct DnsRequest {
73 message: Message,
74 options: DnsRequestOptions,
75 original_query: Option<Query>,
77}
78
79impl DnsRequest {
80 #[cfg(feature = "std")]
82 pub fn from_query(mut query: Query, options: DnsRequestOptions) -> Self {
83 let mut message = Message::query();
84 let mut original_query = None;
85
86 if options.case_randomization {
87 original_query = Some(query.clone());
88 query.name.randomize_label_case();
89 }
90
91 message.queries.push(query);
92 message.metadata.recursion_desired = options.recursion_desired;
93
94 if options.use_edns {
95 message
96 .edns
97 .get_or_insert_with(Edns::new)
98 .set_max_payload(options.edns_payload_len)
99 .set_dnssec_ok(options.edns_set_dnssec_ok);
100 }
101
102 Self::new(message, options).with_original_query(original_query)
103 }
104
105 pub fn new(message: Message, options: DnsRequestOptions) -> Self {
107 Self {
108 message,
109 options,
110 original_query: None,
111 }
112 }
113
114 pub fn with_original_query(mut self, original_query: Option<Query>) -> Self {
116 self.original_query = original_query;
117 self
118 }
119
120 pub fn options(&self) -> &DnsRequestOptions {
122 &self.options
123 }
124
125 pub fn options_mut(&mut self) -> &mut DnsRequestOptions {
127 &mut self.options
128 }
129
130 pub fn into_parts(self) -> (Message, DnsRequestOptions) {
132 (self.message, self.options)
133 }
134
135 pub fn original_query(&self) -> Option<&Query> {
137 self.original_query.as_ref()
138 }
139}
140
141impl Deref for DnsRequest {
142 type Target = Message;
143 fn deref(&self) -> &Self::Target {
144 &self.message
145 }
146}
147
148impl DerefMut for DnsRequest {
149 fn deref_mut(&mut self) -> &mut Self::Target {
150 &mut self.message
151 }
152}
153
154impl From<Message> for DnsRequest {
155 fn from(message: Message) -> Self {
156 Self::new(message, DnsRequestOptions::default())
157 }
158}
159
160#[cfg(all(test, feature = "std"))]
161mod tests {
162 use super::*;
163 use crate::rr::{Name, RecordType};
164
165 #[test]
166 fn from_query_default_includes_edns() {
167 let query = Query::query(Name::from_ascii("example.com.").unwrap(), RecordType::A);
168 let request = DnsRequest::from_query(query, DnsRequestOptions::default());
169 assert!(request.edns.is_some());
170 assert_eq!(request.max_payload(), DEFAULT_MAX_PAYLOAD_LEN);
171 }
172
173 #[test]
174 fn from_query_edns_disabled_no_opt() {
175 let query = Query::query(Name::from_ascii("example.com.").unwrap(), RecordType::A);
176 let request = DnsRequest::from_query(
177 query,
178 DnsRequestOptions {
179 use_edns: false,
180 ..DnsRequestOptions::default()
181 },
182 );
183
184 assert!(request.edns.is_none());
185 assert_eq!(request.max_payload(), 512);
186 }
187}