File Coverage

lib/Nmap/Scanner/Backend/XML.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Nmap::Scanner::Backend::XML;
2              
3 3     3   12 use strict;
  3         4  
  3         100  
4              
5 3     3   14 use vars qw(@ISA);
  3         5  
  3         141  
6             @ISA = qw(Nmap::Scanner::Backend::Processor);
7              
8 3     3   2399 use XML::SAX::ParserFactory;
  3         25867  
  3         83  
9              
10 3     3   20 use Nmap::Scanner;
  3         4  
  3         67  
11 3     3   1293 use Nmap::Scanner::Backend::Results;
  0            
  0            
12             use Nmap::Scanner::Backend::Processor;
13              
14             sub new {
15             my $class = shift;
16             my $you = $class->SUPER::new();
17             return bless $you, $class;
18             }
19              
20             # Process results from "-oX -"
21              
22             sub process {
23            
24             my $self = shift;
25             my $pid = shift;
26             my $read = shift;
27             my $cmdline = shift;
28             my $error = shift;
29              
30             # Suppress warnings about reading unopened handle
31             $^W = 0;
32             my $err = join('', (<$error>));
33             $^W = 1;
34              
35             if ($err ne '') {
36              
37             close($read);
38             close($error);
39              
40             warn <
41            
42            
43            
44             $err
45            
46             EOF
47             exit 1;
48             }
49              
50             my $handler = NmapHandler->new($self);
51             my $parser = XML::SAX::ParserFactory->parser(Handler => $handler);
52              
53             eval { $parser->parse_file($read) };
54              
55              
56             if (defined($@) && ($@ ne '')) {
57              
58             my $msg = join('', <$read>);
59              
60             Nmap::Scanner::debug("bytes in input stream: " . tell($read));
61             Nmap::Scanner::debug("bytes in error stream: " . tell($error));
62              
63             warn <
64            
65            
66            
67             $@
68             $msg
69             $err
70            
71             EOF
72             close($read);
73             exit 1;
74              
75             }
76              
77             close($read);
78              
79             return $handler->results();
80              
81             }
82              
83             1;
84              
85             #
86             # SAX listener to process XML output from nmap.
87             #
88              
89             package NmapHandler;
90              
91             use strict;
92             use base qw(XML::SAX::Base);
93              
94             use XML::SAX::Base;
95              
96             use Nmap::Scanner::Host;
97             use Nmap::Scanner::Hostname;
98             use Nmap::Scanner::Port;
99             use Nmap::Scanner::Service;
100             use Nmap::Scanner::Address;
101             use Nmap::Scanner::Hosts;
102             use Nmap::Scanner::ExtraPorts;
103             use Nmap::Scanner::RunStats;
104             use Nmap::Scanner::RunStats::Finished;
105             use Nmap::Scanner::NmapRun;
106             use Nmap::Scanner::ScanInfo;
107             use Nmap::Scanner::Task;
108             use Nmap::Scanner::TaskProgress;
109             use Nmap::Scanner::Distance;
110             use Nmap::Scanner::Backend::Results;
111              
112             use Nmap::Scanner::OS;
113             use Nmap::Scanner::OS::PortUsed;
114             use Nmap::Scanner::OS::Uptime;
115             use Nmap::Scanner::OS::Class;
116             use Nmap::Scanner::OS::Match;
117             use Nmap::Scanner::OS::TCPSequence;
118             use Nmap::Scanner::OS::TCPTSSequence;
119             use Nmap::Scanner::OS::IPIdSequence;
120             use Nmap::Scanner::OS::Fingerprint;
121              
122             # One function per element .. fun! ;)
123              
124             my %HANDLERS = (
125             host => \&host,
126             hosts => \&hosts,
127             status => \&hoststatus,
128             hostname => \&hostname,
129             smurf => \&smurf,
130             address => \&hostaddress,
131             hostnames => \&hostnames,
132             port => \&port,
133             ports => \&ports,
134             state => \&state,
135             service => \&service,
136             owner => \&owner,
137             addport => \&addport,
138             extraports => \&extraports,
139             os => \&os,
140             portused => \&portused,
141             osclass => \&osclass,
142             osfingerprint => \&osfingerprint,
143             osmatch => \&osmatch,
144             uptime => \&uptime,
145             tcpsequence => \&tcpsequence,
146             tcptssequence => \&tcptssequence,
147             ipidsequence => \&ipidsequence,
148             nmaprun => \&nmaprun,
149             scaninfo => \&scaninfo,
150             taskbegin => \&taskbegin,
151             taskend => \&taskend,
152             taskprogress => \&taskprogress,
153             verbose => \&verbose,
154             debugging => \&debugging,
155             runstats => \&runstats,
156             finished => \&finished,
157             distance => \&distance,
158             );
159              
160             sub new {
161             my $class = shift;
162             my $backend = shift;
163             my $self = $class->SUPER::new();
164             $self->{NMAP_BACKEND} = $backend;
165             $self->{NMAP_PORT} = undef;
166             $self->{NMAP_HOST} = undef;
167             $self->{NMAP_RUNSTATS} = undef;
168             $self->{NMAP_NMAPRUN} = undef;
169             $self->{PORT_COUNT} = 0;
170             $self->{NMAP_OSGUESS} = undef;
171             $self->{NMAP_RESULTS} = Nmap::Scanner::Backend::Results->new();
172             $self->{NMAP_TASK} = undef;
173             $self->{NMAP_TASK_PROGRESS} = undef;
174             return bless $self, $class;
175             }
176              
177             # Controller for start element handlers
178              
179             sub start_element {
180             my ($self, $el) = @_;
181             my $name = $el->{Name};
182              
183             if (exists $HANDLERS{$name}) {
184             Nmap::Scanner::debug("About to handle $name");
185             &{$HANDLERS{$name}}($self, $el->{Attributes});
186             Nmap::Scanner::debug("Handled $name");
187             } else {
188              
189             my %attrs = %{$el->{Attributes}};
190              
191             return unless Nmap::Scanner::debug("Received unhandled XML: $name");
192              
193             for my $key (keys %attrs) {
194             Nmap::Scanner::debug("Unhandled[$name]: $key = $attrs{$key}");
195             }
196             }
197             }
198              
199             # Controller for end element handlers
200              
201             sub end_element {
202              
203             my ($self, $el) = @_;
204              
205             if ($el->{Name} eq 'host') {
206             my $host = $self->{NMAP_HOST};
207             $self->{NMAP_HOST}->os($self->{NMAP_OSGUESS})
208             if $self->{NMAP_OSGUESS};
209             $self->{NMAP_RESULTS}->add_host($host);
210             $self->{NMAP_BACKEND}->notify_scan_complete($self->{NMAP_HOST});
211             undef $self->{NMAP_OSGUESS};
212             } elsif ($el->{Name} eq 'hosts') {
213             $self->{NMAP_NMAPRUN}->run_stats($self->{NMAP_RUNSTATS});
214             } elsif ($el->{Name} eq 'port') {
215             my $port = $self->{NMAP_PORT};
216             Nmap::Scanner::debug("Adding port: " . $port->portid());
217             $self->{NMAP_HOST}->add_port($port);
218             $self->{PORT_COUNT}++;
219             $self->{NMAP_BACKEND}->notify_port_found(
220             $self->{NMAP_HOST}, $self->{NMAP_PORT}
221             );
222             undef $self->{NMAP_PORT};
223             } elsif ($el->{Name} eq 'ports') {
224             unless ($self->{PORT_COUNT} > 0) {
225             $self->{NMAP_BACKEND}->notify_no_ports_open(
226             $self->{NMAP_HOST}, $self->{NMAP_HOST}->extra_ports()
227             );
228             }
229             $self->{PORT_COUNT} = 0;
230             } elsif ($el->{Name} eq 'hostnames') {
231             $self->{NMAP_BACKEND}->notify_scan_started($self->{NMAP_HOST});
232             } elsif ($el->{Name} eq 'taskbegin') {
233             $self->{NMAP_BACKEND}->notify_task_started($self->{NMAP_TASK});
234             } elsif ($el->{Name} eq 'taskend') {
235             $self->{NMAP_BACKEND}->notify_task_ended($self->{NMAP_TASK});
236             } elsif ($el->{Name} eq 'taskprogress') {
237             $self->{NMAP_BACKEND}->notify_task_progress(
238             $self->{NMAP_TASK_PROGRESS});
239             } elsif ($el->{Name} eq 'nmaprun') {
240             $self->{NMAP_RESULTS}->nmap_run($self->{NMAP_NMAPRUN});
241             }
242             }
243              
244             sub host {
245             my ($self, $ref) = @_;
246             $self->{NMAP_HOST} = Nmap::Scanner::Host->new();
247             }
248              
249             sub hoststatus {
250             my ($self, $ref) = @_;
251             my $state = $ref->{'{}state'}->{Value};
252             $self->{NMAP_HOST}->status($state);
253             }
254              
255             sub hostname {
256             my ($self, $ref) = @_;
257             my $host = $self->{NMAP_HOST};
258             my $hostname = Nmap::Scanner::Hostname->new();
259             $hostname->name($ref->{'{}name'}->{Value});
260             $hostname->type($ref->{'{}type'}->{Value});
261             $host->add_hostname($hostname);
262             }
263              
264             sub hostnames {
265             my $self = shift;
266             # Do nothing, as this is just an array of hostnames, held in Host object.
267             }
268              
269             sub ports {
270             my $self = shift;
271             # Do nothing, as this is just an array of ports, held in Host object.
272             }
273              
274             sub smurf {
275             my ($self, $ref) = @_;
276             my $smurf = $ref->{'{}responses'}->{Value};
277             $self->{NMAP_HOST}->smurf($smurf);
278             }
279              
280             sub hostaddress {
281             my ($self, $ref) = @_;
282             my $addr = Nmap::Scanner::Address->new();
283             $addr->addr($ref->{'{}addr'}->{Value});
284             $addr->addrtype($ref->{'{}addrtype'}->{Value});
285             $addr->vendor($ref->{'{}vendor'}->{Value})
286             if $ref->{'{}vendor'}->{Value};
287             $self->{NMAP_HOST}->add_address($addr);
288             }
289              
290             sub port {
291             my ($self, $ref) = @_;
292             my $port = Nmap::Scanner::Port->new();
293             $port->protocol($ref->{'{}protocol'}->{Value});
294             $port->portid($ref->{'{}portid'}->{Value});
295             $self->{NMAP_PORT} = $port;
296             }
297              
298             sub state {
299             my ($self, $ref) = @_;
300             $self->{NMAP_PORT}->state($ref->{'{}state'}->{Value});
301             }
302              
303             sub owner {
304             my ($self, $ref) = @_;
305             my $owner = $ref->{'{}name'}->{Value};
306             $self->{NMAP_PORT}->owner($owner);
307             }
308              
309             sub service {
310              
311             my ($self, $ref) = @_;
312             my $port = $self->{NMAP_PORT};
313             my $svc = Nmap::Scanner::Service->new();
314             $svc->name($ref->{'{}name'}->{Value});
315             $svc->proto($ref->{'{}proto'}->{Value});
316             $svc->rpcnum($ref->{'{}rpcnum'}->{Value});
317             $svc->lowver($ref->{'{}lowver'}->{Value});
318             $svc->highver($ref->{'{}highver'}->{Value});
319             $svc->method($ref->{'{}method'}->{Value});
320             $svc->conf($ref->{'{}conf'}->{Value});
321             $svc->tunnel($ref->{'{}tunnel'}->{Value});
322             $svc->product($ref->{'{}product'}->{Value});
323             $svc->version($ref->{'{}version'}->{Value});
324             $svc->extrainfo($ref->{'{}extrainfo'}->{Value});
325             $port->service($svc);
326             }
327              
328             sub addport {
329             my ($self, $ref) = @_;
330              
331             my $port = Nmap::Scanner::Port->new();
332             $port->state($ref->{'{}state'}->{Value});
333             $port->protocol($ref->{'{}protocol'}->{Value});
334             $port->portid($ref->{'{}portid'}->{Value});
335             $port->owner($ref->{'{}owner'}->{Value})
336             if $ref->{'{}owner'};
337             $self->{NMAP_BACKEND}->notify_port_found(
338             $self->{NMAP_HOST}, $port
339             );
340             }
341              
342             sub extraports {
343             my ($self, $ref) = @_;
344             my $extras = Nmap::Scanner::ExtraPorts->new();
345             $extras->state($ref->{'{}state'}->{Value});
346             $extras->count($ref->{'{}count'}->{Value});
347             $self->{NMAP_HOST}->extra_ports($extras);
348             }
349              
350             sub os {
351             my ($self, $ref) = @_;
352             $self->{NMAP_OSGUESS} = Nmap::Scanner::OS->new();
353             }
354              
355             sub osclass {
356             my ($self, $ref) = @_;
357             my $os = $self->{NMAP_OSGUESS};
358             my $class = Nmap::Scanner::OS::Class->new();
359             $class->type($ref->{'{}type'}->{Value});
360             $class->vendor($ref->{'{}vendor'}->{Value});
361             $class->osfamily($ref->{'{}osfamily'}->{Value});
362             $class->osgen($ref->{'{}osgen'}->{Value});
363             $class->accuracy($ref->{'{}accuracy'}->{Value});
364             $os->add_os_class($class);
365             }
366              
367             sub osfingerprint {
368             my ($self, $ref) = @_;
369             my $os = $self->{NMAP_OSGUESS};
370             my $fingerprint = Nmap::Scanner::OS::Fingerprint->new();
371             $fingerprint->fingerprint($ref->{'{}fingerprint'}->{Value});
372             $os->osfingerprint($fingerprint);
373             }
374            
375             sub osmatch {
376             my ($self, $ref) = @_;
377             my $os = $self->{NMAP_OSGUESS};
378             my $match = Nmap::Scanner::OS::Match->new();
379             $match->name($ref->{'{}name'}->{Value});
380             $match->accuracy($ref->{'{}accuracy'}->{Value});
381             $os->add_os_match($match);
382             }
383              
384             sub portused {
385             my ($self, $ref) = @_;
386             my $os = $self->{NMAP_OSGUESS};
387             my $port = Nmap::Scanner::OS::PortUsed->new();
388             $port->state($ref->{'{}state'}->{Value});
389             $port->proto($ref->{'{}proto'}->{Value});
390             $port->portid($ref->{'{}portid'}->{Value});
391             $os->add_port_used($port);
392             }
393              
394             sub uptime {
395             my ($self, $ref) = @_;
396             my $os = $self->{NMAP_OSGUESS};
397             my $u = Nmap::Scanner::OS::Uptime->new();
398             $u->seconds($ref->{'{}seconds'}->{Value});
399             $u->lastboot($ref->{'{}lastboot'}->{Value});
400             $os->uptime($u);
401             }
402              
403             sub tcpsequence {
404             my ($self, $ref) = @_;
405             my $os = $self->{NMAP_OSGUESS};
406             my $t = Nmap::Scanner::OS::TCPSequence->new();
407             $t->index($ref->{'{}index'}->{Value});
408             $t->class($ref->{'{}class'}->{Value});
409             $t->difficulty($ref->{'{}difficulty'}->{Value});
410             $t->values($ref->{'{}values'}->{Value});
411             $os->tcpsequence($t);
412             }
413              
414             sub tcptssequence {
415             my ($self, $ref) = @_;
416             my $os = $self->{NMAP_OSGUESS};
417             my $t = Nmap::Scanner::OS::TCPTSSequence->new();
418             $t->class($ref->{'{}class'}->{Value});
419             $t->values($ref->{'{}values'}->{Value});
420             $os->tcptssequence($t);
421             }
422              
423             sub ipidsequence {
424             my ($self, $ref) = @_;
425             my $os = $self->{NMAP_OSGUESS};
426             my $t = Nmap::Scanner::OS::IPIdSequence->new();
427             $t->class($ref->{'{}class'}->{Value});
428             $t->values($ref->{'{}values'}->{Value});
429             $os->ipidsequence($t);
430             }
431              
432             sub nmaprun {
433             my ($self, $ref) = @_;
434             my $run = Nmap::Scanner::NmapRun->new();
435             $run->scanner($ref->{'{}scanner'}->{Value});
436             $run->args($ref->{'{}args'}->{Value});
437             $run->start($ref->{'{}start'}->{Value});
438             $run->startstr($ref->{'{}startstr'}->{Value});
439             $run->version($ref->{'{}version'}->{Value});
440             $run->xmloutputversion($ref->{'{}xmloutputversion'}->{Value});
441             $self->{NMAP_NMAPRUN} = $run;
442             }
443              
444             sub scaninfo {
445             my ($self, $ref) = @_;
446             my $info = Nmap::Scanner::ScanInfo->new();
447             $info->type($ref->{'{}type'}->{Value});
448             $info->protocol($ref->{'{}protocol'}->{Value});
449             $info->numservices($ref->{'{}numservices'}->{Value});
450             $info->services($ref->{'{}services'}->{Value});
451             $self->{NMAP_NMAPRUN}->add_scan_info($info);
452             }
453              
454             sub taskbegin {
455             my ($self, $ref) = @_;
456             my $name = $ref->{'{}task'}->{'Value'};
457             my $time = $ref->{'{}time'}->{'Value'};
458             my $task = Nmap::Scanner::Task->new();
459             $task->name($name);
460             $task->begin_time($time);
461             $self->{NMAP_TASK} = $task;
462             }
463              
464             sub taskprogress {
465              
466             my ($self, $ref) = @_;
467              
468             my $time = $ref->{'{}time'}->{'Value'};
469             my $percent = $ref->{'{}percent'}->{'Value'};
470             my $remaining = $ref->{'{}remaining'}->{'Value'};
471             my $etc = $ref->{'{}etc'}->{'Value'};
472             my $tp = Nmap::Scanner::TaskProgress->new();
473              
474             $tp->task($self->{NMAP_TASK});
475             $tp->time($time);
476             $tp->percent($percent);
477             $tp->remaining($remaining);
478             $tp->etc($etc);
479              
480             $self->{NMAP_TASK_PROGRESS} = $tp;
481              
482             }
483              
484             sub taskend {
485              
486             my ($self, $ref) = @_;
487             my $name = $ref->{'{}task'}->{'Value'};
488             my $time = $ref->{'{}time'}->{'Value'};
489             my $task = $self->{NMAP_TASK};
490              
491             $task->end_time($time);
492              
493             $self->{NMAP_NMAPRUN}->add_task($task);
494              
495             }
496              
497             sub distance {
498             my ($self, $ref) = @_;
499             my $distance = Nmap::Scanner::Distance->new();
500             my $value = $ref->{'{}value'}->{Value};
501             $distance->value($value);
502             $self->{NMAP_HOST}->distance($distance);
503             }
504              
505             sub verbose {
506             my ($self, $ref) = @_;
507             $self->{NMAP_NMAPRUN}->verbose($ref->{'{}level'}->{Value});
508             }
509              
510             sub debugging {
511             my ($self, $ref) = @_;
512             $self->{NMAP_NMAPRUN}->debugging($ref->{'{}level'}->{Value});
513             }
514              
515             sub runstats {
516             my ($self, $ref) = @_;
517             my $stats = Nmap::Scanner::RunStats->new();
518             $self->{NMAP_RUNSTATS} = $stats;
519             }
520              
521             sub hosts {
522             my ($self, $ref) = @_;
523             my $hosts = Nmap::Scanner::Hosts->new();
524             $hosts->up($ref->{'{}up'}->{Value});
525             $hosts->down($ref->{'{}down'}->{Value});
526             $hosts->total($ref->{'{}total'}->{Value});
527             $self->{NMAP_RUNSTATS}->hosts($hosts);
528             }
529              
530             sub finished {
531             my ($self, $ref) = @_;
532             my $f = Nmap::Scanner::RunStats::Finished->new();
533             $f->time($ref->{'{}time'}->{Value});
534             $f->timestr($ref->{'{}timestr'}->{Value});
535             $self->{NMAP_RUNSTATS}->finished($f);
536             }
537              
538             sub results {
539             my $self = shift;
540             return $self->{NMAP_RESULTS};
541             }
542              
543             1;
544