1use crate::{
2 core::Rcode,
3 emit::{
4 message::{MessageBuilder, MessageError, QdSection},
5 Buffer, NewBuilder, Sink, SinkError,
6 },
7 view::{Header, Message, View},
8 MAX_SUPPORTED_EDNS_VERSION,
9};
10
11error!(ResponseError, Sink, Message);
12#[derive(Debug, displaydoc::Display)]
14#[prefix_enum_doc_attributes]
15pub enum ResponseError {
16 Sink(SinkError),
18
19 Message(MessageError),
21}
22
23impl From<SinkError> for ResponseError {
24 fn from(inner: SinkError) -> Self {
25 Self::Sink(inner)
26 }
27}
28
29impl From<MessageError> for ResponseError {
30 fn from(inner: MessageError) -> Self {
31 Self::Message(inner)
32 }
33}
34
35pub fn response<'q, 'r>(
49 query: &'q [u8],
50 buffer: &'r mut dyn Buffer,
51 udp: bool,
52) -> Result<Option<(Message<'q>, MessageBuilder<'r, Sink<'r>, QdSection>)>, ResponseError> {
53 use crate::view::ExtensionError::UnimplementedVersion;
54 use crate::view::MessageError;
55 use crate::view::MessageErrorKind as Kind;
56
57 let limit = if udp {
59 Some(512)
60 } else {
61 Sink::capacity_limit(buffer)?
62 };
63 let new = |buffer, limit| -> Result<_, ResponseError> {
64 Ok(MessageBuilder::new(Sink::with_limit(buffer, limit)?)?.qr(true))
65 };
66
67 let header = match Header::view(query, ..) {
68 Err(_) => {
69 new(buffer, limit)?.rcode(Rcode::FormErr).finish()?.finish();
70 return Ok(None);
71 }
72 Ok((x, _)) => x,
73 };
74 let new = |buffer, limit| -> Result<_, ResponseError> {
75 Ok(new(buffer, limit)?
76 .id(header.id())
77 .opcode(header.opcode())
78 .rd(header.rd())
79 .rcode(Rcode::NotImp))
80 };
81
82 let query = match Message::view(query, ..) {
83 Err(MessageError(edns_version, inner)) => {
84 let result = new(buffer, limit)?.rcode(match inner {
85 Kind::Extension(UnimplementedVersion) => Rcode::BADVERS,
86 _ => Rcode::FormErr,
87 });
88 if edns_version.is_some() {
92 result
93 .extension()?
94 .version(MAX_SUPPORTED_EDNS_VERSION)
95 .finish()?
96 .finish()?
97 .finish();
98 } else {
99 result.finish()?.finish();
100 }
101 return Ok(None);
102 }
103 Ok((x, _)) => x,
104 };
105
106 let limit = Sink::response_limit(buffer, udp, &query)?;
108
109 Ok(Some((query, new(buffer, limit)?)))
110}
111
112#[cfg(test)]
113mod test {
114 use arrayvec::ArrayVec;
115
116 use crate::{
117 core::Rcode,
118 emit::Buffer,
119 view::{Message, View},
120 };
121
122 declare_any_error!(AnyError);
123
124 fn a12() -> ArrayVec<u8, 4096> {
125 ArrayVec::new()
126 }
127
128 #[test]
129 fn response() -> Result<(), AnyError> {
130 let mut buffer = a12();
132 assert!(super::response(b"", &mut buffer, false)?.is_none());
133 let (result, _) = Message::view(&buffer, ..)?;
134 assert_eq!(result.header().qr(), true);
135 assert_eq!(result.rcode(), Rcode::FormErr);
136
137 let mut buffer = a12();
139 let (_, response) = super::response(
140 b"\x13\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
141 &mut buffer,
142 false,
143 )?
144 .unwrap();
145 response.finish()?.finish();
146 let (result, _) = Message::view(&buffer, ..)?;
147 assert_eq!(result.header().id(), 0x1313);
148 assert_eq!(result.header().qr(), true);
149 assert_eq!(result.rcode(), Rcode::NotImp);
150
151 let mut buffer = a12();
153 assert!(super::response(
154 b"\x13\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\0\x00\x29\x10\x00\x00\x01\x00\x00\x00\x00",
155 &mut buffer,
156 false,
157 )?.is_none());
158 let (result, _) = Message::view(&buffer, ..)?;
159 assert_eq!(result.header().id(), 0x1313);
160 assert_eq!(result.header().qr(), true);
161 assert_eq!(result.rcode(), Rcode::BADVERS);
162 assert_eq!(result.opt().map(|x| x.version()), Some(0));
163
164 let mut buffer = a12();
166 assert!(super::response(
167 b"\x13\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\0\x00\x29\x10\x00\x00\x00\x00\x00\x00\x00",
168 &mut buffer,
169 false,
170 )?.is_none());
171 let (result, _) = Message::view(&buffer, ..)?;
172 assert_eq!(result.header().id(), 0x1313);
173 assert_eq!(result.header().qr(), true);
174 assert_eq!(result.rcode(), Rcode::FormErr);
175 assert_eq!(result.opt().map(|x| x.version()), Some(0));
176
177 Ok(())
178 }
179
180 #[test]
181 #[rustfmt::skip]
182 fn response_limit() -> Result<(), AnyError> {
183 response_limit_test(Some(4096), false, &mut a12(), b"\x13\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")?;
184 response_limit_test(Some(512), true, &mut a12(), b"\x13\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")?;
185 response_limit_test(Some(512), true, &mut a12(), b"\x13\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\0\x00\x29\x01\xFF\x00\x00\x00\x00\x00\x00")?;
186 response_limit_test(Some(512), true, &mut a12(), b"\x13\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\0\x00\x29\x02\x00\x00\x00\x00\x00\x00\x00")?;
187 response_limit_test(Some(513), true, &mut a12(), b"\x13\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\0\x00\x29\x02\x01\x00\x00\x00\x00\x00\x00")?;
188 response_limit_test(Some(4095), true, &mut a12(), b"\x13\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\0\x00\x29\x0F\xFF\x00\x00\x00\x00\x00\x00")?;
189 response_limit_test(Some(4096), true, &mut a12(), b"\x13\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\0\x00\x29\x10\x00\x00\x00\x00\x00\x00\x00")?;
190 response_limit_test(Some(4096), true, &mut a12(), b"\x13\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\0\x00\x29\x10\x01\x00\x00\x00\x00\x00\x00")?;
191
192 Ok(())
193 }
194
195 #[cfg(feature = "alloc")]
196 #[test]
197 #[rustfmt::skip]
198 fn response_limit_alloc() -> Result<(), AnyError> {
199 response_limit_test(None, false, &mut alloc::vec![], b"\x13\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")?;
200 response_limit_test(Some(512), true, &mut alloc::vec![], b"\x13\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")?;
201 response_limit_test(Some(512), true, &mut alloc::vec![], b"\x13\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\0\x00\x29\x01\xFF\x00\x00\x00\x00\x00\x00")?;
202 response_limit_test(Some(512), true, &mut alloc::vec![], b"\x13\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\0\x00\x29\x02\x00\x00\x00\x00\x00\x00\x00")?;
203 response_limit_test(Some(513), true, &mut alloc::vec![], b"\x13\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\0\x00\x29\x02\x01\x00\x00\x00\x00\x00\x00")?;
204 response_limit_test(Some(4095), true, &mut alloc::vec![], b"\x13\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\0\x00\x29\x0F\xFF\x00\x00\x00\x00\x00\x00")?;
205 response_limit_test(Some(4096), true, &mut alloc::vec![], b"\x13\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\0\x00\x29\x10\x00\x00\x00\x00\x00\x00\x00")?;
206 response_limit_test(Some(4097), true, &mut alloc::vec![], b"\x13\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\0\x00\x29\x10\x01\x00\x00\x00\x00\x00\x00")?;
207
208 Ok(())
209 }
210
211 fn response_limit_test(
212 expected: Option<u16>,
213 udp: bool,
214 buffer: &mut dyn Buffer,
215 query: &[u8],
216 ) -> Result<(), AnyError> {
217 let (_, response) = super::response(query, buffer, udp)?.unwrap();
218 assert_eq!(response.finish()?.limit().map(u16::from), expected);
219
220 Ok(())
221 }
222}
223
224#[cfg(all(test, feature = "bench"))]
225mod bench {
226 extern crate test;
227
228 use test::Bencher;
229
230 #[bench]
231 fn response(bencher: &mut Bencher) {
232 let source = include_bytes!("../samples/daria.daz.cat.query.dns");
233 bencher.iter(|| -> Result<usize, ()> {
234 let mut buffer = alloc::vec![];
235 let (query, response) = super::response(source, &mut buffer, true)
236 .map_err(|_| ())?
237 .expect("guaranteed by input");
238 let question = query.qd().next().expect("guaranteed by input");
239 response
240 .into_an()
241 .record_with_name(&question.qname(), question.qtype(), question.qclass())
242 .map_err(|_| ())?
243 .push_rdata(&[192, 0, 2, 13])
244 .map_err(|_| ())?
245 .finish()
246 .map_err(|_| ())?
247 .finish()
248 .map_err(|_| ())?
249 .finish();
250 Ok(buffer.len())
251 });
252 }
253}