Skip to main content

hickory_server/server/
request_handler.rs

1// Copyright 2015-2021 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//! Request Handler for incoming requests
9
10use std::net::SocketAddr;
11
12use bytes::Bytes;
13
14#[cfg(feature = "testing")]
15use crate::proto::serialize::binary::{BinEncodable, BinEncoder};
16use crate::{
17    net::{runtime::Time, xfer::Protocol},
18    proto::{
19        ProtoError,
20        op::{Header, HeaderCounts, LowerQuery, MessageType, Metadata, ResponseCode},
21        serialize::binary::{BinDecodable, BinDecoder},
22    },
23    server::ResponseHandler,
24    zone_handler::{LookupError, MessageRequest},
25};
26
27/// An incoming request to the DNS catalog
28#[derive(Debug)]
29pub struct Request {
30    /// Message with the associated query or update data
31    pub(crate) message: MessageRequest,
32    pub(super) raw: Bytes,
33    /// Source address of the Client
34    pub(super) src: SocketAddr,
35    /// Protocol of the request
36    pub(super) protocol: Protocol,
37}
38
39impl Request {
40    /// Construct a new Request from the raw bytes, source address, and protocol
41    pub fn from_bytes(
42        raw: Vec<u8>,
43        src: SocketAddr,
44        protocol: Protocol,
45    ) -> Result<Self, ProtoError> {
46        let mut decoder = BinDecoder::new(&raw);
47        let header = Header::read(&mut decoder)?;
48        Ok(Self {
49            message: MessageRequest::read(&mut decoder, header)?,
50            raw: Bytes::from(raw),
51            src,
52            protocol,
53        })
54    }
55
56    /// Construct a new Request from the encoding of a MessageRequest, source address, and protocol
57    #[cfg(feature = "testing")]
58    pub fn from_message(
59        message: MessageRequest,
60        src: SocketAddr,
61        protocol: Protocol,
62    ) -> Result<Self, ProtoError> {
63        let mut encoded = Vec::new();
64        let mut encoder = BinEncoder::new(&mut encoded);
65        message.emit(&mut encoder)?;
66
67        Ok(Self {
68            message,
69            raw: Bytes::from(encoded),
70            src,
71            protocol,
72        })
73    }
74
75    /// Return just the header and request information from the Request Message
76    ///
77    /// Returns an error if there is not exactly one query
78    pub fn request_info(&self) -> Result<RequestInfo<'_>, LookupError> {
79        Ok(RequestInfo {
80            src: self.src,
81            protocol: self.protocol,
82            metadata: &self.message.metadata,
83            query: self.message.queries.try_as_query()?,
84        })
85    }
86
87    /// The IP address from which the request originated.
88    pub fn src(&self) -> SocketAddr {
89        self.src
90    }
91
92    /// The protocol that was used for the request
93    pub fn protocol(&self) -> Protocol {
94        self.protocol
95    }
96
97    /// The raw bytes of the request
98    pub fn as_slice(&self) -> &[u8] {
99        &self.raw
100    }
101}
102
103impl std::ops::Deref for Request {
104    type Target = MessageRequest;
105
106    fn deref(&self) -> &Self::Target {
107        &self.message
108    }
109}
110
111// TODO: add ProtocolInfo that would have TLS details or other additional things...
112/// A narrow view of the Request, specifically a verified single query for the request
113#[non_exhaustive]
114#[derive(Clone)]
115pub struct RequestInfo<'a> {
116    /// The source address from which the request came
117    pub src: SocketAddr,
118    /// The protocol used for the request
119    pub protocol: Protocol,
120    /// The header from the original request
121    pub metadata: &'a Metadata,
122    /// The query from the request
123    pub query: &'a LowerQuery,
124}
125
126impl<'a> RequestInfo<'a> {
127    /// Construct a new RequestInfo
128    ///
129    /// # Arguments
130    ///
131    /// * `src` - The source address from which the request came
132    /// * `protocol` - The protocol used for the request
133    /// * `header` - The header from the original request
134    /// * `query` - The query from the request, LowerQuery is intended to reduce complexity for lookups in zone handlers
135    pub fn new(
136        src: SocketAddr,
137        protocol: Protocol,
138        metadata: &'a Metadata,
139        query: &'a LowerQuery,
140    ) -> Self {
141        Self {
142            src,
143            protocol,
144            metadata,
145            query,
146        }
147    }
148}
149
150/// Information about the response sent for a request
151#[derive(Clone, Copy, Debug)]
152#[repr(transparent)]
153pub struct ResponseInfo(Header);
154
155impl ResponseInfo {
156    pub(crate) fn serve_failed(request: &Request) -> Self {
157        let mut metadata = Metadata::new(
158            request.metadata.id,
159            MessageType::Response,
160            request.metadata.op_code,
161        );
162        metadata.response_code = ResponseCode::ServFail;
163        Self(Header {
164            metadata,
165            counts: HeaderCounts::default(),
166        })
167    }
168
169    /// Header counts for the response
170    pub fn counts(&self) -> HeaderCounts {
171        self.0.counts
172    }
173}
174
175impl From<Header> for ResponseInfo {
176    fn from(value: Header) -> Self {
177        Self(value)
178    }
179}
180
181impl std::ops::Deref for ResponseInfo {
182    type Target = Metadata;
183
184    fn deref(&self) -> &Self::Target {
185        &self.0.metadata
186    }
187}
188
189/// Trait for handling incoming requests, and providing a message response.
190#[async_trait::async_trait]
191pub trait RequestHandler: Send + Sync + Unpin + 'static {
192    /// Determines what needs to happen given the type of request, i.e. Query or Update.
193    ///
194    /// # Arguments
195    ///
196    /// * `request` - the requested action to perform.
197    /// * `response_handle` - handle to which a return message should be sent
198    async fn handle_request<R: ResponseHandler, T: Time>(
199        &self,
200        request: &Request,
201        response_handle: R,
202    ) -> ResponseInfo;
203}
204
205#[cfg(test)]
206mod tests {
207    use super::*;
208    use crate::proto::op::{Metadata, OpCode, Query};
209
210    #[test]
211    fn request_info_clone() {
212        let query = Query::new();
213        let header = Metadata::new(10, MessageType::Query, OpCode::Query);
214        let lower_query = query.into();
215        let origin = RequestInfo::new(
216            "127.0.0.1:3000".parse().unwrap(),
217            Protocol::Udp,
218            &header,
219            &lower_query,
220        );
221        let cloned = origin.clone();
222        assert_eq!(origin.metadata, cloned.metadata);
223    }
224}