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