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 hickory_proto::ProtoError;
13
14use crate::{
15 authority::MessageRequest,
16 proto::{
17 op::{Header, LowerQuery, ResponseCode},
18 xfer::Protocol,
19 },
20 server::ResponseHandler,
21};
22
23/// An incoming request to the DNS catalog
24#[derive(Debug)]
25pub struct Request {
26 /// Message with the associated query or update data
27 message: MessageRequest,
28 /// Source address of the Client
29 src: SocketAddr,
30 /// Protocol of the request
31 protocol: Protocol,
32}
33
34impl Request {
35 /// Build a new requests with the inbound message, source address, and protocol.
36 ///
37 /// This will return an error on bad verification.
38 pub fn new(message: MessageRequest, src: SocketAddr, protocol: Protocol) -> Self {
39 Self {
40 message,
41 src,
42 protocol,
43 }
44 }
45
46 /// Return just the header and request information from the Request Message
47 ///
48 /// Returns an error if there is not exactly one query
49 pub fn request_info(&self) -> Result<RequestInfo<'_>, ProtoError> {
50 Ok(RequestInfo {
51 src: self.src,
52 protocol: self.protocol,
53 header: self.message.header(),
54 query: self.message.raw_queries().try_as_query()?,
55 })
56 }
57
58 /// The IP address from which the request originated.
59 pub fn src(&self) -> SocketAddr {
60 self.src
61 }
62
63 /// The protocol that was used for the request
64 pub fn protocol(&self) -> Protocol {
65 self.protocol
66 }
67}
68
69impl std::ops::Deref for Request {
70 type Target = MessageRequest;
71
72 fn deref(&self) -> &Self::Target {
73 &self.message
74 }
75}
76
77// TODO: add ProtocolInfo that would have TLS details or other additional things...
78/// A narrow view of the Request, specifically a verified single query for the request
79#[non_exhaustive]
80#[derive(Clone)]
81pub struct RequestInfo<'a> {
82 /// The source address from which the request came
83 pub src: SocketAddr,
84 /// The protocol used for the request
85 pub protocol: Protocol,
86 /// The header from the original request
87 pub header: &'a Header,
88 /// The query from the request
89 pub query: &'a LowerQuery,
90}
91
92impl<'a> RequestInfo<'a> {
93 /// Construct a new RequestInfo
94 ///
95 /// # Arguments
96 ///
97 /// * `src` - The source address from which the request came
98 /// * `protocol` - The protocol used for the request
99 /// * `header` - The header from the original request
100 /// * `query` - The query from the request, LowerQuery is intended to reduce complexity for lookups in authorities
101 pub fn new(
102 src: SocketAddr,
103 protocol: Protocol,
104 header: &'a Header,
105 query: &'a LowerQuery,
106 ) -> Self {
107 Self {
108 src,
109 protocol,
110 header,
111 query,
112 }
113 }
114}
115
116/// Information about the response sent for a request
117#[derive(Clone, Copy, Debug)]
118#[repr(transparent)]
119pub struct ResponseInfo(Header);
120
121impl ResponseInfo {
122 pub(crate) fn serve_failed() -> Self {
123 let mut header = Header::new();
124 header.set_response_code(ResponseCode::ServFail);
125 header.into()
126 }
127}
128
129impl From<Header> for ResponseInfo {
130 fn from(header: Header) -> Self {
131 Self(header)
132 }
133}
134
135impl std::ops::Deref for ResponseInfo {
136 type Target = Header;
137
138 fn deref(&self) -> &Self::Target {
139 &self.0
140 }
141}
142
143/// Trait for handling incoming requests, and providing a message response.
144#[async_trait::async_trait]
145pub trait RequestHandler: Send + Sync + Unpin + 'static {
146 /// Determines what needs to happen given the type of request, i.e. Query or Update.
147 ///
148 /// # Arguments
149 ///
150 /// * `request` - the requested action to perform.
151 /// * `response_handle` - handle to which a return message should be sent
152 async fn handle_request<R: ResponseHandler>(
153 &self,
154 request: &Request,
155 response_handle: R,
156 ) -> ResponseInfo;
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162 use crate::proto::op::{Header, Query};
163
164 #[test]
165 fn request_info_clone() {
166 let query: Query = Query::new();
167 let header = Header::new();
168 let lower_query = query.into();
169 let origin = RequestInfo::new(
170 "127.0.0.1:3000".parse().unwrap(),
171 Protocol::Udp,
172 &header,
173 &lower_query,
174 );
175 let cloned = origin.clone();
176 assert_eq!(origin.header, cloned.header);
177 }
178}