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