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