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
use super::{dns_header::*, domain_name::*};
use std::collections::HashMap;
#[derive(Debug)]
pub struct DnsQuestion {
pub qname: String,
pub qtype: u16,
pub qclass: u16,
}
impl DnsQuestion {
pub fn parse_dns_question(
dns_packet_buf: &Vec<u8>,
start: usize,
) -> Result<(DnsQuestion, usize), String> {
let (qname, end) = parse_domain_name(dns_packet_buf, start, dns_packet_buf.len())?;
if end + 3 >= dns_packet_buf.len()
{
return Err("question too short".into());
}
let qtype: u16 = (dns_packet_buf[end] as u16) << 8 | dns_packet_buf[end + 1] as u16;
let qclass: u16 = (dns_packet_buf[end + 2] as u16) << 8 | dns_packet_buf[end + 3] as u16;
let dns_question: DnsQuestion = DnsQuestion {
qname,
qtype,
qclass,
};
Ok((dns_question, end + 4))
}
pub fn parse_questions(
dns_packet_buf: &Vec<u8>,
header: &DnsHeader,
mut start: usize,
) -> Result<(Vec<DnsQuestion>, usize), String> {
let mut questions: Vec<DnsQuestion> = Vec::new();
for _ in 0..header.qdcount {
let (question, end) = DnsQuestion::parse_dns_question(dns_packet_buf, start)?;
start = end;
questions.push(question);
}
Ok((questions, start))
}
pub fn serialize(
&self,
start: usize,
buf: &mut Vec<u8>,
domain_name_offsets: &mut HashMap<String, u16>,
) -> Result<usize, String> {
serialize_domain_name(&self.qname, buf, domain_name_offsets)?;
buf.push(((self.qtype >> 8) & 0xFF) as u8);
buf.push((self.qtype & 0xFF) as u8);
buf.push(((self.qclass >> 8) & 0xFF) as u8);
buf.push((self.qclass & 0xFF) as u8);
let start = start + buf.len();
Ok(start)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{classes::*, query_examples::*, types::*, DNS_HEADER_SIZE};
#[test]
fn test_parse_questions() -> Result<(), String> {
let correct_domain_name = String::from("www.google.com.");
let query = &Vec::from(BASIC_QUERY);
let header = DnsHeader::parse(query)?;
let (questions, end) = DnsQuestion::parse_questions(query, &header, DNS_HEADER_SIZE)?;
assert_eq!(questions.len(), 1);
assert_eq!(end, 32);
let question = &questions[0];
assert_eq!(question.qname, correct_domain_name);
assert_eq!(question.qtype, DNS_TYPE_A);
assert_eq!(question.qclass, DNS_CLASS_IN);
let query = &Vec::from(NAME_COMPRESSION_QUERY);
let header = DnsHeader::parse(query)?;
let (questions, end) = DnsQuestion::parse_questions(query, &header, DNS_HEADER_SIZE)?;
assert_eq!(questions.len(), 2);
assert_eq!(end, query.len());
let question = &questions[0];
assert_eq!(question.qname, correct_domain_name);
assert_eq!(question.qtype, DNS_TYPE_A);
assert_eq!(question.qclass, DNS_CLASS_IN);
let correct_domain_name = String::from("pointer.www.google.com.");
let question = &questions[1];
assert_eq!(question.qname, correct_domain_name);
assert_eq!(question.qtype, DNS_TYPE_NS);
assert_eq!(question.qclass, DNS_CLASS_CH);
Ok(())
}
}