retina_core/protocols/stream/dns/
parser.rs1use super::transaction::{DnsQuery, DnsResponse};
12use super::Dns;
13use crate::conntrack::conn::conn_info::ConnState;
14use crate::conntrack::pdu::L4Pdu;
15use crate::protocols::stream::{ConnParsable, ParseResult, ProbeResult, Session, SessionData};
16
17use std::collections::HashMap;
18
19#[derive(Default, Debug)]
20pub struct DnsParser {
21 sessions: HashMap<usize, Dns>,
23 cnt: usize,
25}
26
27impl ConnParsable for DnsParser {
28 fn parse(&mut self, pdu: &L4Pdu) -> ParseResult {
29 let offset = pdu.offset();
30 let length = pdu.length();
31 if length == 0 {
32 return ParseResult::Skipped;
33 }
34
35 if let Ok(data) = (pdu.mbuf_ref()).get_data_slice(offset, length) {
36 self.process(data)
37 } else {
38 log::warn!("Malformed packet");
39 ParseResult::Skipped
40 }
41 }
42
43 fn probe(&self, pdu: &L4Pdu) -> ProbeResult {
44 let dst_port = pdu.ctxt.dst.port();
45 let src_port = pdu.ctxt.src.port();
46 if src_port == 137 || dst_port == 137 {
47 return ProbeResult::NotForUs;
49 }
50 let offset = pdu.offset();
51 let length = pdu.length();
52 if pdu.length() == 0 {
53 return ProbeResult::Unsure;
54 }
55
56 if let Ok(data) = (pdu.mbuf).get_data_slice(offset, length) {
57 match dns_parser::Packet::parse(data) {
58 Ok(packet) => {
59 if packet.header.query {
60 if packet.questions.is_empty() {
61 return ProbeResult::NotForUs;
62 }
63 } else if packet.answers.is_empty() {
64 return ProbeResult::NotForUs;
65 }
66 ProbeResult::Certain
67 }
68 _ => ProbeResult::NotForUs,
69 }
70 } else {
71 log::warn!("Malformed packet");
72 ProbeResult::Error
73 }
74 }
75
76 fn remove_session(&mut self, session_id: usize) -> Option<Session> {
77 self.sessions.remove(&session_id).map(|dns| Session {
78 data: SessionData::Dns(Box::new(dns)),
79 id: session_id,
80 })
81 }
82
83 fn drain_sessions(&mut self) -> Vec<Session> {
84 self.sessions
85 .drain()
86 .map(|(session_id, dns)| Session {
87 data: SessionData::Dns(Box::new(dns)),
88 id: session_id,
89 })
90 .collect()
91 }
92
93 fn session_match_state(&self) -> ConnState {
94 ConnState::Parsing
95 }
96
97 fn session_nomatch_state(&self) -> ConnState {
98 ConnState::Parsing
99 }
100}
101
102impl DnsParser {
103 pub(crate) fn process(&mut self, data: &[u8]) -> ParseResult {
104 match dns_parser::Packet::parse(data) {
105 Ok(pkt) => {
106 if pkt.header.query {
107 log::debug!("DNS query");
108 let query = DnsQuery::parse_query(&pkt);
109 let query_id = pkt.header.id;
110 for (session_id, dns) in self.sessions.iter_mut() {
111 if query_id == dns.transaction_id {
112 if dns.response.is_some() {
113 dns.query = Some(query);
114 return ParseResult::Done(*session_id);
115 }
116 break;
117 }
118 }
119 let dns = Dns {
120 transaction_id: query_id,
121 query: Some(query),
122 response: None,
123 };
124 let session_id = self.cnt;
125 self.cnt += 1;
126 self.sessions.insert(session_id, dns);
127 ParseResult::Continue(session_id)
128 } else {
129 log::debug!("DNS answer");
130 let response = DnsResponse::parse_response(&pkt);
131 let answer_id = pkt.header.id;
132 for (session_id, dns) in self.sessions.iter_mut() {
133 if answer_id == dns.transaction_id {
134 if dns.query.is_some() {
135 dns.response = Some(response);
136 return ParseResult::Done(*session_id);
137 }
138 break;
139 }
140 }
141 let dns = Dns {
142 transaction_id: answer_id,
143 query: None,
144 response: Some(response),
145 };
146 let session_id = self.cnt;
147 self.cnt += 1;
148 self.sessions.insert(session_id, dns);
149 ParseResult::Continue(session_id)
150 }
151 }
152 e => {
153 log::debug!("parse error: {:?}", e);
154 ParseResult::Skipped
155 }
156 }
157 }
158}