rust_nmap/
lib.rs

1//! A module for nmap xml
2
3#[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    //TODO: taskbegin taskend taskprogress
34    // #[serde(skip_serializing_if = "Option::is_none")]
35    // pub taskbegin: Option<Vec<task_info>>,
36    // #[serde(skip_serializing_if = "Option::is_none")]
37    // pub taskend: Option<Vec<task_info>>,
38    // #[serde(skip_serializing_if = "Option::is_none")]
39    // pub taskprogress: Option<Vec<task_progress_info>>,
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub prescript: Option<prescript>,
42    // #[serde(skip_serializing_if = "Option::is_none")]
43    // #[serde(rename = "prescript>script")]
44    // pub prescripts: Option<Vec<script>>,
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub postscript: Option<postscript>,
47    // #[serde(skip_serializing_if = "Option::is_none")]
48    // #[serde(rename = "postscript>script")]
49    // pub postscripts: Option<Vec<script>>,
50    #[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(rename = "hostnames>hostname")]
178    // pub hostnames: Option<Vec<hostname>>,
179    #[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(rename = "ports>port")]
184    // pub ports: Option<Vec<port>>,
185    // #[serde(skip_serializing_if = "Option::is_none")]
186    // #[serde(rename = "ports>extraports")]
187    // pub extraports: Option<Vec<extraports>>,
188    // #[serde(rename = "ports")]
189    // pub ports2: Option<Vec<port>>,
190    #[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(rename = "hostscript>script")]
203    // pub hostscripts: Option<script>,
204    #[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    // pub cpes: Option<Vec<cpe>>,
355}
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    // pub cpes: Option<Vec<cpe>>,
496}
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
556/// # Examples
557///
558/// Basic usage:
559///
560/// ```no_run
561/// use rust_nmap;
562///
563/// let result = rust_nmap::parse_nmap_xml("/xxx/nmap_result.xml");
564/// println!("{:?}", result.unwrap());
565/// ```
566pub 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}