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