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}