simple_dns/dns/mod.rs
1//! Provides parsing and manipulation for DNS packets
2
3mod character_string;
4pub use character_string::CharacterString;
5
6mod name;
7pub use name::Name;
8
9mod label;
10pub use label::Label;
11
12mod packet;
13pub use packet::Packet;
14
15mod header;
16use header::Header;
17
18pub mod header_buffer;
19
20mod wire_format;
21pub(crate) use wire_format::WireFormat;
22
23mod question;
24pub use question::Question;
25
26pub mod rdata;
27pub use rdata::TYPE;
28
29mod resource_record;
30pub use resource_record::ResourceRecord;
31
32use crate::lib::TryFrom;
33use bitflags::bitflags;
34
35const MAX_LABEL_LENGTH: usize = 63;
36const MAX_SERVICE_NAME_LENGTH: usize = 16;
37const MAX_NAME_LENGTH: usize = 255;
38const MAX_CHARACTER_STRING_LENGTH: usize = 255;
39const MAX_NULL_LENGTH: usize = 65535;
40
41bitflags! {
42 /// Possible Packet Flags
43 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
44 pub struct PacketFlag: u16 {
45 /// Indicates if this packet is a query or a response. This is the QR flag in the DNS
46 /// specifications, this flag is called Response here to be more ergonomic
47 const RESPONSE = 0b1000_0000_0000_0000;
48
49 /// Authoritative Answer - this bit is valid in responses,
50 /// and specifies that the responding name server is an authority for the domain name in question section.
51 const AUTHORITATIVE_ANSWER = 0b0000_0100_0000_0000;
52 /// TrunCation - specifies that this message was truncated due to
53 /// length greater than that permitted on the transmission channel.
54 const TRUNCATION = 0b0000_0010_0000_0000;
55 /// Recursion Desired may be set in a query and is copied into the response.
56 /// If RD is set, it directs the name server to pursue the query recursively.
57 /// Recursive query support is optional.
58 const RECURSION_DESIRED = 0b0000_0001_0000_0000;
59 /// Recursion Available is set or cleared in a response.
60 /// It denotes whether recursive query support is available in the name server.
61 const RECURSION_AVAILABLE = 0b0000_0000_1000_0000;
62 #[allow(missing_docs)]
63 const AUTHENTIC_DATA = 0b0000_0000_0010_0000;
64 #[allow(missing_docs)]
65 const CHECKING_DISABLED = 0b0000_0000_0001_0000;
66 }
67}
68
69// /// The maximum DNS packet size is 9000 bytes less the maximum
70// /// sizes of the IP (60) and UDP (8) headers.
71// // const MAX_PACKET_SIZE: usize = 9000 - 68;
72
73/// Possible QTYPE values for a Question in a DNS packet
74/// Each value is described according to its own RFC
75#[derive(Debug, Copy, Clone, PartialEq, Eq)]
76pub enum QTYPE {
77 /// Query for the specific [TYPE]
78 TYPE(TYPE),
79 /// A request for incremental transfer of a zone. [RFC 1995](https://tools.ietf.org/html/rfc1995)
80 IXFR,
81 /// A request for a transfer of an entire zone, [RFC 1035](https://tools.ietf.org/html/rfc1035)
82 AXFR,
83 /// A request for mailbox-related records (MB, MG or MR), [RFC 1035](https://tools.ietf.org/html/rfc1035)
84 MAILB,
85 /// A request for mail agent RRs (Obsolete - see MX), [RFC 1035](https://tools.ietf.org/html/rfc1035)
86 MAILA,
87 /// A request for all records, [RFC 1035](https://tools.ietf.org/html/rfc1035)
88 ANY,
89}
90
91impl From<TYPE> for QTYPE {
92 fn from(v: TYPE) -> Self {
93 Self::TYPE(v)
94 }
95}
96
97impl TryFrom<u16> for QTYPE {
98 type Error = crate::SimpleDnsError;
99
100 fn try_from(value: u16) -> Result<Self, Self::Error> {
101 match value {
102 251 => Ok(QTYPE::IXFR),
103 252 => Ok(QTYPE::AXFR),
104 253 => Ok(QTYPE::MAILB),
105 254 => Ok(QTYPE::MAILA),
106 255 => Ok(QTYPE::ANY),
107 v => match TYPE::from(v) {
108 TYPE::Unknown(_) => Err(Self::Error::InvalidQType(v)),
109 ty => Ok(ty.into()),
110 },
111 }
112 }
113}
114
115impl From<QTYPE> for u16 {
116 fn from(val: QTYPE) -> Self {
117 match val {
118 QTYPE::TYPE(ty) => ty.into(),
119 QTYPE::IXFR => 251,
120 QTYPE::AXFR => 252,
121 QTYPE::MAILB => 253,
122 QTYPE::MAILA => 254,
123 QTYPE::ANY => 255,
124 }
125 }
126}
127
128/// Possible CLASS values for a Resource in a DNS packet
129/// Each value is described according to its own RFC
130#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
131pub enum CLASS {
132 /// The Internet, [RFC 1035](https://tools.ietf.org/html/rfc1035)
133 IN = 1,
134 /// The CSNET class (Obsolete - used only for examples in some obsolete RFCs), [RFC 1035](https://tools.ietf.org/html/rfc1035)
135 CS = 2,
136 /// The CHAOS class, [RFC 1035](https://tools.ietf.org/html/rfc1035)
137 CH = 3,
138 /// Hesiod [Dyer 87], [RFC 1035](https://tools.ietf.org/html/rfc1035)
139 HS = 4,
140 /// [RFC 2136](https://datatracker.ietf.org/doc/html/rfc2136)
141 NONE = 254,
142}
143
144impl TryFrom<u16> for CLASS {
145 type Error = crate::SimpleDnsError;
146
147 fn try_from(value: u16) -> Result<Self, Self::Error> {
148 use self::CLASS::*;
149 match value {
150 1 => Ok(IN),
151 2 => Ok(CS),
152 3 => Ok(CH),
153 4 => Ok(HS),
154 254 => Ok(NONE),
155 v => Err(Self::Error::InvalidClass(v)),
156 }
157 }
158}
159
160impl From<CLASS> for u16 {
161 fn from(val: CLASS) -> Self {
162 val as u16
163 }
164}
165
166/// Possible QCLASS values for a Question in a DNS packet
167/// Each value is described according to its own RFC
168#[derive(Debug, Copy, Clone, PartialEq, Eq)]
169pub enum QCLASS {
170 /// Query for the specific [CLASS]
171 CLASS(CLASS),
172 /// [RFC 1035](https://tools.ietf.org/html/rfc1035)
173 ANY,
174}
175
176impl From<CLASS> for QCLASS {
177 fn from(v: CLASS) -> Self {
178 Self::CLASS(v)
179 }
180}
181
182impl TryFrom<u16> for QCLASS {
183 type Error = crate::SimpleDnsError;
184
185 fn try_from(value: u16) -> Result<Self, Self::Error> {
186 match value {
187 255 => Ok(QCLASS::ANY),
188 v => CLASS::try_from(v).map(|x| x.into()),
189 }
190 }
191}
192
193impl From<QCLASS> for u16 {
194 fn from(val: QCLASS) -> Self {
195 match val {
196 QCLASS::CLASS(class) => class as u16,
197 QCLASS::ANY => 255,
198 }
199 }
200}
201
202/// Possible OPCODE values for a DNS packet, use to specify the type of operation.
203/// [RFC 1035](https://tools.ietf.org/html/rfc1035): A four bit field that specifies kind of query in this message.
204/// This value is set by the originator of a query and copied into the response.
205#[derive(Debug, Copy, Clone, PartialEq, Eq)]
206pub enum OPCODE {
207 /// Normal query
208 StandardQuery = 0,
209 /// Inverse query (query a name by IP)
210 InverseQuery = 1,
211 /// Server status request
212 ServerStatusRequest = 2,
213 /// Notify query
214 Notify = 4,
215 /// Update query [RFC 2136](https://datatracker.ietf.org/doc/html/rfc2136)
216 Update = 5,
217 /// Reserved opcode for future use
218 Reserved,
219}
220
221impl From<u16> for OPCODE {
222 fn from(code: u16) -> Self {
223 match code {
224 0 => OPCODE::StandardQuery,
225 1 => OPCODE::InverseQuery,
226 2 => OPCODE::ServerStatusRequest,
227 4 => OPCODE::Notify,
228 5 => OPCODE::Update,
229 _ => OPCODE::Reserved,
230 }
231 }
232}
233
234/// Possible RCODE values for a DNS packet
235/// [RFC 1035](https://tools.ietf.org/html/rfc1035) Response code - this 4 bit field is set as part of responses.
236/// The values have the following interpretation
237#[derive(Debug, Copy, Clone, PartialEq, Eq)]
238pub enum RCODE {
239 /// No error condition
240 NoError = 0,
241 /// Format error - The name server was unable to interpret the query.
242 FormatError = 1,
243 /// Server failure - The name server was unable to process this query due to a problem with the name server.
244 ServerFailure = 2,
245 /// Name Error - Meaningful only for responses from an authoritative name server,
246 /// this code signifies that the domain name referenced in the query does not exist.
247 NameError = 3,
248 /// Not Implemented - The name server does not support the requested kind of query.
249 NotImplemented = 4,
250 /// Refused - The name server refuses to perform the specified operation for policy reasons.
251 /// For example, a name server may not wish to provide the information to the particular requester,
252 /// or a name server may not wish to perform a particular operation (e.g., zone transfer) for particular data.
253 Refused = 5,
254 /// Some name that ought not to exist, does exist.
255 /// [RFC 2136](https://datatracker.ietf.org/doc/html/rfc2136)
256 YXDOMAIN = 6,
257 /// Some RRset that ought not to exist, does exist.
258 /// [RFC 2136](https://datatracker.ietf.org/doc/html/rfc2136)
259 YXRRSET = 7,
260 /// Some RRset that ought to exist, does not exist.
261 /// [RFC 2136](https://datatracker.ietf.org/doc/html/rfc2136)
262 NXRRSET = 8,
263 /// The server is not authoritative for the zone named in the Zone Section.
264 /// [RFC 2136](https://datatracker.ietf.org/doc/html/rfc2136)
265 NOTAUTH = 9,
266 /// A name used in the Prerequisite or Update Section is not within the zone denoted by the Zone Section.
267 /// [RFC 2136](https://datatracker.ietf.org/doc/html/rfc2136)
268 NOTZONE = 10,
269 /// EDNS Version not supported by the responder
270 /// [RFC 6891](https://datatracker.ietf.org/doc/html/rfc6891)
271 BADVERS = 16,
272
273 /// Reserved for future use.
274 Reserved,
275}
276
277impl From<u16> for RCODE {
278 fn from(code: u16) -> Self {
279 use RCODE::*;
280 match code {
281 0 => NoError,
282 1 => FormatError,
283 2 => ServerFailure,
284 3 => NameError,
285 4 => NotImplemented,
286 5 => Refused,
287 6 => YXDOMAIN,
288 7 => YXRRSET,
289 8 => NXRRSET,
290 9 => NOTAUTH,
291 10 => NOTZONE,
292 16 => BADVERS,
293 _ => RCODE::Reserved,
294 }
295 }
296}