dns_parser_joe/
rrdata.rs

1use std::net::{Ipv4Addr, Ipv6Addr};
2
3use byteorder::{BigEndian, ByteOrder};
4
5use {Name, Type, Error, SoaRecord};
6use std::str;
7
8/// The enumeration that represents known types of DNS resource records data
9#[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    // Anything that can't be parsed yet
21    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}