1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use std::net::{Ipv4Addr, Ipv6Addr};
use byteorder::{BigEndian, ByteOrder};
use {Name, Type, Error, SoaRecord};
use std::str;
#[derive(Debug)]
#[allow(missing_docs)]
pub enum RRData<'a> {
CNAME(Name<'a>),
NS(Name<'a>),
A(Ipv4Addr),
AAAA(Ipv6Addr),
SRV { priority: u16, weight: u16, port: u16, target: Name<'a> },
SOA(SoaRecord<'a>),
PTR(Name<'a>),
MX { preference: u16, exchange: Name<'a> },
TXT(String),
Unknown(&'a [u8]),
}
impl<'a> RRData<'a> {
pub fn parse(typ: Type, rdata: &'a [u8], original: &'a [u8])
-> Result<RRData<'a>, Error>
{
match typ {
Type::A => {
if rdata.len() != 4 {
return Err(Error::WrongRdataLength);
}
Ok(RRData::A(
Ipv4Addr::from(BigEndian::read_u32(rdata))))
}
Type::AAAA => {
if rdata.len() != 16 {
return Err(Error::WrongRdataLength);
}
Ok(RRData::AAAA(Ipv6Addr::new(
BigEndian::read_u16(&rdata[0..2]),
BigEndian::read_u16(&rdata[2..4]),
BigEndian::read_u16(&rdata[4..6]),
BigEndian::read_u16(&rdata[6..8]),
BigEndian::read_u16(&rdata[8..10]),
BigEndian::read_u16(&rdata[10..12]),
BigEndian::read_u16(&rdata[12..14]),
BigEndian::read_u16(&rdata[14..16]),
)))
}
Type::CNAME => {
Ok(RRData::CNAME(try!(Name::scan(rdata, original))))
}
Type::NS => {
Ok(RRData::NS(try!(Name::scan(rdata, original))))
}
Type::MX => {
if rdata.len() < 3 {
return Err(Error::WrongRdataLength);
}
Ok(RRData::MX {
preference: BigEndian::read_u16(&rdata[..2]),
exchange: try!(Name::scan(&rdata[2..], original)),
})
}
Type::PTR => {
Ok(RRData::PTR(try!(Name::scan(rdata, original))))
}
Type::SOA => {
let mut pos = 0;
let primary_name_server = try!(Name::scan(rdata, original));
pos += primary_name_server.byte_len();
let mailbox = try!(Name::scan(&rdata[pos..], original));
pos += mailbox.byte_len();
if rdata[pos..].len() < 20 {
return Err(Error::WrongRdataLength);
}
Ok(RRData::SOA(SoaRecord {
primary_ns: primary_name_server,
mailbox: mailbox,
serial: BigEndian::read_u32(&rdata[pos..(pos+4)]),
refresh: BigEndian::read_u32(&rdata[(pos+4)..(pos+8)]),
retry: BigEndian::read_u32(&rdata[(pos+8)..(pos+12)]),
expire: BigEndian::read_u32(&rdata[(pos+12)..(pos+16)]),
minimum_ttl: BigEndian::read_u32(&rdata[(pos+16)..(pos+20)]),
}))
}
Type::SRV => {
if rdata.len() < 7 {
return Err(Error::WrongRdataLength);
}
Ok(RRData::SRV {
priority: BigEndian::read_u16(&rdata[..2]),
weight: BigEndian::read_u16(&rdata[2..4]),
port: BigEndian::read_u16(&rdata[4..6]),
target: try!(Name::scan(&rdata[6..], original)),
})
}
Type::TXT => {
let len = rdata.len();
if len < 1 {
return Err(Error::WrongRdataLength);
}
let mut ret_string = String::new();
let mut pos = 0;
while pos < len {
let rdlen = rdata[pos] as usize;
pos += 1;
if len < rdlen + pos {
return Err(Error::WrongRdataLength);
}
match str::from_utf8(&rdata[pos..(pos+rdlen)]) {
Ok(val) => ret_string.push_str(val),
Err(e) => return Err(Error::TxtDataIsNotUTF8(e)),
}
pos += rdlen;
}
Ok(RRData::TXT(ret_string))
}
_ => {
Ok(RRData::Unknown(rdata))
}
}
}
}