1#[allow(dead_code)]
4extern crate serde;
5extern crate serde_xml_rs;
6use std::fs;
7
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Deserialize, PartialEq, Serialize)]
11#[allow(non_camel_case_types)]
12pub struct nmap_run {
13 #[serde(skip_serializing_if = "Option::is_none")]
14 pub scanner: Option<String>,
15 #[serde(skip_serializing_if = "Option::is_none")]
16 pub args: Option<String>,
17 #[serde(skip_serializing_if = "Option::is_none")]
18 pub start: Option<i32>,
19 #[serde(skip_serializing_if = "Option::is_none")]
20 pub startstr: Option<String>,
21 #[serde(skip_serializing_if = "Option::is_none")]
22 pub version: Option<String>,
23 #[serde(skip_serializing_if = "Option::is_none")]
24 pub xmloutputversion: Option<String>,
25 #[serde(skip_serializing_if = "Option::is_none")]
26 pub profile_name: Option<String>,
27 #[serde(skip_serializing_if = "Option::is_none")]
28 pub scaninfo: Option<scaninfo>,
29 #[serde(skip_serializing_if = "Option::is_none")]
30 pub verbose: Option<verbose>,
31 #[serde(skip_serializing_if = "Option::is_none")]
32 pub debugging: Option<debugging>,
33 #[serde(skip_serializing_if = "Option::is_none")]
41 pub prescript: Option<prescript>,
42 #[serde(skip_serializing_if = "Option::is_none")]
46 pub postscript: Option<postscript>,
47 #[serde(skip_serializing_if = "Option::is_none")]
51 pub host: Option<Vec<host>>,
52 #[serde(skip_serializing_if = "Option::is_none")]
53 pub target: Option<Vec<target>>,
54 #[serde(skip_serializing_if = "Option::is_none")]
55 pub runstats: Option<runstats>,
56}
57
58
59
60#[derive(Debug, Deserialize, PartialEq, Serialize)]
61#[allow(non_camel_case_types)]
62pub struct prescript {
63 #[serde(skip_serializing_if = "Option::is_none")]
64 pub script: Option<Vec<script>>
65}
66
67#[derive(Debug, Deserialize, PartialEq, Serialize)]
68#[allow(non_camel_case_types)]
69pub struct postscript {
70 #[serde(skip_serializing_if = "Option::is_none")]
71 pub script: Option<Vec<script>>
72}
73
74#[derive(Debug, Deserialize, PartialEq, Serialize)]
75#[allow(non_camel_case_types)]
76pub struct scaninfo {
77 #[serde(skip_serializing_if = "Option::is_none")]
78 pub r#type: Option<String>,
79 #[serde(skip_serializing_if = "Option::is_none")]
80 pub protocol: Option<String>,
81 #[serde(skip_serializing_if = "Option::is_none")]
82 pub numservices: Option<u32>,
83 #[serde(skip_serializing_if = "Option::is_none")]
84 pub services: Option<String>,
85 #[serde(skip_serializing_if = "Option::is_none")]
86 pub scanflags: Option<String>,
87}
88
89#[derive(Debug, Deserialize, PartialEq, Serialize)]
90#[allow(non_camel_case_types)]
91pub struct verbose {
92 #[serde(skip_serializing_if = "Option::is_none")]
93 pub level: Option<u32>,
94}
95#[derive(Debug, Deserialize, Serialize, PartialEq)]
96#[allow(non_camel_case_types)]
97pub struct debugging {
98 #[serde(skip_serializing_if = "Option::is_none")]
99 pub level: Option<u32>,
100}
101
102#[derive(Debug, Deserialize, Serialize, PartialEq)]
103#[allow(non_camel_case_types)]
104pub struct task_info {
105 #[serde(skip_serializing_if = "Option::is_none")]
106 pub task: Option<String>,
107 #[serde(skip_serializing_if = "Option::is_none")]
108 pub time: Option<i32>,
109 #[serde(skip_serializing_if = "Option::is_none")]
110 pub extrainfo: Option<String>,
111}
112
113#[derive(Debug, Deserialize, Serialize, PartialEq)]
114#[allow(non_camel_case_types)]
115pub struct task_progress_info {
116 #[serde(skip_serializing_if = "Option::is_none")]
117 pub task: Option<String>,
118 #[serde(skip_serializing_if = "Option::is_none")]
119 pub time: Option<i32>,
120 #[serde(skip_serializing_if = "Option::is_none")]
121 pub percent: Option<f32>,
122 #[serde(skip_serializing_if = "Option::is_none")]
123 pub remaining: Option<u32>,
124 #[serde(skip_serializing_if = "Option::is_none")]
125 pub etc: Option<u32>,
126}
127
128#[derive(Debug, Deserialize, Serialize, PartialEq)]
129#[allow(non_camel_case_types)]
130pub struct script {
131 #[serde(skip_serializing_if = "Option::is_none")]
132 pub id: Option<String>,
133 #[serde(skip_serializing_if = "Option::is_none")]
134 pub output: Option<String>,
135 #[serde(skip_serializing_if = "Option::is_none")]
136 pub table: Option<Vec<table>>,
137 #[serde(skip_serializing_if = "Option::is_none")]
138 pub elem: Option<Vec<element>>,
139}
140
141#[derive(Debug, Deserialize, Serialize, PartialEq)]
142#[allow(non_camel_case_types)]
143pub struct table {
144 #[serde(skip_serializing_if = "Option::is_none")]
145 pub key: Option<String>,
146 #[serde(skip_serializing_if = "Option::is_none")]
147 pub elem: Option<Vec<element>>,
148 #[serde(skip_serializing_if = "Option::is_none")]
149 pub table: Option<Vec<table>>,
150}
151
152#[derive(Debug, Deserialize, Serialize, PartialEq)]
153#[allow(non_camel_case_types)]
154pub struct element {
155 #[serde(skip_serializing_if = "Option::is_none")]
156 pub key: Option<String>,
157 #[serde(skip_serializing_if = "Option::is_none")]
158 #[serde(rename = "$value")]
159 pub value: Option<String>,
160}
161
162#[derive(Debug, Deserialize, Serialize, PartialEq)]
163#[allow(non_camel_case_types)]
164pub struct host {
165 #[serde(skip_serializing_if = "Option::is_none")]
166 pub starttime: Option<i32>,
167 #[serde(skip_serializing_if = "Option::is_none")]
168 pub endtime: Option<i32>,
169 #[serde(skip_serializing_if = "Option::is_none")]
170 pub comment: Option<String>,
171 #[serde(skip_serializing_if = "Option::is_none")]
172 pub status: Option<status>,
173 #[serde(skip_serializing_if = "Option::is_none")]
174 pub address: Option<Vec<address>>,
175 #[serde(skip_serializing_if = "Option::is_none")]
176 pub hostnames: Option<hostnames>,
177 #[serde(skip_serializing_if = "Option::is_none")]
180 pub smurf: Option<Vec<smurf>>,
181 #[serde(skip_serializing_if = "Option::is_none")]
182 pub ports: Option<ports2>,
183 #[serde(skip_serializing_if = "Option::is_none")]
191 pub os: Option<os>,
192 #[serde(skip_serializing_if = "Option::is_none")]
193 pub distance: Option<distance>,
194 #[serde(skip_serializing_if = "Option::is_none")]
195 pub uptime: Option<uptime>,
196 #[serde(skip_serializing_if = "Option::is_none")]
197 pub ipidsequence: Option<ipidsequence>,
198 #[serde(skip_serializing_if = "Option::is_none")]
199 pub tcptssequence: Option<tcptssequence>,
200 #[serde(skip_serializing_if = "Option::is_none")]
201 pub hostscript: Option<hostscript>,
202 #[serde(skip_serializing_if = "Option::is_none")]
205 pub trace: Option<trace>,
206 #[serde(skip_serializing_if = "Option::is_none")]
207 pub times: Option<times>,
208}
209
210#[derive(Debug, Deserialize, Serialize, PartialEq)]
211#[allow(non_camel_case_types)]
212pub struct hostscript {
213 #[serde(skip_serializing_if = "Option::is_none")]
214 pub script: Option<script>,
215}
216
217#[derive(Debug, Deserialize, Serialize, PartialEq)]
218#[allow(non_camel_case_types)]
219pub struct hostnames {
220 #[serde(skip_serializing_if = "Option::is_none")]
221 pub hostname: Option<Vec<hostname>>,
222}
223
224#[derive(Debug, Deserialize, Serialize, PartialEq)]
225#[allow(non_camel_case_types)]
226pub struct ports2 {
227 #[serde(skip_serializing_if = "Option::is_none")]
228 pub port: Option<Vec<port>>,
229 #[serde(skip_serializing_if = "Option::is_none")]
230 pub extraports: Option<Vec<extraports>>,
231}
232
233#[derive(Debug, Deserialize, Serialize, PartialEq)]
234#[allow(non_camel_case_types)]
235pub struct times {
236 #[serde(skip_serializing_if = "Option::is_none")]
237 pub srtt: Option<String>,
238 #[serde(skip_serializing_if = "Option::is_none")]
239 pub rttvar: Option<String>,
240 #[serde(skip_serializing_if = "Option::is_none")]
241 pub to: Option<String>,
242}
243
244#[derive(Debug, Deserialize, Serialize, PartialEq)]
245#[allow(non_camel_case_types)]
246pub struct trace {
247 #[serde(skip_serializing_if = "Option::is_none")]
248 pub proto: Option<String>,
249 #[serde(skip_serializing_if = "Option::is_none")]
250 pub port: Option<u32>,
251 #[serde(skip_serializing_if = "Option::is_none")]
252 #[serde(rename = "hop")]
253 pub hops: Option<Vec<hop>>,
254}
255
256#[derive(Debug, Deserialize, Serialize, PartialEq)]
257#[allow(non_camel_case_types)]
258pub struct hop {
259 #[serde(skip_serializing_if = "Option::is_none")]
260 pub ttl: Option<f32>,
261 #[serde(skip_serializing_if = "Option::is_none")]
262 pub rtt: Option<f32>,
263 #[serde(skip_serializing_if = "Option::is_none")]
264 pub ipaddr: Option<String>,
265 #[serde(skip_serializing_if = "Option::is_none")]
266 pub host: Option<String>,
267}
268
269#[derive(Debug, Deserialize, Serialize, PartialEq)]
270#[allow(non_camel_case_types)]
271pub struct tcptssequence {
272 #[serde(skip_serializing_if = "Option::is_none")]
273 pub class: Option<String>,
274 #[serde(skip_serializing_if = "Option::is_none")]
275 pub values: Option<String>,
276}
277
278#[derive(Debug, Deserialize, Serialize, PartialEq)]
279#[allow(non_camel_case_types)]
280pub struct ipidsequence {
281 #[serde(skip_serializing_if = "Option::is_none")]
282 pub class: Option<String>,
283 #[serde(skip_serializing_if = "Option::is_none")]
284 pub values: Option<String>,
285}
286
287#[derive(Debug, Deserialize, Serialize, PartialEq)]
288#[allow(non_camel_case_types)]
289pub struct uptime {
290 #[serde(skip_serializing_if = "Option::is_none")]
291 pub seconds: Option<u32>,
292 #[serde(skip_serializing_if = "Option::is_none")]
293 pub lastboot: Option<String>,
294}
295
296#[derive(Debug, Deserialize, Serialize, PartialEq)]
297#[allow(non_camel_case_types)]
298pub struct distance {
299 #[serde(skip_serializing_if = "Option::is_none")]
300 pub value: Option<i32>,
301}
302
303#[derive(Debug, Deserialize, Serialize, PartialEq)]
304#[allow(non_camel_case_types)]
305pub struct os {
306 #[serde(skip_serializing_if = "Option::is_none")]
307 pub portused: Option<Vec<portused>>,
308 #[serde(skip_serializing_if = "Option::is_none")]
309 pub osmatch: Option<Vec<osmatch>>,
310 #[serde(skip_serializing_if = "Option::is_none")]
311 pub osfingerprint: Option<Vec<osfingerprint>>,
312}
313
314#[derive(Debug, Deserialize, Serialize, PartialEq)]
315#[allow(non_camel_case_types)]
316pub struct portused {
317 #[serde(skip_serializing_if = "Option::is_none")]
318 pub state: Option<String>,
319 #[serde(skip_serializing_if = "Option::is_none")]
320 pub proto: Option<String>,
321 #[serde(skip_serializing_if = "Option::is_none")]
322 pub portid: Option<u32>,
323}
324
325#[derive(Debug, Deserialize, Serialize, PartialEq)]
326#[allow(non_camel_case_types)]
327pub struct osmatch {
328 #[serde(skip_serializing_if = "Option::is_none")]
329 pub name: Option<String>,
330 #[serde(skip_serializing_if = "Option::is_none")]
331 pub accuracy: Option<u32>,
332 #[serde(skip_serializing_if = "Option::is_none")]
333 pub line: Option<u32>,
334 #[serde(skip_serializing_if = "Option::is_none")]
335 pub osclass: Option<Vec<osclass>>,
336}
337
338#[derive(Debug, Deserialize, Serialize, PartialEq)]
339#[allow(non_camel_case_types)]
340pub struct osclass {
341 #[serde(skip_serializing_if = "Option::is_none")]
342 pub vendor: Option<String>,
343 #[serde(skip_serializing_if = "Option::is_none")]
344 pub osgen: Option<String>,
345 #[serde(skip_serializing_if = "Option::is_none")]
346 pub r#type: Option<String>,
347 #[serde(skip_serializing_if = "Option::is_none")]
348 pub accuracy: Option<u32>,
349 #[serde(skip_serializing_if = "Option::is_none")]
350 pub osfamily: Option<String>,
351 #[serde(skip_serializing_if = "Option::is_none")]
352 #[serde(rename = "cpe")]
353 pub cpe: Option<String>,
354 }
356
357#[derive(Debug, Deserialize, Serialize, PartialEq)]
358#[allow(non_camel_case_types)]
359pub struct osfingerprint {
360 #[serde(skip_serializing_if = "Option::is_none")]
361 pub fingerprint: Option<String>,
362}
363
364#[derive(Debug, Deserialize, Serialize, PartialEq)]
365#[allow(non_camel_case_types)]
366pub struct extraports {
367 #[serde(skip_serializing_if = "Option::is_none")]
368 pub state: Option<String>,
369 #[serde(skip_serializing_if = "Option::is_none")]
370 pub count: Option<u32>,
371 #[serde(skip_serializing_if = "Option::is_none")]
372 pub extrareasons: Option<Vec<reason>>,
373}
374
375#[derive(Debug, Deserialize, Serialize, PartialEq)]
376#[allow(non_camel_case_types)]
377pub struct reason {
378 #[serde(skip_serializing_if = "Option::is_none")]
379 pub reason: Option<String>,
380 #[serde(skip_serializing_if = "Option::is_none")]
381 pub count: Option<u32>,
382}
383
384#[derive(Debug, Deserialize, Serialize, PartialEq)]
385#[allow(non_camel_case_types)]
386pub struct status {
387 #[serde(skip_serializing_if = "Option::is_none")]
388 pub state: Option<String>,
389 #[serde(skip_serializing_if = "Option::is_none")]
390 pub reason: Option<String>,
391 #[serde(skip_serializing_if = "Option::is_none")]
392 pub reason_ttl: Option<f32>,
393}
394
395#[derive(Debug, Deserialize, Serialize, PartialEq)]
396#[allow(non_camel_case_types)]
397pub struct address {
398 #[serde(skip_serializing_if = "Option::is_none")]
399 pub addr: Option<String>,
400 #[serde(skip_serializing_if = "Option::is_none")]
401 pub addrtype: Option<String>,
402 #[serde(skip_serializing_if = "Option::is_none")]
403 pub vendor: Option<String>,
404}
405
406#[derive(Debug, Deserialize, Serialize, PartialEq)]
407#[allow(non_camel_case_types)]
408pub struct hostname {
409 #[serde(skip_serializing_if = "Option::is_none")]
410 pub name: Option<String>,
411 #[serde(skip_serializing_if = "Option::is_none")]
412 pub r#type: Option<String>,
413}
414
415#[derive(Debug, Deserialize, Serialize, PartialEq)]
416#[allow(non_camel_case_types)]
417pub struct smurf {
418 #[serde(skip_serializing_if = "Option::is_none")]
419 pub responses: Option<String>,
420}
421
422#[derive(Debug, Deserialize, Serialize, PartialEq)]
423#[allow(non_camel_case_types)]
424pub struct port {
425 #[serde(skip_serializing_if = "Option::is_none")]
426 pub protocol: Option<String>,
427 #[serde(skip_serializing_if = "Option::is_none")]
428 pub portid: Option<u32>,
429 #[serde(skip_serializing_if = "Option::is_none")]
430 pub state: Option<state>,
431 #[serde(skip_serializing_if = "Option::is_none")]
432 pub owner: Option<owner>,
433 #[serde(skip_serializing_if = "Option::is_none")]
434 pub service: Option<service>,
435 #[serde(skip_serializing_if = "Option::is_none")]
436 pub script: Option<Vec<script>>,
437}
438
439#[derive(Debug, Deserialize, PartialEq, Serialize)]
440#[allow(non_camel_case_types)]
441pub struct state {
442 #[serde(skip_serializing_if = "Option::is_none")]
443 pub state: Option<String>,
444 #[serde(skip_serializing_if = "Option::is_none")]
445 pub reason: Option<String>,
446 #[serde(skip_serializing_if = "Option::is_none")]
447 pub reason_ttl: Option<f32>,
448 #[serde(skip_serializing_if = "Option::is_none")]
449 pub reason_ip: Option<String>,
450}
451
452#[derive(Debug, Deserialize, PartialEq, Serialize)]
453#[allow(non_camel_case_types)]
454pub struct owner {
455 #[serde(skip_serializing_if = "Option::is_none")]
456 pub name: Option<String>,
457}
458
459#[derive(Debug, Deserialize, PartialEq, Serialize)]
460#[allow(non_camel_case_types)]
461pub struct service {
462 #[serde(skip_serializing_if = "Option::is_none")]
463 pub name: Option<String>,
464 #[serde(skip_serializing_if = "Option::is_none")]
465 pub conf: Option<u32>,
466 #[serde(skip_serializing_if = "Option::is_none")]
467 pub method: Option<String>,
468 #[serde(skip_serializing_if = "Option::is_none")]
469 pub version: Option<String>,
470 #[serde(skip_serializing_if = "Option::is_none")]
471 pub product: Option<String>,
472 #[serde(skip_serializing_if = "Option::is_none")]
473 pub extrainfo: Option<String>,
474 #[serde(skip_serializing_if = "Option::is_none")]
475 pub tunnel: Option<String>,
476 #[serde(skip_serializing_if = "Option::is_none")]
477 pub proto: Option<String>,
478 #[serde(skip_serializing_if = "Option::is_none")]
479 pub rpcnum: Option<String>,
480 #[serde(skip_serializing_if = "Option::is_none")]
481 pub lowver: Option<String>,
482 #[serde(skip_serializing_if = "Option::is_none")]
483 pub hiver: Option<String>,
484 #[serde(skip_serializing_if = "Option::is_none")]
485 pub hostname: Option<String>,
486 #[serde(skip_serializing_if = "Option::is_none")]
487 pub ostype: Option<String>,
488 #[serde(skip_serializing_if = "Option::is_none")]
489 pub devicetype: Option<String>,
490 #[serde(skip_serializing_if = "Option::is_none")]
491 pub servicefp: Option<String>,
492 #[serde(skip_serializing_if = "Option::is_none")]
493 #[serde(rename = "cpe")]
494 pub cpe: Option<Vec<cpe>>,
495 }
497
498#[derive(Debug, Deserialize, PartialEq, Serialize)]
499#[allow(non_camel_case_types)]
500pub struct cpe {
501 #[serde(skip_serializing_if = "Option::is_none")]
502 #[serde(rename = "$value")]
503 value: Option<String>,
504}
505
506#[derive(Debug, Deserialize, PartialEq, Serialize)]
507#[allow(non_camel_case_types)]
508pub struct target {
509 #[serde(skip_serializing_if = "Option::is_none")]
510 pub specification: Option<String>,
511 #[serde(skip_serializing_if = "Option::is_none")]
512 pub status: Option<String>,
513 #[serde(skip_serializing_if = "Option::is_none")]
514 pub reason: Option<String>,
515}
516
517#[derive(Debug, Deserialize, PartialEq, Serialize)]
518#[allow(non_camel_case_types)]
519pub struct runstats {
520 #[serde(skip_serializing_if = "Option::is_none")]
521 pub finished: Option<finished>,
522 #[serde(skip_serializing_if = "Option::is_none")]
523 pub hoststats: Option<hoststats>,
524}
525
526#[derive(Debug, Deserialize, PartialEq, Serialize)]
527#[allow(non_camel_case_types)]
528pub struct finished {
529 #[serde(skip_serializing_if = "Option::is_none")]
530 pub time: Option<i32>,
531 #[serde(skip_serializing_if = "Option::is_none")]
532 pub timestr: Option<String>,
533 #[serde(skip_serializing_if = "Option::is_none")]
534 pub elapsed: Option<f32>,
535 #[serde(skip_serializing_if = "Option::is_none")]
536 pub summary: Option<String>,
537 #[serde(skip_serializing_if = "Option::is_none")]
538 pub exit: Option<String>,
539 #[serde(skip_serializing_if = "Option::is_none")]
540 pub errormsg: Option<String>,
541}
542
543#[derive(Debug, Deserialize, PartialEq, Serialize)]
544#[allow(non_camel_case_types)]
545pub struct hoststats {
546 #[serde(skip_serializing_if = "Option::is_none")]
547 pub up: Option<i32>,
548 #[serde(skip_serializing_if = "Option::is_none")]
549 pub down: Option<i32>,
550 #[serde(skip_serializing_if = "Option::is_none")]
551 pub total: Option<i32>,
552}
553
554type BoxResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;
555
556pub fn parse_nmap_xml(filename: &str) -> BoxResult<nmap_run> {
567 let xml_info = match fs::read_to_string(filename) {
568 Ok(xml_info) => xml_info,
569 Err(err) => return Err(Box::new(err) as Box<dyn std::error::Error>),
570 };
571 let nmap_run_info = match serde_xml_rs::from_str(&xml_info) {
572 Ok(nmap_run_info) => nmap_run_info,
573 Err(err) => return Err(Box::new(err) as Box<dyn std::error::Error>),
574 };
575 Ok(nmap_run_info)
576}