1use crate::error::HuginnNetHttpError;
2use crate::output::{
3 Browser, BrowserQualityMatched, HttpRequestOutput, HttpResponseOutput, IpPort, WebServer,
4 WebServerQualityMatched,
5};
6use crate::{http_process, HttpAnalysisResult, SignatureMatcher};
7use huginn_net_db::http::HttpDiagnosis;
8use pnet::packet::ipv4::Ipv4Packet;
9use pnet::packet::ipv6::Ipv6Packet;
10use pnet::packet::tcp::TcpPacket;
11use pnet::packet::Packet;
12use std::net::IpAddr;
13use ttl_cache::TtlCache;
14
15pub struct ObservablePackage {
16 pub source: IpPort,
17 pub destination: IpPort,
18 pub http_result: HttpAnalysisResult,
19}
20
21pub fn process_ipv4_packet(
23 ipv4: &Ipv4Packet,
24 http_flows: &mut TtlCache<http_process::FlowKey, http_process::TcpFlow>,
25 http_processors: &http_process::HttpProcessors,
26 matcher: Option<&SignatureMatcher>,
27) -> Result<HttpAnalysisResult, HuginnNetHttpError> {
28 let observable_package =
29 create_observable_package_ipv4(ipv4, http_flows, http_processors, matcher)?;
30 Ok(observable_package.http_result)
31}
32
33fn create_observable_package_ipv4(
34 ipv4: &Ipv4Packet,
35 http_flows: &mut TtlCache<http_process::FlowKey, http_process::TcpFlow>,
36 http_processors: &http_process::HttpProcessors,
37 matcher: Option<&SignatureMatcher>,
38) -> Result<ObservablePackage, HuginnNetHttpError> {
39 let tcp = TcpPacket::new(ipv4.payload())
40 .ok_or_else(|| HuginnNetHttpError::Parse("Invalid TCP packet".to_string()))?;
41
42 let source = IpPort {
43 ip: IpAddr::V4(ipv4.get_source()),
44 port: tcp.get_source(),
45 };
46 let destination = IpPort {
47 ip: IpAddr::V4(ipv4.get_destination()),
48 port: tcp.get_destination(),
49 };
50
51 let http_package = http_process::process_http_ipv4(ipv4, http_flows, http_processors)?;
52
53 let mut http_result = HttpAnalysisResult {
54 http_request: None,
55 http_response: None,
56 };
57
58 if let Some(http_request) = http_package.http_request {
59 let browser_quality = if let Some(matcher) = matcher {
60 if let Some((label, _signature, quality)) =
61 matcher.matching_by_http_request(&http_request)
62 {
63 BrowserQualityMatched {
64 browser: Some(Browser::from(label)),
65 quality: huginn_net_db::utils::MatchQualityType::Matched(quality),
66 }
67 } else {
68 BrowserQualityMatched {
69 browser: None,
70 quality: huginn_net_db::utils::MatchQualityType::NotMatched,
71 }
72 }
73 } else {
74 BrowserQualityMatched {
75 browser: None,
76 quality: huginn_net_db::utils::MatchQualityType::Disabled,
77 }
78 };
79
80 let user_agent = http_request.user_agent.clone();
81 let (signature_matcher, ua_matcher) = if let Some(matcher) = matcher {
82 let sig_match = matcher.matching_by_http_request(&http_request);
83 let ua_match = user_agent
84 .as_ref()
85 .and_then(|ua| matcher.matching_by_user_agent(ua.clone()));
86 (sig_match, ua_match)
87 } else {
88 (None, None)
89 };
90
91 let diagnosis = crate::http_common::get_diagnostic(
92 user_agent,
93 ua_matcher,
94 signature_matcher.map(|(label, _signature, _quality)| label),
95 );
96
97 let request_output = HttpRequestOutput {
98 source: IpPort::new(std::net::IpAddr::V4(ipv4.get_source()), tcp.get_source()),
99 destination: IpPort::new(
100 std::net::IpAddr::V4(ipv4.get_destination()),
101 tcp.get_destination(),
102 ),
103 lang: http_request.lang.clone(),
104 diagnosis,
105 browser_matched: browser_quality,
106 sig: http_request,
107 };
108 http_result.http_request = Some(request_output);
109 }
110
111 if let Some(http_response) = http_package.http_response {
112 let web_server_quality = if let Some(matcher) = matcher {
113 if let Some((label, _signature, quality)) =
114 matcher.matching_by_http_response(&http_response)
115 {
116 WebServerQualityMatched {
117 web_server: Some(WebServer::from(label)),
118 quality: huginn_net_db::utils::MatchQualityType::Matched(quality),
119 }
120 } else {
121 WebServerQualityMatched {
122 web_server: None,
123 quality: huginn_net_db::utils::MatchQualityType::NotMatched,
124 }
125 }
126 } else {
127 WebServerQualityMatched {
128 web_server: None,
129 quality: huginn_net_db::utils::MatchQualityType::Disabled,
130 }
131 };
132
133 let response_output = HttpResponseOutput {
134 source: IpPort::new(std::net::IpAddr::V4(ipv4.get_source()), tcp.get_source()),
135 destination: IpPort::new(
136 std::net::IpAddr::V4(ipv4.get_destination()),
137 tcp.get_destination(),
138 ),
139 diagnosis: HttpDiagnosis::None, web_server_matched: web_server_quality,
141 sig: http_response,
142 };
143 http_result.http_response = Some(response_output);
144 }
145
146 Ok(ObservablePackage {
147 source,
148 destination,
149 http_result,
150 })
151}
152
153pub fn process_ipv6_packet(
155 ipv6: &Ipv6Packet,
156 http_flows: &mut TtlCache<http_process::FlowKey, http_process::TcpFlow>,
157 http_processors: &http_process::HttpProcessors,
158 matcher: Option<&SignatureMatcher>,
159) -> Result<HttpAnalysisResult, HuginnNetHttpError> {
160 let observable_package =
161 create_observable_package_ipv6(ipv6, http_flows, http_processors, matcher)?;
162 Ok(observable_package.http_result)
163}
164
165fn create_observable_package_ipv6(
166 ipv6: &Ipv6Packet,
167 http_flows: &mut TtlCache<http_process::FlowKey, http_process::TcpFlow>,
168 http_processors: &http_process::HttpProcessors,
169 matcher: Option<&SignatureMatcher>,
170) -> Result<ObservablePackage, HuginnNetHttpError> {
171 let tcp = TcpPacket::new(ipv6.payload())
173 .ok_or_else(|| HuginnNetHttpError::Parse("Invalid TCP packet".to_string()))?;
174
175 let source = IpPort {
176 ip: IpAddr::V6(ipv6.get_source()),
177 port: tcp.get_source(),
178 };
179 let destination = IpPort {
180 ip: IpAddr::V6(ipv6.get_destination()),
181 port: tcp.get_destination(),
182 };
183
184 let http_package = http_process::process_http_ipv6(ipv6, http_flows, http_processors)?;
185
186 let mut http_result = HttpAnalysisResult {
187 http_request: None,
188 http_response: None,
189 };
190
191 if let Some(http_request) = http_package.http_request {
193 let browser_quality = if let Some(matcher) = matcher {
194 if let Some((label, _signature, quality)) =
195 matcher.matching_by_http_request(&http_request)
196 {
197 BrowserQualityMatched {
198 browser: Some(Browser::from(label)),
199 quality: huginn_net_db::utils::MatchQualityType::Matched(quality),
200 }
201 } else {
202 BrowserQualityMatched {
203 browser: None,
204 quality: huginn_net_db::utils::MatchQualityType::NotMatched,
205 }
206 }
207 } else {
208 BrowserQualityMatched {
209 browser: None,
210 quality: huginn_net_db::utils::MatchQualityType::Disabled,
211 }
212 };
213
214 let user_agent = http_request.user_agent.clone();
215 let (signature_matcher, ua_matcher) = if let Some(matcher) = matcher {
216 let sig_match = matcher.matching_by_http_request(&http_request);
217 let ua_match = user_agent
218 .as_ref()
219 .and_then(|ua| matcher.matching_by_user_agent(ua.clone()));
220 (sig_match, ua_match)
221 } else {
222 (None, None)
223 };
224
225 let diagnosis = crate::http_common::get_diagnostic(
226 user_agent,
227 ua_matcher,
228 signature_matcher.map(|(label, _signature, _quality)| label),
229 );
230
231 let request_output = HttpRequestOutput {
232 source: IpPort::new(std::net::IpAddr::V6(ipv6.get_source()), tcp.get_source()),
233 destination: IpPort::new(
234 std::net::IpAddr::V6(ipv6.get_destination()),
235 tcp.get_destination(),
236 ),
237 lang: http_request.lang.clone(),
238 diagnosis,
239 browser_matched: browser_quality,
240 sig: http_request,
241 };
242 http_result.http_request = Some(request_output);
243 }
244
245 if let Some(http_response) = http_package.http_response {
247 let web_server_quality = if let Some(matcher) = matcher {
248 if let Some((label, _signature, quality)) =
249 matcher.matching_by_http_response(&http_response)
250 {
251 WebServerQualityMatched {
252 web_server: Some(WebServer::from(label)),
253 quality: huginn_net_db::utils::MatchQualityType::Matched(quality),
254 }
255 } else {
256 WebServerQualityMatched {
257 web_server: None,
258 quality: huginn_net_db::utils::MatchQualityType::NotMatched,
259 }
260 }
261 } else {
262 WebServerQualityMatched {
263 web_server: None,
264 quality: huginn_net_db::utils::MatchQualityType::Disabled,
265 }
266 };
267
268 let response_output = HttpResponseOutput {
269 source: IpPort::new(std::net::IpAddr::V6(ipv6.get_source()), tcp.get_source()),
270 destination: IpPort::new(
271 std::net::IpAddr::V6(ipv6.get_destination()),
272 tcp.get_destination(),
273 ),
274 diagnosis: HttpDiagnosis::None, web_server_matched: web_server_quality,
276 sig: http_response,
277 };
278 http_result.http_response = Some(response_output);
279 }
280
281 Ok(ObservablePackage {
282 source,
283 destination,
284 http_result,
285 })
286}