nonymous/
server.rs

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/// failed to start emitting response
13#[derive(Debug, displaydoc::Display)]
14#[prefix_enum_doc_attributes]
15pub enum ResponseError {
16    /// failed to create sink: {0}
17    Sink(SinkError),
18
19    /// failed to emit message: {0}
20    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
35/// Starts building a new response (QR=1) for the given query (QR=0).
36///
37/// Returns the query view and response builder, or writes an error response to the given `buffer`
38/// and returns `None`, or returns a [`MessageError`] if either of those fail.
39///
40/// The algorithm is as follows:
41/// 1. If the query header is malformed, return an empty response with RCODE = FormErr
42/// 2. Start a new response with the same ID + OPCODE + RD, defaulting to RCODE = NotImp
43/// 3. If the query is well-formed and its EDNS version (if any) supported, return Ok(Some())
44/// 4. If the query has any EDNS OPT RR, add EDNS OPT RR to the response
45/// 5. If the query EDNS version is unimplemented, finish the response with RCODE = BADVERS
46/// 6. If the query is otherwise malformed, finish the response with RCODE = FormErr
47/// 7. Return Ok(None)
48pub 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    // limit to 512 iff udp, until query indicates otherwise
58    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            // RFC 6891 § 6.1.3 “All responses MUST be limited in format to the VERSION level of the
89            // request, but the VERSION of each response SHOULD be the highest implementation level
90            // of the responder.
91            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    // compute limit as min(capacity limit, query udp limit)
107    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        // empty FormErr response if header malformed
131        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        // matching NotImp response by default
138        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        // matching BADVERS response if EDNS version unimplemented
152        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        // matching FormErr response if otherwise malformed
165        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}