xref: /aosp_15_r20/tools/netsim/rust/http-proxy/src/dns.rs (revision cf78ab8cffb8fc9207af348f23af247fb04370a6)
1*cf78ab8cSAndroid Build Coastguard Worker // Copyright 2024 Google LLC
2*cf78ab8cSAndroid Build Coastguard Worker //
3*cf78ab8cSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*cf78ab8cSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*cf78ab8cSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*cf78ab8cSAndroid Build Coastguard Worker //
7*cf78ab8cSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*cf78ab8cSAndroid Build Coastguard Worker //
9*cf78ab8cSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*cf78ab8cSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*cf78ab8cSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*cf78ab8cSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*cf78ab8cSAndroid Build Coastguard Worker // limitations under the License.
14*cf78ab8cSAndroid Build Coastguard Worker 
15*cf78ab8cSAndroid Build Coastguard Worker /// This module parses DNS response records and extracts fully
16*cf78ab8cSAndroid Build Coastguard Worker /// qualified domain names (FQDNs) along with their corresponding
17*cf78ab8cSAndroid Build Coastguard Worker /// IP Addresses (IpAddr).
18*cf78ab8cSAndroid Build Coastguard Worker ///
19*cf78ab8cSAndroid Build Coastguard Worker /// **Note:** This is not a general-purpose DNS response parser. It is
20*cf78ab8cSAndroid Build Coastguard Worker /// designed to handle specific record types and response formats.
21*cf78ab8cSAndroid Build Coastguard Worker use std::convert::TryFrom;
22*cf78ab8cSAndroid Build Coastguard Worker use std::fmt;
23*cf78ab8cSAndroid Build Coastguard Worker use std::io::{Cursor, Read, Seek, SeekFrom};
24*cf78ab8cSAndroid Build Coastguard Worker use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
25*cf78ab8cSAndroid Build Coastguard Worker use std::str;
26*cf78ab8cSAndroid Build Coastguard Worker #[allow(unused_imports)]
27*cf78ab8cSAndroid Build Coastguard Worker use std::str::FromStr;
28*cf78ab8cSAndroid Build Coastguard Worker 
29*cf78ab8cSAndroid Build Coastguard Worker // REGION CURSOR
30*cf78ab8cSAndroid Build Coastguard Worker 
31*cf78ab8cSAndroid Build Coastguard Worker /// Extension trait providing convenient methods for reading primitive
32*cf78ab8cSAndroid Build Coastguard Worker /// data types used by DNS messages from a `Cursor<&[u8]>`.
33*cf78ab8cSAndroid Build Coastguard Worker 
34*cf78ab8cSAndroid Build Coastguard Worker trait CursorExt: Read + Seek + Clone {
read_u8(&mut self) -> std::io::Result<u8>35*cf78ab8cSAndroid Build Coastguard Worker     fn read_u8(&mut self) -> std::io::Result<u8>;
read_u16(&mut self) -> std::io::Result<u16>36*cf78ab8cSAndroid Build Coastguard Worker     fn read_u16(&mut self) -> std::io::Result<u16>;
read_u32(&mut self) -> std::io::Result<u32>37*cf78ab8cSAndroid Build Coastguard Worker     fn read_u32(&mut self) -> std::io::Result<u32>;
read_ipv4addr(&mut self) -> std::io::Result<Ipv4Addr>38*cf78ab8cSAndroid Build Coastguard Worker     fn read_ipv4addr(&mut self) -> std::io::Result<Ipv4Addr>;
read_ipv6addr(&mut self) -> std::io::Result<Ipv6Addr>39*cf78ab8cSAndroid Build Coastguard Worker     fn read_ipv6addr(&mut self) -> std::io::Result<Ipv6Addr>;
get_ref(&self) -> &[u8]40*cf78ab8cSAndroid Build Coastguard Worker     fn get_ref(&self) -> &[u8];
position(&self) -> u6441*cf78ab8cSAndroid Build Coastguard Worker     fn position(&self) -> u64;
set_position(&mut self, pos: u64)42*cf78ab8cSAndroid Build Coastguard Worker     fn set_position(&mut self, pos: u64);
43*cf78ab8cSAndroid Build Coastguard Worker }
44*cf78ab8cSAndroid Build Coastguard Worker 
45*cf78ab8cSAndroid Build Coastguard Worker impl CursorExt for Cursor<&[u8]> {
read_u8(&mut self) -> std::io::Result<u8>46*cf78ab8cSAndroid Build Coastguard Worker     fn read_u8(&mut self) -> std::io::Result<u8> {
47*cf78ab8cSAndroid Build Coastguard Worker         let mut buf = [0; 1];
48*cf78ab8cSAndroid Build Coastguard Worker         self.read_exact(&mut buf)?;
49*cf78ab8cSAndroid Build Coastguard Worker         Ok(buf[0])
50*cf78ab8cSAndroid Build Coastguard Worker     }
51*cf78ab8cSAndroid Build Coastguard Worker 
read_u16(&mut self) -> std::io::Result<u16>52*cf78ab8cSAndroid Build Coastguard Worker     fn read_u16(&mut self) -> std::io::Result<u16> {
53*cf78ab8cSAndroid Build Coastguard Worker         let mut buf = [0; 2];
54*cf78ab8cSAndroid Build Coastguard Worker         self.read_exact(&mut buf)?;
55*cf78ab8cSAndroid Build Coastguard Worker         Ok(u16::from_be_bytes(buf))
56*cf78ab8cSAndroid Build Coastguard Worker     }
57*cf78ab8cSAndroid Build Coastguard Worker 
read_u32(&mut self) -> std::io::Result<u32>58*cf78ab8cSAndroid Build Coastguard Worker     fn read_u32(&mut self) -> std::io::Result<u32> {
59*cf78ab8cSAndroid Build Coastguard Worker         let mut buf = [0; 4];
60*cf78ab8cSAndroid Build Coastguard Worker         self.read_exact(&mut buf)?;
61*cf78ab8cSAndroid Build Coastguard Worker         Ok(u32::from_be_bytes(buf))
62*cf78ab8cSAndroid Build Coastguard Worker     }
63*cf78ab8cSAndroid Build Coastguard Worker 
read_ipv4addr(&mut self) -> std::io::Result<Ipv4Addr>64*cf78ab8cSAndroid Build Coastguard Worker     fn read_ipv4addr(&mut self) -> std::io::Result<Ipv4Addr> {
65*cf78ab8cSAndroid Build Coastguard Worker         let mut buf = [0; 4];
66*cf78ab8cSAndroid Build Coastguard Worker         self.read_exact(&mut buf)?;
67*cf78ab8cSAndroid Build Coastguard Worker         Ok(Ipv4Addr::from(buf))
68*cf78ab8cSAndroid Build Coastguard Worker     }
69*cf78ab8cSAndroid Build Coastguard Worker 
read_ipv6addr(&mut self) -> std::io::Result<Ipv6Addr>70*cf78ab8cSAndroid Build Coastguard Worker     fn read_ipv6addr(&mut self) -> std::io::Result<Ipv6Addr> {
71*cf78ab8cSAndroid Build Coastguard Worker         let mut buf = [0; 16];
72*cf78ab8cSAndroid Build Coastguard Worker         self.read_exact(&mut buf)?;
73*cf78ab8cSAndroid Build Coastguard Worker         Ok(Ipv6Addr::from(buf))
74*cf78ab8cSAndroid Build Coastguard Worker     }
75*cf78ab8cSAndroid Build Coastguard Worker 
get_ref(&self) -> &[u8]76*cf78ab8cSAndroid Build Coastguard Worker     fn get_ref(&self) -> &[u8] {
77*cf78ab8cSAndroid Build Coastguard Worker         self.get_ref() // Call the original get_ref method
78*cf78ab8cSAndroid Build Coastguard Worker     }
position(&self) -> u6479*cf78ab8cSAndroid Build Coastguard Worker     fn position(&self) -> u64 {
80*cf78ab8cSAndroid Build Coastguard Worker         self.position()
81*cf78ab8cSAndroid Build Coastguard Worker     }
set_position(&mut self, pos: u64)82*cf78ab8cSAndroid Build Coastguard Worker     fn set_position(&mut self, pos: u64) {
83*cf78ab8cSAndroid Build Coastguard Worker         self.set_position(pos)
84*cf78ab8cSAndroid Build Coastguard Worker     }
85*cf78ab8cSAndroid Build Coastguard Worker }
86*cf78ab8cSAndroid Build Coastguard Worker 
87*cf78ab8cSAndroid Build Coastguard Worker // END REGION CURSOR
88*cf78ab8cSAndroid Build Coastguard Worker 
89*cf78ab8cSAndroid Build Coastguard Worker // REGION MESSAGE
90*cf78ab8cSAndroid Build Coastguard Worker 
91*cf78ab8cSAndroid Build Coastguard Worker /// '''
92*cf78ab8cSAndroid Build Coastguard Worker ///  +---------------------+
93*cf78ab8cSAndroid Build Coastguard Worker ///  |        Header       |
94*cf78ab8cSAndroid Build Coastguard Worker ///  +---------------------+
95*cf78ab8cSAndroid Build Coastguard Worker ///  |       Question      | the question for the name server
96*cf78ab8cSAndroid Build Coastguard Worker ///  +---------------------+
97*cf78ab8cSAndroid Build Coastguard Worker ///  |        Answer       | RRs answering the question
98*cf78ab8cSAndroid Build Coastguard Worker ///  +---------------------+
99*cf78ab8cSAndroid Build Coastguard Worker ///  |      Authority      | RRs pointing toward an authority
100*cf78ab8cSAndroid Build Coastguard Worker ///  +---------------------+
101*cf78ab8cSAndroid Build Coastguard Worker ///  |      Additional     | RRs holding additional information
102*cf78ab8cSAndroid Build Coastguard Worker ///  +---------------------+
103*cf78ab8cSAndroid Build Coastguard Worker /// '''
104*cf78ab8cSAndroid Build Coastguard Worker 
105*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug)]
106*cf78ab8cSAndroid Build Coastguard Worker struct Message {
107*cf78ab8cSAndroid Build Coastguard Worker     #[allow(dead_code)]
108*cf78ab8cSAndroid Build Coastguard Worker     header: Header,
109*cf78ab8cSAndroid Build Coastguard Worker     #[allow(dead_code)]
110*cf78ab8cSAndroid Build Coastguard Worker     questions: Vec<Question>,
111*cf78ab8cSAndroid Build Coastguard Worker     answers: Vec<ResourceRecord>,
112*cf78ab8cSAndroid Build Coastguard Worker     // Other types not needed
113*cf78ab8cSAndroid Build Coastguard Worker     // Authority
114*cf78ab8cSAndroid Build Coastguard Worker     // Additional
115*cf78ab8cSAndroid Build Coastguard Worker }
116*cf78ab8cSAndroid Build Coastguard Worker 
117*cf78ab8cSAndroid Build Coastguard Worker impl Message {
parse(cursor: &mut impl CursorExt) -> Result<Message>118*cf78ab8cSAndroid Build Coastguard Worker     fn parse(cursor: &mut impl CursorExt) -> Result<Message> {
119*cf78ab8cSAndroid Build Coastguard Worker         let header = Header::parse(cursor)?;
120*cf78ab8cSAndroid Build Coastguard Worker 
121*cf78ab8cSAndroid Build Coastguard Worker         // Reject DNS messages that are not responses
122*cf78ab8cSAndroid Build Coastguard Worker         if !header.response {
123*cf78ab8cSAndroid Build Coastguard Worker             return Err(DnsError::ResponseExpected);
124*cf78ab8cSAndroid Build Coastguard Worker         }
125*cf78ab8cSAndroid Build Coastguard Worker         if header.opcode != Opcode::StandardQuery {
126*cf78ab8cSAndroid Build Coastguard Worker             return Err(DnsError::StandardQueryExpected);
127*cf78ab8cSAndroid Build Coastguard Worker         }
128*cf78ab8cSAndroid Build Coastguard Worker         if header.response_code != ResponseCode::NoError {
129*cf78ab8cSAndroid Build Coastguard Worker             return Err(DnsError::ResponseCodeExpected);
130*cf78ab8cSAndroid Build Coastguard Worker         }
131*cf78ab8cSAndroid Build Coastguard Worker 
132*cf78ab8cSAndroid Build Coastguard Worker         if header.answer_count == 0 {
133*cf78ab8cSAndroid Build Coastguard Worker             return Err(DnsError::AnswerExpected);
134*cf78ab8cSAndroid Build Coastguard Worker         }
135*cf78ab8cSAndroid Build Coastguard Worker 
136*cf78ab8cSAndroid Build Coastguard Worker         let mut questions = Vec::with_capacity(header.question_count);
137*cf78ab8cSAndroid Build Coastguard Worker         for _i in 0..header.question_count {
138*cf78ab8cSAndroid Build Coastguard Worker             let question = Question::split_once(cursor)?;
139*cf78ab8cSAndroid Build Coastguard Worker             questions.push(question);
140*cf78ab8cSAndroid Build Coastguard Worker         }
141*cf78ab8cSAndroid Build Coastguard Worker         let mut answers = Vec::with_capacity(header.answer_count);
142*cf78ab8cSAndroid Build Coastguard Worker         for _i in 0..header.answer_count {
143*cf78ab8cSAndroid Build Coastguard Worker             let answer = ResourceRecord::split_once(cursor)?;
144*cf78ab8cSAndroid Build Coastguard Worker             answers.push(answer);
145*cf78ab8cSAndroid Build Coastguard Worker         }
146*cf78ab8cSAndroid Build Coastguard Worker         Ok(Message { header, questions, answers })
147*cf78ab8cSAndroid Build Coastguard Worker     }
148*cf78ab8cSAndroid Build Coastguard Worker }
149*cf78ab8cSAndroid Build Coastguard Worker 
parse_answers(bytes: &[u8]) -> Result<Vec<(IpAddr, String)>>150*cf78ab8cSAndroid Build Coastguard Worker pub fn parse_answers(bytes: &[u8]) -> Result<Vec<(IpAddr, String)>> {
151*cf78ab8cSAndroid Build Coastguard Worker     let mut cursor = Cursor::new(bytes);
152*cf78ab8cSAndroid Build Coastguard Worker     let msg = Message::parse(&mut cursor)?;
153*cf78ab8cSAndroid Build Coastguard Worker     let mut responses = Vec::with_capacity(msg.answers.len());
154*cf78ab8cSAndroid Build Coastguard Worker     for answer in msg.answers {
155*cf78ab8cSAndroid Build Coastguard Worker         responses.push((answer.resource_data.into(), answer.name));
156*cf78ab8cSAndroid Build Coastguard Worker     }
157*cf78ab8cSAndroid Build Coastguard Worker     Ok(responses)
158*cf78ab8cSAndroid Build Coastguard Worker }
159*cf78ab8cSAndroid Build Coastguard Worker 
160*cf78ab8cSAndroid Build Coastguard Worker // END REGION MESSAGE
161*cf78ab8cSAndroid Build Coastguard Worker 
162*cf78ab8cSAndroid Build Coastguard Worker // REGION HEADER
163*cf78ab8cSAndroid Build Coastguard Worker 
164*cf78ab8cSAndroid Build Coastguard Worker /// Represents parsed header of the packet.
165*cf78ab8cSAndroid Build Coastguard Worker /// The header contains the following fields:
166*cf78ab8cSAndroid Build Coastguard Worker /// '''
167*cf78ab8cSAndroid Build Coastguard Worker ///                                  1  1  1  1  1  1
168*cf78ab8cSAndroid Build Coastguard Worker ///    0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
169*cf78ab8cSAndroid Build Coastguard Worker ///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
170*cf78ab8cSAndroid Build Coastguard Worker ///  |                      ID                       |
171*cf78ab8cSAndroid Build Coastguard Worker ///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
172*cf78ab8cSAndroid Build Coastguard Worker ///  |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
173*cf78ab8cSAndroid Build Coastguard Worker ///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
174*cf78ab8cSAndroid Build Coastguard Worker ///  |                    QDCOUNT                    |
175*cf78ab8cSAndroid Build Coastguard Worker ///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
176*cf78ab8cSAndroid Build Coastguard Worker ///  |                    ANCOUNT                    |
177*cf78ab8cSAndroid Build Coastguard Worker ///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
178*cf78ab8cSAndroid Build Coastguard Worker ///  |                    NSCOUNT                    |
179*cf78ab8cSAndroid Build Coastguard Worker ///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
180*cf78ab8cSAndroid Build Coastguard Worker ///  |                    ARCOUNT                    |
181*cf78ab8cSAndroid Build Coastguard Worker ///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
182*cf78ab8cSAndroid Build Coastguard Worker /// '''
183*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, PartialEq, Eq, Clone, Copy)]
184*cf78ab8cSAndroid Build Coastguard Worker struct Header {
185*cf78ab8cSAndroid Build Coastguard Worker     /// A 16 bit identifier assigned by the program that
186*cf78ab8cSAndroid Build Coastguard Worker     /// generates any kind of query.  This identifier is copied
187*cf78ab8cSAndroid Build Coastguard Worker     /// the corresponding reply and can be used by the requester
188*cf78ab8cSAndroid Build Coastguard Worker     /// to match up replies to outstanding queries.
189*cf78ab8cSAndroid Build Coastguard Worker     id: u16,
190*cf78ab8cSAndroid Build Coastguard Worker     /// A one bit field that specifies whether this message is a
191*cf78ab8cSAndroid Build Coastguard Worker     /// query (0), or a response (1).
192*cf78ab8cSAndroid Build Coastguard Worker     response: bool,
193*cf78ab8cSAndroid Build Coastguard Worker     /// A four bit field that specifies kind of query in this
194*cf78ab8cSAndroid Build Coastguard Worker     /// message.  This value is set by the originator of a query
195*cf78ab8cSAndroid Build Coastguard Worker     /// and copied into the response.
196*cf78ab8cSAndroid Build Coastguard Worker     opcode: Opcode,
197*cf78ab8cSAndroid Build Coastguard Worker     response_code: ResponseCode,
198*cf78ab8cSAndroid Build Coastguard Worker     question_count: usize,
199*cf78ab8cSAndroid Build Coastguard Worker     answer_count: usize,
200*cf78ab8cSAndroid Build Coastguard Worker     nameserver_count: usize,
201*cf78ab8cSAndroid Build Coastguard Worker     additional_count: usize,
202*cf78ab8cSAndroid Build Coastguard Worker }
203*cf78ab8cSAndroid Build Coastguard Worker 
204*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, PartialEq, Eq, Clone, Copy)]
205*cf78ab8cSAndroid Build Coastguard Worker enum Opcode {
206*cf78ab8cSAndroid Build Coastguard Worker     /// Normal query
207*cf78ab8cSAndroid Build Coastguard Worker     StandardQuery = 0,
208*cf78ab8cSAndroid Build Coastguard Worker     /// Inverse query (query a name by IP)
209*cf78ab8cSAndroid Build Coastguard Worker     InverseQuery = 1,
210*cf78ab8cSAndroid Build Coastguard Worker     /// Server status request
211*cf78ab8cSAndroid Build Coastguard Worker     ServerStatusRequest = 2,
212*cf78ab8cSAndroid Build Coastguard Worker }
213*cf78ab8cSAndroid Build Coastguard Worker 
214*cf78ab8cSAndroid Build Coastguard Worker /// The RCODE value according to RFC 1035
215*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, PartialEq, Eq, Clone, Copy)]
216*cf78ab8cSAndroid Build Coastguard Worker enum ResponseCode {
217*cf78ab8cSAndroid Build Coastguard Worker     NoError,
218*cf78ab8cSAndroid Build Coastguard Worker     FormatError,
219*cf78ab8cSAndroid Build Coastguard Worker     ServerFailure,
220*cf78ab8cSAndroid Build Coastguard Worker     NameError,
221*cf78ab8cSAndroid Build Coastguard Worker     NotImplemented,
222*cf78ab8cSAndroid Build Coastguard Worker     Refused,
223*cf78ab8cSAndroid Build Coastguard Worker }
224*cf78ab8cSAndroid Build Coastguard Worker 
225*cf78ab8cSAndroid Build Coastguard Worker impl TryFrom<u16> for ResponseCode {
226*cf78ab8cSAndroid Build Coastguard Worker     type Error = DnsError;
227*cf78ab8cSAndroid Build Coastguard Worker 
try_from(value: u16) -> Result<Self>228*cf78ab8cSAndroid Build Coastguard Worker     fn try_from(value: u16) -> Result<Self> {
229*cf78ab8cSAndroid Build Coastguard Worker         match value {
230*cf78ab8cSAndroid Build Coastguard Worker             0 => Ok(ResponseCode::NoError),
231*cf78ab8cSAndroid Build Coastguard Worker             1 => Ok(ResponseCode::FormatError),
232*cf78ab8cSAndroid Build Coastguard Worker             2 => Ok(ResponseCode::ServerFailure),
233*cf78ab8cSAndroid Build Coastguard Worker             3 => Ok(ResponseCode::NameError),
234*cf78ab8cSAndroid Build Coastguard Worker             4 => Ok(ResponseCode::NotImplemented),
235*cf78ab8cSAndroid Build Coastguard Worker             5 => Ok(ResponseCode::Refused),
236*cf78ab8cSAndroid Build Coastguard Worker             _ => Err(DnsError::InvalidResponseCode(value)),
237*cf78ab8cSAndroid Build Coastguard Worker         }
238*cf78ab8cSAndroid Build Coastguard Worker     }
239*cf78ab8cSAndroid Build Coastguard Worker }
240*cf78ab8cSAndroid Build Coastguard Worker 
241*cf78ab8cSAndroid Build Coastguard Worker impl TryFrom<u16> for Opcode {
242*cf78ab8cSAndroid Build Coastguard Worker     type Error = DnsError;
243*cf78ab8cSAndroid Build Coastguard Worker 
try_from(value: u16) -> Result<Self>244*cf78ab8cSAndroid Build Coastguard Worker     fn try_from(value: u16) -> Result<Self> {
245*cf78ab8cSAndroid Build Coastguard Worker         match value {
246*cf78ab8cSAndroid Build Coastguard Worker             0 => Ok(Opcode::StandardQuery),
247*cf78ab8cSAndroid Build Coastguard Worker             1 => Ok(Opcode::InverseQuery),
248*cf78ab8cSAndroid Build Coastguard Worker             2 => Ok(Opcode::ServerStatusRequest),
249*cf78ab8cSAndroid Build Coastguard Worker             _ => Err(DnsError::InvalidOpcode(value)),
250*cf78ab8cSAndroid Build Coastguard Worker         }
251*cf78ab8cSAndroid Build Coastguard Worker     }
252*cf78ab8cSAndroid Build Coastguard Worker }
253*cf78ab8cSAndroid Build Coastguard Worker 
254*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq)]
255*cf78ab8cSAndroid Build Coastguard Worker struct Flag(u16);
256*cf78ab8cSAndroid Build Coastguard Worker 
257*cf78ab8cSAndroid Build Coastguard Worker impl Flag {
258*cf78ab8cSAndroid Build Coastguard Worker     const RESPONSE: u16 = 0x8000;
259*cf78ab8cSAndroid Build Coastguard Worker     const OPCODE_MASK: u16 = 0x7800;
260*cf78ab8cSAndroid Build Coastguard Worker     const RESERVED_MASK: u16 = 0x0004;
261*cf78ab8cSAndroid Build Coastguard Worker     const RESPONSE_CODE_MASK: u16 = 0x000F;
262*cf78ab8cSAndroid Build Coastguard Worker 
new(value: u16) -> Self263*cf78ab8cSAndroid Build Coastguard Worker     fn new(value: u16) -> Self {
264*cf78ab8cSAndroid Build Coastguard Worker         Self(value)
265*cf78ab8cSAndroid Build Coastguard Worker     }
266*cf78ab8cSAndroid Build Coastguard Worker 
is_set(&self, mask: u16) -> bool267*cf78ab8cSAndroid Build Coastguard Worker     fn is_set(&self, mask: u16) -> bool {
268*cf78ab8cSAndroid Build Coastguard Worker         (self.0 & mask) == mask
269*cf78ab8cSAndroid Build Coastguard Worker     }
270*cf78ab8cSAndroid Build Coastguard Worker 
get(&self, mask: u16) -> u16271*cf78ab8cSAndroid Build Coastguard Worker     fn get(&self, mask: u16) -> u16 {
272*cf78ab8cSAndroid Build Coastguard Worker         (self.0 & mask) >> mask.trailing_zeros()
273*cf78ab8cSAndroid Build Coastguard Worker     }
274*cf78ab8cSAndroid Build Coastguard Worker }
275*cf78ab8cSAndroid Build Coastguard Worker 
276*cf78ab8cSAndroid Build Coastguard Worker impl Header {
277*cf78ab8cSAndroid Build Coastguard Worker     /// Parse the header into a header structure
parse(cursor: &mut impl CursorExt) -> Result<Header>278*cf78ab8cSAndroid Build Coastguard Worker     fn parse(cursor: &mut impl CursorExt) -> Result<Header> {
279*cf78ab8cSAndroid Build Coastguard Worker         let id = cursor.read_u16()?;
280*cf78ab8cSAndroid Build Coastguard Worker         let f = cursor.read_u16()?;
281*cf78ab8cSAndroid Build Coastguard Worker         let question_count = cursor.read_u16()? as usize;
282*cf78ab8cSAndroid Build Coastguard Worker         let answer_count = cursor.read_u16()? as usize;
283*cf78ab8cSAndroid Build Coastguard Worker         let nameserver_count = cursor.read_u16()? as usize;
284*cf78ab8cSAndroid Build Coastguard Worker         let additional_count = cursor.read_u16()? as usize;
285*cf78ab8cSAndroid Build Coastguard Worker         let flags = Flag::new(f);
286*cf78ab8cSAndroid Build Coastguard Worker         if flags.get(Flag::RESERVED_MASK) != 0 {
287*cf78ab8cSAndroid Build Coastguard Worker             return Err(DnsError::ReservedBitsAreNonZero);
288*cf78ab8cSAndroid Build Coastguard Worker         }
289*cf78ab8cSAndroid Build Coastguard Worker         let header = Header {
290*cf78ab8cSAndroid Build Coastguard Worker             id,
291*cf78ab8cSAndroid Build Coastguard Worker             response: flags.is_set(Flag::RESPONSE),
292*cf78ab8cSAndroid Build Coastguard Worker             opcode: Opcode::try_from(flags.get(Flag::OPCODE_MASK))?,
293*cf78ab8cSAndroid Build Coastguard Worker             response_code: ResponseCode::try_from(flags.get(Flag::RESPONSE_CODE_MASK))?,
294*cf78ab8cSAndroid Build Coastguard Worker             question_count,
295*cf78ab8cSAndroid Build Coastguard Worker             answer_count,
296*cf78ab8cSAndroid Build Coastguard Worker             nameserver_count,
297*cf78ab8cSAndroid Build Coastguard Worker             additional_count,
298*cf78ab8cSAndroid Build Coastguard Worker         };
299*cf78ab8cSAndroid Build Coastguard Worker         Ok(header)
300*cf78ab8cSAndroid Build Coastguard Worker     }
301*cf78ab8cSAndroid Build Coastguard Worker }
302*cf78ab8cSAndroid Build Coastguard Worker 
303*cf78ab8cSAndroid Build Coastguard Worker // END REGION HEADER
304*cf78ab8cSAndroid Build Coastguard Worker 
305*cf78ab8cSAndroid Build Coastguard Worker // REGION QUESTION
306*cf78ab8cSAndroid Build Coastguard Worker 
307*cf78ab8cSAndroid Build Coastguard Worker /// 4.1.2. Question section format
308*cf78ab8cSAndroid Build Coastguard Worker ///
309*cf78ab8cSAndroid Build Coastguard Worker /// The question section is used to carry the "question" in most queries,
310*cf78ab8cSAndroid Build Coastguard Worker /// i.e., the parameters that define what is being asked.  The section
311*cf78ab8cSAndroid Build Coastguard Worker /// contains QDCOUNT (usually 1) entries, each of the following format:
312*cf78ab8cSAndroid Build Coastguard Worker /// '''
313*cf78ab8cSAndroid Build Coastguard Worker ///                               1  1  1  1  1  1
314*cf78ab8cSAndroid Build Coastguard Worker /// 0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
315*cf78ab8cSAndroid Build Coastguard Worker /// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
316*cf78ab8cSAndroid Build Coastguard Worker /// |                                               |
317*cf78ab8cSAndroid Build Coastguard Worker /// /                     QNAME                     /
318*cf78ab8cSAndroid Build Coastguard Worker /// /                                               /
319*cf78ab8cSAndroid Build Coastguard Worker /// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
320*cf78ab8cSAndroid Build Coastguard Worker /// |                     QTYPE                     |
321*cf78ab8cSAndroid Build Coastguard Worker /// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
322*cf78ab8cSAndroid Build Coastguard Worker /// |                     QCLASS                    |
323*cf78ab8cSAndroid Build Coastguard Worker /// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
324*cf78ab8cSAndroid Build Coastguard Worker /// '''
325*cf78ab8cSAndroid Build Coastguard Worker 
326*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug)]
327*cf78ab8cSAndroid Build Coastguard Worker struct Question {
328*cf78ab8cSAndroid Build Coastguard Worker     #[allow(dead_code)]
329*cf78ab8cSAndroid Build Coastguard Worker     name: String,
330*cf78ab8cSAndroid Build Coastguard Worker     #[allow(dead_code)]
331*cf78ab8cSAndroid Build Coastguard Worker     qtype: u16,
332*cf78ab8cSAndroid Build Coastguard Worker     #[allow(dead_code)]
333*cf78ab8cSAndroid Build Coastguard Worker     qclass: u16,
334*cf78ab8cSAndroid Build Coastguard Worker }
335*cf78ab8cSAndroid Build Coastguard Worker 
336*cf78ab8cSAndroid Build Coastguard Worker impl Question {
split_once(cursor: &mut impl CursorExt) -> Result<Question>337*cf78ab8cSAndroid Build Coastguard Worker     fn split_once(cursor: &mut impl CursorExt) -> Result<Question> {
338*cf78ab8cSAndroid Build Coastguard Worker         let name = Name::to_string(cursor)?;
339*cf78ab8cSAndroid Build Coastguard Worker         let qtype = cursor.read_u16()?;
340*cf78ab8cSAndroid Build Coastguard Worker         let qclass = cursor.read_u16()?;
341*cf78ab8cSAndroid Build Coastguard Worker         Ok(Question { name, qtype, qclass })
342*cf78ab8cSAndroid Build Coastguard Worker     }
343*cf78ab8cSAndroid Build Coastguard Worker }
344*cf78ab8cSAndroid Build Coastguard Worker 
345*cf78ab8cSAndroid Build Coastguard Worker // END REGION QUESTION
346*cf78ab8cSAndroid Build Coastguard Worker 
347*cf78ab8cSAndroid Build Coastguard Worker // REGION RESOURCE RECORD
348*cf78ab8cSAndroid Build Coastguard Worker 
349*cf78ab8cSAndroid Build Coastguard Worker /// All RRs have the same top level format shown below:
350*cf78ab8cSAndroid Build Coastguard Worker ///
351*cf78ab8cSAndroid Build Coastguard Worker /// '''
352*cf78ab8cSAndroid Build Coastguard Worker ///                                1  1  1  1  1  1
353*cf78ab8cSAndroid Build Coastguard Worker ///  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
354*cf78ab8cSAndroid Build Coastguard Worker ///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
355*cf78ab8cSAndroid Build Coastguard Worker ///  |                                               |
356*cf78ab8cSAndroid Build Coastguard Worker ///  /                                               /
357*cf78ab8cSAndroid Build Coastguard Worker ///  /                      NAME                     /
358*cf78ab8cSAndroid Build Coastguard Worker ///  |                                               |
359*cf78ab8cSAndroid Build Coastguard Worker ///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
360*cf78ab8cSAndroid Build Coastguard Worker ///  |                      TYPE                     |
361*cf78ab8cSAndroid Build Coastguard Worker ///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
362*cf78ab8cSAndroid Build Coastguard Worker ///  |                     CLASS                     |
363*cf78ab8cSAndroid Build Coastguard Worker ///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
364*cf78ab8cSAndroid Build Coastguard Worker ///  |                      TTL                      |
365*cf78ab8cSAndroid Build Coastguard Worker ///  |                                               |
366*cf78ab8cSAndroid Build Coastguard Worker ///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
367*cf78ab8cSAndroid Build Coastguard Worker ///  |                   RDLENGTH                    |
368*cf78ab8cSAndroid Build Coastguard Worker ///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
369*cf78ab8cSAndroid Build Coastguard Worker ///  /                     RDATA                     /
370*cf78ab8cSAndroid Build Coastguard Worker ///  /                                               /
371*cf78ab8cSAndroid Build Coastguard Worker ///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
372*cf78ab8cSAndroid Build Coastguard Worker /// '''
373*cf78ab8cSAndroid Build Coastguard Worker 
374*cf78ab8cSAndroid Build Coastguard Worker // DNS resource record classes.
375*cf78ab8cSAndroid Build Coastguard Worker //
376*cf78ab8cSAndroid Build Coastguard Worker // The only one we care about is Internet
377*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug)]
378*cf78ab8cSAndroid Build Coastguard Worker enum ResourceClass {
379*cf78ab8cSAndroid Build Coastguard Worker     Internet = 1,
380*cf78ab8cSAndroid Build Coastguard Worker }
381*cf78ab8cSAndroid Build Coastguard Worker 
382*cf78ab8cSAndroid Build Coastguard Worker // Type fields in resource records.
383*cf78ab8cSAndroid Build Coastguard Worker //
384*cf78ab8cSAndroid Build Coastguard Worker // The only ones we care about are A and AAAA
385*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug)]
386*cf78ab8cSAndroid Build Coastguard Worker enum ResourceType {
387*cf78ab8cSAndroid Build Coastguard Worker     // IPv4 address.
388*cf78ab8cSAndroid Build Coastguard Worker     A = 1,
389*cf78ab8cSAndroid Build Coastguard Worker     // IPv6 address, see RFC 3596.
390*cf78ab8cSAndroid Build Coastguard Worker     Aaaa = 28,
391*cf78ab8cSAndroid Build Coastguard Worker }
392*cf78ab8cSAndroid Build Coastguard Worker 
393*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug)]
394*cf78ab8cSAndroid Build Coastguard Worker struct ResourceRecord {
395*cf78ab8cSAndroid Build Coastguard Worker     name: String,
396*cf78ab8cSAndroid Build Coastguard Worker     #[allow(dead_code)]
397*cf78ab8cSAndroid Build Coastguard Worker     resource_type: ResourceType,
398*cf78ab8cSAndroid Build Coastguard Worker     #[allow(dead_code)]
399*cf78ab8cSAndroid Build Coastguard Worker     resource_class: ResourceClass,
400*cf78ab8cSAndroid Build Coastguard Worker     #[allow(dead_code)]
401*cf78ab8cSAndroid Build Coastguard Worker     ttl: u32,
402*cf78ab8cSAndroid Build Coastguard Worker     resource_data: ResourceData,
403*cf78ab8cSAndroid Build Coastguard Worker }
404*cf78ab8cSAndroid Build Coastguard Worker 
405*cf78ab8cSAndroid Build Coastguard Worker impl ResourceRecord {
split_once(cursor: &mut impl CursorExt) -> Result<ResourceRecord>406*cf78ab8cSAndroid Build Coastguard Worker     fn split_once(cursor: &mut impl CursorExt) -> Result<ResourceRecord> {
407*cf78ab8cSAndroid Build Coastguard Worker         let name = Name::to_string(cursor)?;
408*cf78ab8cSAndroid Build Coastguard Worker         let rtype = cursor.read_u16()?;
409*cf78ab8cSAndroid Build Coastguard Worker         let resource_type = match rtype {
410*cf78ab8cSAndroid Build Coastguard Worker             x if x == ResourceType::A as u16 => ResourceType::A,
411*cf78ab8cSAndroid Build Coastguard Worker             x if x == ResourceType::Aaaa as u16 => ResourceType::Aaaa,
412*cf78ab8cSAndroid Build Coastguard Worker             _ => return Err(DnsError::InvalidResourceType),
413*cf78ab8cSAndroid Build Coastguard Worker         };
414*cf78ab8cSAndroid Build Coastguard Worker         let rclass = cursor.read_u16()?;
415*cf78ab8cSAndroid Build Coastguard Worker         let resource_class = match rclass {
416*cf78ab8cSAndroid Build Coastguard Worker             x if x == ResourceClass::Internet as u16 => ResourceClass::Internet,
417*cf78ab8cSAndroid Build Coastguard Worker             _ => return Err(DnsError::InvalidResourceClass),
418*cf78ab8cSAndroid Build Coastguard Worker         };
419*cf78ab8cSAndroid Build Coastguard Worker         let ttl = cursor.read_u32()?;
420*cf78ab8cSAndroid Build Coastguard Worker         let _ = cursor.read_u16()?;
421*cf78ab8cSAndroid Build Coastguard Worker         let resource_data = ResourceData::split_once(cursor, &resource_type)?;
422*cf78ab8cSAndroid Build Coastguard Worker         Ok(ResourceRecord { name, resource_type, resource_class, ttl, resource_data })
423*cf78ab8cSAndroid Build Coastguard Worker     }
424*cf78ab8cSAndroid Build Coastguard Worker }
425*cf78ab8cSAndroid Build Coastguard Worker 
426*cf78ab8cSAndroid Build Coastguard Worker // Only interested in IpAddr resource data
427*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, PartialEq)]
428*cf78ab8cSAndroid Build Coastguard Worker struct ResourceData(IpAddr);
429*cf78ab8cSAndroid Build Coastguard Worker 
430*cf78ab8cSAndroid Build Coastguard Worker impl From<ResourceData> for IpAddr {
from(resource_data: ResourceData) -> Self431*cf78ab8cSAndroid Build Coastguard Worker     fn from(resource_data: ResourceData) -> Self {
432*cf78ab8cSAndroid Build Coastguard Worker         resource_data.0
433*cf78ab8cSAndroid Build Coastguard Worker     }
434*cf78ab8cSAndroid Build Coastguard Worker }
435*cf78ab8cSAndroid Build Coastguard Worker 
436*cf78ab8cSAndroid Build Coastguard Worker impl ResourceData {
split_once( cursor: &mut impl CursorExt, resource_type: &ResourceType, ) -> Result<ResourceData>437*cf78ab8cSAndroid Build Coastguard Worker     fn split_once(
438*cf78ab8cSAndroid Build Coastguard Worker         cursor: &mut impl CursorExt,
439*cf78ab8cSAndroid Build Coastguard Worker         resource_type: &ResourceType,
440*cf78ab8cSAndroid Build Coastguard Worker     ) -> Result<ResourceData> {
441*cf78ab8cSAndroid Build Coastguard Worker         match resource_type {
442*cf78ab8cSAndroid Build Coastguard Worker             ResourceType::A => Ok(ResourceData(cursor.read_ipv4addr()?.into())),
443*cf78ab8cSAndroid Build Coastguard Worker             ResourceType::Aaaa => Ok(ResourceData(cursor.read_ipv6addr()?.into())),
444*cf78ab8cSAndroid Build Coastguard Worker         }
445*cf78ab8cSAndroid Build Coastguard Worker     }
446*cf78ab8cSAndroid Build Coastguard Worker }
447*cf78ab8cSAndroid Build Coastguard Worker 
448*cf78ab8cSAndroid Build Coastguard Worker // END REGION RESOURCE RECORD
449*cf78ab8cSAndroid Build Coastguard Worker 
450*cf78ab8cSAndroid Build Coastguard Worker // REGION LABEL
451*cf78ab8cSAndroid Build Coastguard Worker 
452*cf78ab8cSAndroid Build Coastguard Worker type Result<T> = core::result::Result<T, DnsError>;
453*cf78ab8cSAndroid Build Coastguard Worker 
454*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug)]
455*cf78ab8cSAndroid Build Coastguard Worker pub enum DnsError {
456*cf78ab8cSAndroid Build Coastguard Worker     ResponseExpected,
457*cf78ab8cSAndroid Build Coastguard Worker     StandardQueryExpected,
458*cf78ab8cSAndroid Build Coastguard Worker     ResponseCodeExpected,
459*cf78ab8cSAndroid Build Coastguard Worker     AnswerExpected,
460*cf78ab8cSAndroid Build Coastguard Worker     PointerLoop,
461*cf78ab8cSAndroid Build Coastguard Worker     InvalidLength,
462*cf78ab8cSAndroid Build Coastguard Worker     Utf8Error(str::Utf8Error),
463*cf78ab8cSAndroid Build Coastguard Worker     InvalidResourceType,
464*cf78ab8cSAndroid Build Coastguard Worker     InvalidResourceClass,
465*cf78ab8cSAndroid Build Coastguard Worker     AddrParseError(std::net::AddrParseError),
466*cf78ab8cSAndroid Build Coastguard Worker     InvalidOpcode(u16),
467*cf78ab8cSAndroid Build Coastguard Worker     InvalidResponseCode(u16),
468*cf78ab8cSAndroid Build Coastguard Worker     ReservedBitsAreNonZero,
469*cf78ab8cSAndroid Build Coastguard Worker     IoError(std::io::Error),
470*cf78ab8cSAndroid Build Coastguard Worker }
471*cf78ab8cSAndroid Build Coastguard Worker 
472*cf78ab8cSAndroid Build Coastguard Worker impl std::error::Error for DnsError {}
473*cf78ab8cSAndroid Build Coastguard Worker 
474*cf78ab8cSAndroid Build Coastguard Worker impl fmt::Display for DnsError {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result475*cf78ab8cSAndroid Build Coastguard Worker     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
476*cf78ab8cSAndroid Build Coastguard Worker         write!(fmt, "{self:?}")
477*cf78ab8cSAndroid Build Coastguard Worker     }
478*cf78ab8cSAndroid Build Coastguard Worker }
479*cf78ab8cSAndroid Build Coastguard Worker 
480*cf78ab8cSAndroid Build Coastguard Worker impl From<std::io::Error> for DnsError {
from(err: std::io::Error) -> Self481*cf78ab8cSAndroid Build Coastguard Worker     fn from(err: std::io::Error) -> Self {
482*cf78ab8cSAndroid Build Coastguard Worker         DnsError::IoError(err)
483*cf78ab8cSAndroid Build Coastguard Worker     }
484*cf78ab8cSAndroid Build Coastguard Worker }
485*cf78ab8cSAndroid Build Coastguard Worker impl From<str::Utf8Error> for DnsError {
from(err: str::Utf8Error) -> Self486*cf78ab8cSAndroid Build Coastguard Worker     fn from(err: str::Utf8Error) -> Self {
487*cf78ab8cSAndroid Build Coastguard Worker         DnsError::Utf8Error(err)
488*cf78ab8cSAndroid Build Coastguard Worker     }
489*cf78ab8cSAndroid Build Coastguard Worker }
490*cf78ab8cSAndroid Build Coastguard Worker 
491*cf78ab8cSAndroid Build Coastguard Worker impl From<std::net::AddrParseError> for DnsError {
from(err: std::net::AddrParseError) -> Self492*cf78ab8cSAndroid Build Coastguard Worker     fn from(err: std::net::AddrParseError) -> Self {
493*cf78ab8cSAndroid Build Coastguard Worker         DnsError::AddrParseError(err)
494*cf78ab8cSAndroid Build Coastguard Worker     }
495*cf78ab8cSAndroid Build Coastguard Worker }
496*cf78ab8cSAndroid Build Coastguard Worker 
497*cf78ab8cSAndroid Build Coastguard Worker // REGION NAME
498*cf78ab8cSAndroid Build Coastguard Worker 
499*cf78ab8cSAndroid Build Coastguard Worker /// RFC 1035 4.1.4. Message compression
500*cf78ab8cSAndroid Build Coastguard Worker ///
501*cf78ab8cSAndroid Build Coastguard Worker /// In order to reduce the size of messages, the domain system
502*cf78ab8cSAndroid Build Coastguard Worker /// utilizes a compression scheme which eliminates the repetition of
503*cf78ab8cSAndroid Build Coastguard Worker /// domain names in a message.  In this scheme, an entire domain name
504*cf78ab8cSAndroid Build Coastguard Worker /// or a list of labels at the end of a domain name is replaced with a
505*cf78ab8cSAndroid Build Coastguard Worker /// pointer to a prior occurrence of the same name.
506*cf78ab8cSAndroid Build Coastguard Worker ///
507*cf78ab8cSAndroid Build Coastguard Worker /// The pointer takes the form of a two octet sequence:
508*cf78ab8cSAndroid Build Coastguard Worker ///
509*cf78ab8cSAndroid Build Coastguard Worker /// '''
510*cf78ab8cSAndroid Build Coastguard Worker ///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
511*cf78ab8cSAndroid Build Coastguard Worker ///  | 1  1|                OFFSET                   |
512*cf78ab8cSAndroid Build Coastguard Worker ///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
513*cf78ab8cSAndroid Build Coastguard Worker /// '''
514*cf78ab8cSAndroid Build Coastguard Worker 
515*cf78ab8cSAndroid Build Coastguard Worker enum NamePart {
516*cf78ab8cSAndroid Build Coastguard Worker     Label(String),
517*cf78ab8cSAndroid Build Coastguard Worker     Pointer(u64),
518*cf78ab8cSAndroid Build Coastguard Worker     Root,
519*cf78ab8cSAndroid Build Coastguard Worker }
520*cf78ab8cSAndroid Build Coastguard Worker 
521*cf78ab8cSAndroid Build Coastguard Worker const PTR_MASK: u8 = 0b11000000;
522*cf78ab8cSAndroid Build Coastguard Worker 
523*cf78ab8cSAndroid Build Coastguard Worker impl NamePart {
524*cf78ab8cSAndroid Build Coastguard Worker     /// Domain name labels have a maximum length of 63 octets.
525*cf78ab8cSAndroid Build Coastguard Worker     const MAX: u8 = 63;
526*cf78ab8cSAndroid Build Coastguard Worker 
527*cf78ab8cSAndroid Build Coastguard Worker     #[allow(dead_code)]
split_once(cursor: &mut impl CursorExt) -> Result<NamePart>528*cf78ab8cSAndroid Build Coastguard Worker     fn split_once(cursor: &mut impl CursorExt) -> Result<NamePart> {
529*cf78ab8cSAndroid Build Coastguard Worker         let size = cursor.read_u8()?;
530*cf78ab8cSAndroid Build Coastguard Worker         if size & PTR_MASK == PTR_MASK {
531*cf78ab8cSAndroid Build Coastguard Worker             let two = cursor.read_u8()?;
532*cf78ab8cSAndroid Build Coastguard Worker             let offset: u64 = u16::from_be_bytes([size & !PTR_MASK, two]).into();
533*cf78ab8cSAndroid Build Coastguard Worker             return Ok(NamePart::Pointer(offset));
534*cf78ab8cSAndroid Build Coastguard Worker         }
535*cf78ab8cSAndroid Build Coastguard Worker         if size == 0 {
536*cf78ab8cSAndroid Build Coastguard Worker             return Ok(NamePart::Root);
537*cf78ab8cSAndroid Build Coastguard Worker         }
538*cf78ab8cSAndroid Build Coastguard Worker         if size > Self::MAX {
539*cf78ab8cSAndroid Build Coastguard Worker             return Err(DnsError::InvalidLength);
540*cf78ab8cSAndroid Build Coastguard Worker         }
541*cf78ab8cSAndroid Build Coastguard Worker         let end = size as usize;
542*cf78ab8cSAndroid Build Coastguard Worker         let buffer_ref: &[u8] = cursor.get_ref();
543*cf78ab8cSAndroid Build Coastguard Worker         let start = cursor.position() as usize;
544*cf78ab8cSAndroid Build Coastguard Worker         let label = str::from_utf8(&buffer_ref[start..start + end])?.to_string();
545*cf78ab8cSAndroid Build Coastguard Worker         cursor.seek(SeekFrom::Current(end as i64))?;
546*cf78ab8cSAndroid Build Coastguard Worker         Ok(NamePart::Label(label))
547*cf78ab8cSAndroid Build Coastguard Worker     }
548*cf78ab8cSAndroid Build Coastguard Worker }
549*cf78ab8cSAndroid Build Coastguard Worker 
550*cf78ab8cSAndroid Build Coastguard Worker /// The Fully Qualitifed Domain Name from ANSWER and RR records
551*cf78ab8cSAndroid Build Coastguard Worker 
552*cf78ab8cSAndroid Build Coastguard Worker struct Name();
553*cf78ab8cSAndroid Build Coastguard Worker 
554*cf78ab8cSAndroid Build Coastguard Worker impl Name {
555*cf78ab8cSAndroid Build Coastguard Worker     // Convert a variable length QNAME or NAME to a String.
556*cf78ab8cSAndroid Build Coastguard Worker     //
557*cf78ab8cSAndroid Build Coastguard Worker     // The cursor is updated to the end of the first sequence of
558*cf78ab8cSAndroid Build Coastguard Worker     // labels, and not the position after a Pointer. This allows the
559*cf78ab8cSAndroid Build Coastguard Worker     // cursor to be used for reading the remainder of the Question or
560*cf78ab8cSAndroid Build Coastguard Worker     // ResourceRecord.
561*cf78ab8cSAndroid Build Coastguard Worker     //
562*cf78ab8cSAndroid Build Coastguard Worker     // Limit the number of Pointers in malificient messages to avoid
563*cf78ab8cSAndroid Build Coastguard Worker     // looping.
564*cf78ab8cSAndroid Build Coastguard Worker     //
to_string(cursor: &mut impl CursorExt) -> Result<String>565*cf78ab8cSAndroid Build Coastguard Worker     fn to_string(cursor: &mut impl CursorExt) -> Result<String> {
566*cf78ab8cSAndroid Build Coastguard Worker         Self::to_string_guard(cursor, 0)
567*cf78ab8cSAndroid Build Coastguard Worker     }
568*cf78ab8cSAndroid Build Coastguard Worker 
to_string_guard(cursor: &mut impl CursorExt, jumps: usize) -> Result<String>569*cf78ab8cSAndroid Build Coastguard Worker     fn to_string_guard(cursor: &mut impl CursorExt, jumps: usize) -> Result<String> {
570*cf78ab8cSAndroid Build Coastguard Worker         if jumps > 2 {
571*cf78ab8cSAndroid Build Coastguard Worker             return Err(DnsError::PointerLoop);
572*cf78ab8cSAndroid Build Coastguard Worker         }
573*cf78ab8cSAndroid Build Coastguard Worker         let mut name = String::with_capacity(255);
574*cf78ab8cSAndroid Build Coastguard Worker         loop {
575*cf78ab8cSAndroid Build Coastguard Worker             match NamePart::split_once(cursor)? {
576*cf78ab8cSAndroid Build Coastguard Worker                 NamePart::Root => return Ok(name),
577*cf78ab8cSAndroid Build Coastguard Worker                 NamePart::Pointer(offset) => {
578*cf78ab8cSAndroid Build Coastguard Worker                     let mut pointer_cursor = cursor.clone();
579*cf78ab8cSAndroid Build Coastguard Worker                     pointer_cursor.set_position(offset);
580*cf78ab8cSAndroid Build Coastguard Worker                     let pointer_name = Name::to_string_guard(&mut pointer_cursor, jumps + 1)?;
581*cf78ab8cSAndroid Build Coastguard Worker                     name.push_str(&pointer_name);
582*cf78ab8cSAndroid Build Coastguard Worker                     return Ok(name);
583*cf78ab8cSAndroid Build Coastguard Worker                 }
584*cf78ab8cSAndroid Build Coastguard Worker                 NamePart::Label(label) => {
585*cf78ab8cSAndroid Build Coastguard Worker                     if !name.is_empty() {
586*cf78ab8cSAndroid Build Coastguard Worker                         name.push('.');
587*cf78ab8cSAndroid Build Coastguard Worker                     }
588*cf78ab8cSAndroid Build Coastguard Worker                     name.push_str(&label);
589*cf78ab8cSAndroid Build Coastguard Worker                 }
590*cf78ab8cSAndroid Build Coastguard Worker             };
591*cf78ab8cSAndroid Build Coastguard Worker         }
592*cf78ab8cSAndroid Build Coastguard Worker     }
593*cf78ab8cSAndroid Build Coastguard Worker }
594*cf78ab8cSAndroid Build Coastguard Worker 
595*cf78ab8cSAndroid Build Coastguard Worker // END REGION NAME
596*cf78ab8cSAndroid Build Coastguard Worker 
597*cf78ab8cSAndroid Build Coastguard Worker #[cfg(test)]
598*cf78ab8cSAndroid Build Coastguard Worker mod test_message {
599*cf78ab8cSAndroid Build Coastguard Worker     use super::*;
600*cf78ab8cSAndroid Build Coastguard Worker 
601*cf78ab8cSAndroid Build Coastguard Worker     #[test]
test_dns_responses() -> Result<()>602*cf78ab8cSAndroid Build Coastguard Worker     fn test_dns_responses() -> Result<()> {
603*cf78ab8cSAndroid Build Coastguard Worker         let bytes: [u8; 81] = [
604*cf78ab8cSAndroid Build Coastguard Worker             0xc2, 0x87, 0x81, 0x80, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x3, 0x69, 0x62, 0x6d,
605*cf78ab8cSAndroid Build Coastguard Worker             0x3, 0x63, 0x6f, 0x6d, 0x0, 0x0, 0x1c, 0x0, 0x1, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0,
606*cf78ab8cSAndroid Build Coastguard Worker             0x0, 0x0, 0x8, 0x0, 0x10, 0x26, 0x0, 0x14, 0x6, 0x5e, 0x0, 0x2, 0x93, 0x0, 0x0, 0x0,
607*cf78ab8cSAndroid Build Coastguard Worker             0x0, 0x0, 0x0, 0x38, 0x31, 0xc0, 0xc, 0x0, 0x1c, 0x0, 0x1, 0x0, 0x0, 0x0, 0x8, 0x0,
608*cf78ab8cSAndroid Build Coastguard Worker             0x10, 0x26, 0x0, 0x14, 0x6, 0x5e, 0x0, 0x2, 0xaa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38,
609*cf78ab8cSAndroid Build Coastguard Worker             0x31,
610*cf78ab8cSAndroid Build Coastguard Worker         ];
611*cf78ab8cSAndroid Build Coastguard Worker         let bytes: &[u8] = &bytes;
612*cf78ab8cSAndroid Build Coastguard Worker         let answers = parse_answers(bytes)?;
613*cf78ab8cSAndroid Build Coastguard Worker         assert_eq!(
614*cf78ab8cSAndroid Build Coastguard Worker             *answers.get(0).unwrap(),
615*cf78ab8cSAndroid Build Coastguard Worker             (Ipv6Addr::from_str("2600:1406:5e00:293::3831")?.into(), "ibm.com".to_string())
616*cf78ab8cSAndroid Build Coastguard Worker         );
617*cf78ab8cSAndroid Build Coastguard Worker         assert_eq!(
618*cf78ab8cSAndroid Build Coastguard Worker             *answers.get(1).unwrap(),
619*cf78ab8cSAndroid Build Coastguard Worker             (Ipv6Addr::from_str("2600:1406:5e00:2aa::3831")?.into(), "ibm.com".to_string())
620*cf78ab8cSAndroid Build Coastguard Worker         );
621*cf78ab8cSAndroid Build Coastguard Worker         Ok(())
622*cf78ab8cSAndroid Build Coastguard Worker     }
623*cf78ab8cSAndroid Build Coastguard Worker }
624