dns_parser/rdata/
txt.rs

1use Error;
2
3#[derive(Debug, Clone)]
4pub struct Record<'a> {
5    bytes: &'a [u8],
6}
7
8#[derive(Debug)]
9pub struct RecordIter<'a> {
10    bytes: &'a [u8],
11}
12
13impl<'a> Iterator for RecordIter<'a> {
14    type Item = &'a [u8];
15    fn next(&mut self) -> Option<&'a [u8]> {
16        if self.bytes.len() >= 1 {
17            let len = self.bytes[0] as usize;
18            debug_assert!(self.bytes.len() >= len+1);
19            let (head, tail) = self.bytes[1..].split_at(len);
20            self.bytes = tail;
21            return Some(head);
22        }
23        return None;
24    }
25}
26
27impl<'a> Record<'a> {
28
29    // Returns iterator over text chunks
30    pub fn iter(&self) -> RecordIter<'a> {
31        RecordIter {
32            bytes: self.bytes,
33        }
34    }
35}
36
37impl<'a> super::Record<'a> for Record<'a> {
38
39    const TYPE: isize = 16;
40
41    fn parse(rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
42        // Just a quick check that record is valid
43        let len = rdata.len();
44        if len < 1 {
45            return Err(Error::WrongRdataLength);
46        }
47        let mut pos = 0;
48        while pos < len {
49            let rdlen = rdata[pos] as usize;
50            pos += 1;
51            if len < rdlen + pos {
52                return Err(Error::WrongRdataLength);
53            }
54            pos += rdlen;
55        }
56        Ok(super::RData::TXT(Record {
57            bytes: rdata,
58        }))
59    }
60}
61
62#[cfg(test)]
63mod test {
64
65    use std::str::from_utf8;
66
67    use {Packet, Header};
68    use Opcode::*;
69    use ResponseCode::NoError;
70    use QueryType as QT;
71    use QueryClass as QC;
72    use Class as C;
73    use RData;
74
75    #[test]
76    fn parse_response_multiple_strings() {
77        let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
78                          \x08facebook\x03com\x00\x00\x10\x00\x01\
79                          \xc0\x0c\x00\x10\x00\x01\x00\x01\x51\x3d\x00\x23\
80                          \x15\x76\x3d\x73\x70\x66\x31\x20\x72\x65\x64\x69\
81                          \x72\x65\x63\x74\x3d\x5f\x73\x70\x66\x2e\
82                          \x0c\x66\x61\x63\x65\x62\x6f\x6f\x6b\x2e\x63\x6f\x6d";
83
84        let packet = Packet::parse(response).unwrap();
85        assert_eq!(packet.header, Header {
86            id: 1573,
87            query: false,
88            opcode: StandardQuery,
89            authoritative: false,
90            truncated: false,
91            recursion_desired: true,
92            recursion_available: true,
93            authenticated_data: false,
94            checking_disabled: false,
95            response_code: NoError,
96            questions: 1,
97            answers: 1,
98            nameservers: 0,
99            additional: 0,
100        });
101        assert_eq!(packet.questions.len(), 1);
102        assert_eq!(packet.questions[0].qtype, QT::TXT);
103        assert_eq!(packet.questions[0].qclass, QC::IN);
104        assert_eq!(&packet.questions[0].qname.to_string()[..], "facebook.com");
105        assert_eq!(packet.answers.len(), 1);
106        assert_eq!(&packet.answers[0].name.to_string()[..], "facebook.com");
107        assert_eq!(packet.answers[0].multicast_unique, false);
108        assert_eq!(packet.answers[0].cls, C::IN);
109        assert_eq!(packet.answers[0].ttl, 86333);
110        match packet.answers[0].data {
111            RData::TXT(ref text) => {
112                assert_eq!(text.iter()
113                    .map(|x| from_utf8(x).unwrap())
114                    .collect::<Vec<_>>()
115                    .concat(), "v=spf1 redirect=_spf.facebook.com");
116
117                // also assert boundaries are kept
118                assert_eq!(text.iter().collect::<Vec<_>>(),
119                    ["v=spf1 redirect=_spf.".as_bytes(),
120                     "facebook.com".as_bytes()]);
121            }
122            ref x => panic!("Wrong rdata {:?}", x),
123        }
124    }
125}