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
128
129
130
131
132
133
pub mod dns_header;
pub mod dns_question;
pub mod dns_resource_record;
use crate::domain_name::*;
use crate::{classes::*, *};
use dns_header::*;
use dns_question::*;
use dns_resource_record::*;
use std::collections::HashMap;
#[derive(Debug)]
pub struct DnsPacket {
pub header: DnsHeader,
pub question: Vec<DnsQuestion>,
pub answer: Vec<DnsResourceRecord>,
pub authority: Vec<DnsResourceRecord>,
pub additional: Vec<DnsResourceRecord>,
}
impl DnsPacket {
pub fn new(domain_name: &String, resource_record_type: u16) -> Result<DnsPacket, String> {
let mut header = DnsHeader::new()?;
let domain_name = normalize_domain_name(domain_name);
if !is_domain_name_valid(&domain_name) {
return Err(format!("invalid domain name: {}", domain_name));
}
let question = vec![DnsQuestion {
qname: domain_name,
qtype: resource_record_type,
qclass: DNS_CLASS_IN,
}];
header.qdcount = 1;
let dns_packet = DnsPacket {
header,
question,
answer: Vec::new(),
authority: Vec::new(),
additional: Vec::new(),
};
Ok(dns_packet)
}
pub fn parse_dns_packet(dns_packet_buf: &Vec<u8>) -> Result<DnsPacket, String> {
let header = DnsHeader::parse(dns_packet_buf)?;
let start = DNS_HEADER_SIZE;
let (questions, start) = DnsQuestion::parse_questions(dns_packet_buf, &header, start)?;
let (answers, start) =
DnsResourceRecord::parse_resource_records(dns_packet_buf, start, header.ancount)?;
let (authorities, start) =
DnsResourceRecord::parse_resource_records(dns_packet_buf, start, header.nscount)?;
let (additionals, _) =
DnsResourceRecord::parse_resource_records(dns_packet_buf, start, header.arcount)?;
let dns_packet: DnsPacket = DnsPacket {
header,
question: questions,
answer: answers,
authority: authorities,
additional: additionals,
};
Ok(dns_packet)
}
pub fn serialize(&self) -> Result<Vec<u8>, String> {
let mut buf = Vec::new();
let mut domain_name_offsets = HashMap::new();
buf.append(&mut self.header.serialize());
let mut curr_index = DNS_HEADER_SIZE;
for question in &self.question {
curr_index = question.serialize(curr_index, &mut buf, &mut domain_name_offsets)?;
}
for resource_record in &self.answer {
curr_index =
resource_record.serialize(curr_index, &mut buf, &mut domain_name_offsets)?;
}
for resource_record in &self.authority {
curr_index =
resource_record.serialize(curr_index, &mut buf, &mut domain_name_offsets)?;
}
for resource_record in &self.additional {
resource_record.serialize(curr_index, &mut buf, &mut domain_name_offsets)?;
}
Ok(buf)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::query_examples::*;
#[test]
fn test_serialize() -> Result<(), String> {
let query = Vec::from(NAME_COMPRESSION_QUERY);
let dns_packet = DnsPacket::parse_dns_packet(&query)?;
let res = dns_packet.serialize()?;
assert_eq!(query, res, "\nquery: {:02X?}\nres: {:02X?}", query, res);
Ok(())
}
}