1use nom::bytes::streaming::take;
12use nom::number::streaming::be_u16;
13
14use num_enum::TryFromPrimitive;
15
16use sawp_flags::{Flag, Flags};
17
18use std::convert::TryFrom;
19
20use crate::{custom_many0, ErrorFlags, IResult};
21#[cfg(feature = "ffi")]
22use sawp_ffi::GenerateFFI;
23
24#[derive(Clone, Copy, Debug, PartialEq, Eq, TryFromPrimitive)]
25#[repr(u16)]
26pub enum OptionCode {
27    LLQ = 1,
29    UL = 2,
31    NSID = 3,
33    DAU = 5,
35    DHU = 6,
37    N3U = 7,
39    EDNSCLIENTSUBNET = 8,
41    EDNSEXPIRE = 9,
43    COOKIE = 10,
45    EDNSTCPKEEPALIVE = 11,
47    PADDING = 12,
49    CHAIN = 13,
51    EDNSKEYTAG = 14,
53    EDNSERROR = 15,
55    EDNSCLIENTTAG = 16,
57    EDNSSERVERTAG = 17,
59    DEVICEID = 26946,
61    UNKNOWN,
62}
63
64impl OptionCode {
65    pub fn from_raw(val: u16) -> Self {
66        OptionCode::try_from(val).unwrap_or(OptionCode::UNKNOWN)
67    }
68}
69
70#[cfg_attr(feature = "ffi", derive(GenerateFFI))]
71#[cfg_attr(feature = "ffi", sawp_ffi(prefix = "sawp_dns"))]
72#[derive(Debug, PartialEq, Eq)]
73pub struct EdnsOption {
74    #[cfg_attr(feature = "ffi", sawp_ffi(copy))]
75    pub code: OptionCode,
76    pub data: Vec<u8>,
77}
78
79impl EdnsOption {
80    pub fn parse(input: &[u8]) -> IResult<(EdnsOption, Flags<ErrorFlags>)> {
81        let (input, (code, inner_error_flags)) = EdnsOption::parse_option_code(input)?;
82        let (input, option_length) = be_u16(input)?;
83        let (input, data) = take(option_length)(input)?;
84
85        Ok((
86            input,
87            (
88                EdnsOption {
89                    code,
90                    data: data.to_vec(),
91                },
92                inner_error_flags,
93            ),
94        ))
95    }
96
97    fn parse_option_code(input: &[u8]) -> IResult<(OptionCode, Flags<ErrorFlags>)> {
98        let mut error_flags = ErrorFlags::none();
99
100        let (input, raw_option_code) = be_u16(input)?;
101        let code = OptionCode::from_raw(raw_option_code);
102        if code == OptionCode::UNKNOWN {
103            error_flags |= ErrorFlags::EdnsParseFail;
104        }
105        Ok((input, (code, error_flags)))
106    }
107
108    pub fn parse_options(
109        input: &[u8],
110        data_len: u16,
111    ) -> IResult<(Vec<EdnsOption>, Flags<ErrorFlags>)> {
112        let mut error_flags = ErrorFlags::none();
113        if data_len < 4 {
114            return Ok((input, (vec![], error_flags)));
115        }
116
117        let (input, options) = custom_many0(|input| {
118            let (input, (option, inner_error_flags)) = EdnsOption::parse(input)?;
119            error_flags |= inner_error_flags;
120            Ok((input, option))
121        })(input)?;
122
123        Ok((input, (options, error_flags)))
124    }
125}