1use {SerialNumber, Ttl, std};
2
3pub trait Format<'a> {
5 type Name: Name<'a>;
6 type RawOctets: AsRef<[u8]> + Clone + std::fmt::Debug + Eq + PartialEq;
7}
8
9pub trait Name<'a>: std::fmt::Display {
11 type LabelIter: Iterator<Item = &'a str>;
12 fn labels(&'a self) -> Self::LabelIter;
13}
14
15#[derive(Clone, Debug, Eq, PartialEq)]
17pub struct Question<'a, F: Format<'a>> {
18 qname: F::Name,
19 qtype: QType,
20 qclass: QClass,
21}
22
23impl<'a, F: Format<'a>> Question<'a, F> {
24 pub fn new<N: Into<F::Name>>(qname: N, qtype: QType, qclass: QClass) -> Self {
25 Question {
26 qname: qname.into(),
27 qtype: qtype,
28 qclass: qclass,
29 }
30 }
31
32 pub fn qname(&self) -> &F::Name {
33 &self.qname
34 }
35
36 pub fn qtype(&self) -> QType {
37 self.qtype
38 }
39
40 pub fn qclass(&self) -> QClass {
41 self.qclass
42 }
43}
44
45#[derive(Clone, Debug, Eq, PartialEq)]
47pub struct ResourceRecord<'a, F: Format<'a>> {
48 name: F::Name,
49 type_: Type,
50 class: Class,
51 ttl: Ttl,
52 rdata: RData<'a, F>,
53}
54
55impl<'a, F: Format<'a>> ResourceRecord<'a, F> {
56 pub fn new<N: Into<F::Name>, IntoT: Into<Ttl>, R: Into<RData<'a, F>>>(name: N,
57 type_: Type,
58 class: Class,
59 ttl: IntoT,
60 rdata: R)
61 -> Self {
62 ResourceRecord {
63 name: name.into(),
64 type_: type_,
65 class: class,
66 ttl: ttl.into(),
67 rdata: rdata.into(),
68 }
69 }
70
71 pub fn name(&self) -> &F::Name {
72 &self.name
73 }
74
75 pub fn type_(&self) -> Type {
76 self.type_
77 }
78
79 pub fn class(&self) -> Class {
80 self.class
81 }
82
83 pub fn ttl(&self) -> Ttl {
84 self.ttl
85 }
86
87 pub fn rdata(&self) -> &RData<'a, F> {
88 &self.rdata
89 }
90}
91
92#[derive(Clone, Debug, Eq, PartialEq)]
94pub enum RData<'a, F: Format<'a>> {
95 A { address: std::net::Ipv4Addr },
96 CName { cname: F::Name },
97 NS { nsdname: F::Name },
98 SOA {
99 mname: F::Name,
100 rname: F::Name,
101 serial: SerialNumber,
102 refresh: Ttl,
103 retry: Ttl,
104 expire: Ttl,
105 minimum: Ttl,
106 },
107 Other { octets: F::RawOctets },
108}
109
110#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
112pub struct Class(pub u16);
113
114impl Class {
115 pub fn as_u16(&self) -> u16 {
117 self.0
118 }
119}
120
121#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
123pub struct QClass(pub u16);
124
125impl QClass {
126 pub fn as_u16(&self) -> u16 {
128 self.0
129 }
130}
131
132impl From<QClass> for Class {
133 fn from(x: QClass) -> Self {
134 Class(x.0)
135 }
136}
137
138pub mod class {
140 use super::Class;
141
142 pub const IN: Class = Class(1);
144}
145
146pub mod qclass {
148 use super::QClass;
149
150 pub const IN: QClass = QClass(1);
152
153 pub const ANY: QClass = QClass(255);
155}
156
157#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
159pub struct Type(pub u16);
160
161impl Type {
162 pub fn as_u16(&self) -> u16 {
164 self.0
165 }
166}
167
168#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
170pub struct QType(pub u16);
171
172impl QType {
173 pub fn as_u16(&self) -> u16 {
175 self.0
176 }
177}
178
179impl From<QType> for Type {
180 fn from(x: QType) -> Self {
181 Type(x.0)
182 }
183}
184
185pub mod type_ {
187 use super::Type;
188
189 pub const A: Type = Type(1);
191
192 pub const NS: Type = Type(2);
194
195 pub const CNAME: Type = Type(5);
197
198 pub const SOA: Type = Type(6);
200}
201
202pub mod qtype {
204 use super::QType;
205
206 pub const A: QType = QType(1);
208
209 pub const NS: QType = QType(2);
211
212 pub const CNAME: QType = QType(5);
214
215 pub const SOA: QType = QType(6);
217
218 pub const ANY: QType = QType(255);
220}
221
222pub fn is_label_valid(s: &[u8]) -> bool {
223 debug_assert!(!s.is_empty());
224 let c = *s.first().unwrap() as char;
225 if !c.is_alphabetic() {
226 return false;
227 }
228 let c = *s.last().unwrap() as char;
229 if !c.is_alphanumeric() {
230 return false;
231 }
232 s.iter().map(|&b| b as char).all(|c| c.is_alphanumeric() || c == '-')
233}
234
235#[cfg(test)]
236mod tests {
237 #[test]
238 fn is_label_valid() {
239 let f = |s: &str| super::is_label_valid(s.as_bytes());
240 assert!(f("a"));
241 assert!(f("alpha"));
242 assert!(f("alpha17"));
243 assert!(f("alpha-bravo"));
244 assert!(f("alpha-bravo17"));
245 assert!(!f("-alpha-bravo17"));
246 assert!(!f("1alpha"));
247 assert!(!f("-alpha"));
248 assert!(!f("alpha-"));
249 assert!(!f("alpha.bravo"));
250 }
251}