sawp_dns/
answer.rs

1use nom::bytes::streaming::take;
2use nom::number::complete::be_u32;
3use nom::number::streaming::be_u16;
4
5use sawp_flags::{Flag, Flags};
6
7use crate::enums::{RecordClass, RecordType};
8use crate::rdata::RDataType;
9use crate::{custom_count, ErrorFlags, IResult, Name};
10
11#[cfg(feature = "ffi")]
12use sawp_ffi::GenerateFFI;
13
14/// Per RFC1035/RFC4408: max RDATA len = 65535 octets. Since TXT RDATA includes a length byte before
15/// each TXT string, min size per TXT is 2 bytes, leaving maximum of 65535/2 parser runs needed.
16const MAX_TXT_PARSES: usize = 32767;
17/// First three bytes of an OPT AR - determines whether an AR should be parsed with special "OPT logic".
18const OPT_RR_START: [u8; 3] = [0, 0, 41];
19
20/// A parsed DNS answer
21#[cfg_attr(feature = "ffi", derive(GenerateFFI))]
22#[cfg_attr(feature = "ffi", sawp_ffi(prefix = "sawp_dns"))]
23#[derive(Debug, PartialEq, Eq)]
24pub struct Answer {
25    pub name: Vec<u8>,
26    #[cfg_attr(feature = "ffi", sawp_ffi(copy))]
27    pub rtype: RecordType,
28    pub rtype_raw: u16,
29    #[cfg_attr(feature = "ffi", sawp_ffi(copy))]
30    pub rclass: RecordClass,
31    pub rclass_raw: u16,
32    pub ttl: u32,
33    pub data: RDataType,
34}
35
36impl Answer {
37    fn parse<'a>(
38        input: &'a [u8],
39        reference_bytes: &'a [u8],
40    ) -> IResult<'a, (Answer, Flags<ErrorFlags>)> {
41        let (input, (name, mut error_flags)) = Name::parse(reference_bytes)(input)?;
42
43        let (input, working_rtype) = be_u16(input)?;
44        let rtype = RecordType::from_raw(working_rtype);
45        if rtype == RecordType::UNKNOWN {
46            error_flags |= ErrorFlags::UnknownRtype;
47        }
48
49        let (input, working_rclass) = be_u16(input)?;
50        let rclass = RecordClass::from_raw(working_rclass);
51        if rclass == RecordClass::UNKNOWN {
52            error_flags |= ErrorFlags::UnknownRclass;
53        }
54
55        let (input, ttl) = be_u32(input)?;
56
57        let mut answer: Answer = Answer {
58            name,
59            rtype,
60            rtype_raw: working_rtype,
61            rclass,
62            rclass_raw: working_rclass,
63            ttl,
64            data: RDataType::UNKNOWN(vec![]),
65        };
66
67        let (input, data_len) = be_u16(input)?;
68        let (rem, local_data) = take(data_len)(input)?;
69
70        // always call once
71        let (mut local_data, (mut rdata, inner_error_flags)) =
72            RDataType::parse(local_data, reference_bytes, rtype)?;
73        error_flags |= inner_error_flags;
74
75        // get ref to buffer we will extend first, if TXT
76        if let RDataType::TXT(ref mut current_rdata) = rdata {
77            for _ in 0..MAX_TXT_PARSES - 1 {
78                if local_data.is_empty() {
79                    break;
80                }
81                let (new_data, (rdata, inner_error_flags)) =
82                    RDataType::parse(local_data, reference_bytes, rtype)?;
83                error_flags |= inner_error_flags;
84                if let RDataType::TXT(new_rdata) = rdata {
85                    current_rdata.extend(new_rdata);
86                    local_data = new_data;
87                } else {
88                    break;
89                }
90            }
91        }
92        answer.data = rdata;
93        Ok((rem, (answer, error_flags)))
94    }
95
96    fn parse_additional<'a>(
97        input: &'a [u8],
98        reference_bytes: &'a [u8],
99    ) -> IResult<'a, (Answer, Flags<ErrorFlags>, bool)> {
100        let mut opt_rr_present = false;
101        if input.len() >= 3 && input[0..3] == OPT_RR_START[0..3] {
102            let (input, (data, inner_error_flags)) = RDataType::parse_rdata_opt(&input[3..])?;
103            opt_rr_present = true;
104            Ok((
105                input,
106                (
107                    Answer {
108                        name: vec![0], // OPT RRs must be named 0 <root>
109                        rtype: RecordType::OPT,
110                        rtype_raw: 41,
111                        rclass: RecordClass::NONE, // OPT RRs have no class
112                        rclass_raw: 254,
113                        ttl: 0, // OPT RRs do not contain a TTL
114                        data,
115                    },
116                    inner_error_flags,
117                    opt_rr_present,
118                ),
119            ))
120        } else {
121            let (input, (answer, inner_error_flags)) = Answer::parse(input, reference_bytes)?;
122            Ok((input, (answer, inner_error_flags, opt_rr_present)))
123        }
124    }
125
126    pub fn parse_additionals<'a>(
127        input: &'a [u8],
128        reference_bytes: &'a [u8],
129        acnt: usize,
130    ) -> IResult<'a, (Vec<Answer>, Flags<ErrorFlags>)> {
131        let mut opt_rr_present = false;
132        let mut error_flags = ErrorFlags::none();
133        let (input, answers) = custom_count(
134            |input, reference_bytes| {
135                let (input, (answer, inner_error_flags, inner_opt_rr_present)) =
136                    Answer::parse_additional(input, reference_bytes)?;
137                if inner_opt_rr_present {
138                    if opt_rr_present {
139                        error_flags |= ErrorFlags::ExtraOptRr;
140                    } else {
141                        opt_rr_present = true;
142                    }
143                }
144                error_flags |= inner_error_flags;
145                Ok((input, answer))
146            },
147            acnt,
148        )(input, reference_bytes)?;
149
150        Ok((input, (answers, error_flags)))
151    }
152
153    pub fn parse_answers<'a>(
154        input: &'a [u8],
155        reference_bytes: &'a [u8],
156        acnt: usize,
157    ) -> IResult<'a, (Vec<Answer>, Flags<ErrorFlags>)> {
158        let mut error_flags = ErrorFlags::none();
159        let (input, answers) = custom_count(
160            |input, reference_bytes| {
161                let (input, (answer, inner_error_flags)) = Answer::parse(input, reference_bytes)?;
162                error_flags |= inner_error_flags;
163                Ok((input, answer))
164            },
165            acnt,
166        )(input, reference_bytes)?;
167
168        Ok((input, (answers, error_flags)))
169    }
170}