1package Nmap::Parser;
2
3use strict;
4use XML::Twig;
5
6our $VERSION = 1.37;
7
8
9sub new {
10
11    my ( $class, $self ) = shift;
12    $class = ref($class) || $class;
13
14    $self->{twig} = new XML::Twig(
15        start_tag_handlers => { nmaprun => sub {$self->_nmaprun_start_tag_hdlr(@_)} },
16
17        twig_roots => {
18            scaninfo => sub {$self->_scaninfo_tag_hdlr(@_)},
19            prescript => sub {$self->_prescript_tag_hdlr(@_)},
20            postscript => sub {$self->_postscript_tag_hdlr(@_)},
21            finished => sub {$self->_finished_tag_hdlr(@_)},
22            host     => sub {$self->_host_tag_hdlr(@_)},
23        },
24        ignore_elts => {
25            addport      => 1,
26            debugging    => 1,
27            verbose      => 1,
28            hosts        => 1,
29            taskbegin    => 1,
30            taskend      => 1,
31            taskprogress => 1
32        }
33    );
34
35    bless( $self, $class );
36    return $self;
37}
38
39#/*****************************************************************************/
40# NMAP::PARSER OBJECT METHODS
41#/*****************************************************************************/
42
43#Safe parse and parsefile will return $@ which will contain the error
44#that occured if the parsing failed (it might be empty when no error occurred)
45
46sub callback {
47    my $self     = shift;
48    my $callback = shift;    #first arg is CODE
49    if ( ref($callback) eq 'CODE' ) {
50        $self->{callback}{coderef}       = $callback;
51        $self->{callback}{is_registered} = 1;
52    }
53    else {
54        $self->{callback}{is_registered} = 0;
55    }
56
57    #returns if a callback is registered or not
58    return $self->{callback}{is_registered};
59}
60
61sub _parse {
62    my $type = shift;
63    my $self = shift;
64    $self->{HOSTS} = undef;
65    $self->{SESSION} = undef;
66    {
67        file => sub { $self->{twig}->safe_parsefile(@_); },
68        string => sub { $self->{twig}->safe_parse(@_); },
69    }->{$type}->(@_);
70    if ($@) { die $@; }
71    $self->purge;
72    return $self;
73}
74
75sub parse {
76    return _parse('string', @_);
77}
78
79sub parsefile {
80    return _parse('file', @_);
81}
82
83sub parsescan {
84    my $self = shift;
85    my $nmap = shift;
86    my $args = shift;
87    my @ips  = @_;
88    my $FH;
89
90    if ( $args =~ /-o(?:X|N|G)/ ) {
91        die
92"[Nmap-Parser] Cannot pass option '-oX', '-oN' or '-oG' to parsecan()";
93    }
94
95    my $cmd;
96
97#if output file is defined, point it to a localfile then call parsefile instead.
98    if ( defined( $self->{cache_file} ) ) {
99        $cmd =
100            "$nmap $args -v -v -v -oX "
101          . $self->{cache_file} . " "
102          . ( join ' ', @ips );
103        `$cmd`;    #remove output from STDOUT
104        $self->parsefile( $self->{cache_file} );
105    }
106    else {
107        $cmd = "$nmap $args -v -v -v -oX - " . ( join ' ', @ips );
108        open $FH,
109          "$cmd |" || die "[Nmap-Parser] Could not perform nmap scan - $!";
110        $self->parse($FH);
111        close $FH;
112    }
113
114    return $self;
115}
116
117sub cache_scan {
118    my $self = shift;
119    $self->{cache_file} = shift || 'nmap-parser-cache.' . time() . '.xml';
120}
121
122sub purge {
123    my $self = shift;
124    $self->{twig}->purge;
125    return $self;
126}
127
128sub addr_sort {
129    my $self = shift if ref $_[0];
130
131    return (
132        map { unpack("x16A*", $_) }
133            sort { $a cmp $b }
134            map {
135                my @vals;
136                if( /:/ ) { #IPv6
137                    @vals = split /:/;
138                    @vals = map { $_ eq '' ? (0) x (8-$#vals) : hex } @vals
139                } else { #IPv4
140                    my @v4 = split /\./;
141                    # Sort as IPv4-mapped IPv6, per RFC 4291 Section 2.5.5.2
142                    @vals = ( (0) x 5, 0xffff, map { 256*$v4[$_] + $v4[$_+1] } (0,2) );
143                }
144                pack("n8A*", @vals, $_)
145            } @_
146        );
147}
148
149#MAIN SCAN INFORMATION
150sub get_session {
151    my $self = shift;
152    my $obj  = Nmap::Parser::Session->new( $self->{SESSION} );
153    return $obj;
154}
155
156#HOST STUFF
157sub get_host {
158    my ( $self, $ip ) = (@_);
159    if ( $ip eq '' ) {
160        warn "[Nmap-Parser] No IP address given to get_host()\n";
161        return undef;
162    }
163    $self->{HOSTS}{$ip};
164}
165
166sub del_host {
167    my ( $self, $ip ) = (@_);
168    if ( $ip eq '' ) {
169        warn "[Nmap-Parser] No IP address given to del_host()\n";
170        return undef;
171    }
172    delete $self->{HOSTS}{$ip};
173}
174
175sub all_hosts {
176    my $self = shift;
177    my $status = shift || '';
178
179    return ( values %{ $self->{HOSTS} } ) if ( $status eq '' );
180
181    my @hosts = grep { $_->{status} eq $status } ( values %{ $self->{HOSTS} } );
182    return @hosts;
183}
184
185sub get_ips {
186    my $self = shift;
187    my $status = shift || '';
188
189    return $self->addr_sort( keys %{ $self->{HOSTS} } ) if ( $status eq '' );
190
191    my @hosts =
192      grep { $self->{HOSTS}{$_}{status} eq $status }
193      ( keys %{ $self->{HOSTS} } );
194    return $self->addr_sort(@hosts);
195
196}
197
198#/*****************************************************************************/
199# PARSING TAG HANDLERS FOR XML::TWIG
200#/*****************************************************************************/
201
202sub _nmaprun_start_tag_hdlr {
203
204    my ($self, $twig, $tag ) = @_;
205
206    $self->{SESSION}{start_time}   = $tag->{att}->{start};
207    $self->{SESSION}{nmap_version} = $tag->{att}->{version};
208    $self->{SESSION}{start_str}    = $tag->{att}->{startstr};
209    $self->{SESSION}{xml_version}  = $tag->{att}->{xmloutputversion};
210    $self->{SESSION}{scan_args}    = $tag->{att}->{args};
211    $self->{SESSION} = Nmap::Parser::Session->new( $self->{SESSION} );
212
213    $twig->purge;
214
215}
216
217sub _scaninfo_tag_hdlr {
218    my ( $self, $twig, $tag ) = @_;
219    my $type        = $tag->{att}->{type};
220    my $proto       = $tag->{att}->{protocol};
221    my $numservices = $tag->{att}->{numservices};
222
223    if ( defined($type) ) {    #there can be more than one type in one scan
224        $self->{SESSION}{type}{$type}        = $proto;
225        $self->{SESSION}{numservices}{$type} = $numservices;
226    }
227    $twig->purge;
228}
229
230sub _prescript_tag_hdlr {
231    my ($self, $twig, $tag ) = @_;
232    my $scripts_hashref;
233    for my $script ( $tag->children('script') ) {
234        $scripts_hashref->{ $script->{att}->{id} } =
235            __script_tag_hdlr( $script );
236    }
237    $self->{SESSION}{prescript} = $scripts_hashref;
238    $twig->purge;
239}
240
241sub _postscript_tag_hdlr {
242    my ($self, $twig, $tag ) = @_;
243    my $scripts_hashref;
244    for my $script ( $tag->children('script') ) {
245        $scripts_hashref->{ $script->{att}->{id} } =
246          __script_tag_hdlr( $script );
247    }
248    $self->{SESSION}{postscript} = $scripts_hashref;
249    $twig->purge;
250}
251
252sub _finished_tag_hdlr {
253    my ($self, $twig, $tag ) = @_;
254    $self->{SESSION}{finish_time} = $tag->{att}->{time};
255    $self->{SESSION}{time_str}    = $tag->{att}->{timestr};
256    $twig->purge;
257}
258
259#parses all the host information in one swoop (calling __host_*_tag_hdlrs)
260sub _host_tag_hdlr {
261    my ($self, $twig, $tag ) = @_;
262    my $id = undef;
263
264    return undef unless ( defined $tag );
265
266    #GET ADDRESS INFO
267    my $addr_hashref;
268    $addr_hashref = __host_addr_tag_hdlr($tag);
269
270    #use this as the identifier
271    $id =
272         $addr_hashref->{ipv4}
273      || $addr_hashref->{ipv6}
274      || $addr_hashref->{mac};    #worstcase use MAC
275
276    $self->{HOSTS}{$id}{addrs} = $addr_hashref;
277
278    return undef unless ( defined($id) || $id ne '' );
279
280    #GET HOSTNAMES
281    $self->{HOSTS}{$id}{hostnames} = __host_hostnames_tag_hdlr($tag);
282
283    #GET STARTTIME
284    $self->{HOSTS}{$id}{starttime} = $tag->{att}->{starttime};
285
286    #GET STATUS
287    $self->{HOSTS}{$id}{status} = $tag->first_child('status')->{att}->{state};
288
289    #CONTINUE PROCESSING IF STATUS IS UP - OTHERWISE NO MORE XML
290    if ( lc( $self->{HOSTS}{$id}{status} ) eq 'up' ) {
291
292        $self->{HOSTS}{$id}{ports}         = __host_port_tag_hdlr($tag);
293        $self->{HOSTS}{$id}{os}            = __host_os_tag_hdlr($tag);
294        $self->{HOSTS}{$id}{uptime}        = __host_uptime_tag_hdlr($tag);
295        $self->{HOSTS}{$id}{tcpsequence}   = __host_tcpsequence_tag_hdlr($tag);
296        $self->{HOSTS}{$id}{ipidsequence}  = __host_ipidsequence_tag_hdlr($tag);
297        $self->{HOSTS}{$id}{tcptssequence} = __host_tcptssequence_tag_hdlr($tag);
298        $self->{HOSTS}{$id}{hostscript} = __host_hostscript_tag_hdlr($tag);
299        $self->{HOSTS}{$id}{distance} =
300          __host_distance_tag_hdlr($tag);    #returns simple value
301        $self->{HOSTS}{$id}{trace}         = __host_trace_tag_hdlr($tag);
302        $self->{HOSTS}{$id}{trace_error}   = __host_trace_error_tag_hdlr($tag);
303    }
304
305    #CREATE HOST OBJECT FOR USER
306    $self->{HOSTS}{$id} = Nmap::Parser::Host->new( $self->{HOSTS}{$id} );
307
308    if ( $self->{callback}{is_registered} ) {
309        &{ $self->{callback}{coderef} }( $self->{HOSTS}{$id} );
310        delete $self->{HOSTS}{$id};
311    }
312
313    $twig->purge;
314
315}
316
317sub __host_addr_tag_hdlr {
318    my $tag = shift;
319    my $addr_hashref;
320
321    #children() will return all children with tag name address
322    for my $addr ( $tag->children('address') ) {
323        if ( lc( $addr->{att}->{addrtype} ) eq 'mac' ) {
324
325            #we'll assume for now, only 1 MAC address per system
326            $addr_hashref->{mac}{addr}   = $addr->{att}->{addr};
327            $addr_hashref->{mac}{vendor} = $addr->{att}->{vendor};
328        }
329        elsif ( lc( $addr->{att}->{addrtype} ) eq 'ipv4' ) {
330            $addr_hashref->{ipv4} = $addr->{att}->{addr};
331        }    #support for ipv6? we'll see
332        elsif ( lc( $addr->{att}->{addrtype} ) eq 'ipv6' ) {
333            $addr_hashref->{ipv6} = $addr->{att}->{addr};
334        }
335
336    }
337
338    return $addr_hashref;
339}
340
341sub __host_hostnames_tag_hdlr {
342    my $tag = shift;
343
344    my $hostnames_tag = $tag->first_child('hostnames');
345    return undef unless ( defined $hostnames_tag );
346
347    my @hostnames;
348
349    for my $name ( $hostnames_tag->children('hostname') ) {
350        push @hostnames, $name->{att}->{name};
351    }
352
353    return \@hostnames;
354
355}
356
357sub __host_port_tag_hdlr {
358    my $tag = shift;
359    my ( $port_hashref, $ports_tag );
360
361    $ports_tag = $tag->first_child('ports');
362
363    return undef unless ( defined $ports_tag );
364
365    #Parsing Extraports
366    my $extraports_tag = $ports_tag->first_child('extraports');
367    if ( defined $extraports_tag && $extraports_tag ne '' ) {
368        $port_hashref->{extraports}{state} = $extraports_tag->{att}->{state};
369        $port_hashref->{extraports}{count} = $extraports_tag->{att}->{count};
370    }
371
372    #Parsing regular port information
373
374    my ( $tcp_port_count, $udp_port_count ) = ( 0, 0 );
375
376    for my $port_tag ( $ports_tag->children('port') ) {
377        my $proto  = $port_tag->{att}->{protocol};
378        my $portid = $port_tag->{att}->{portid};
379        my $state  = $port_tag->first_child('state');
380        my $owner  = $port_tag->first_child('owner') || undef;
381
382        $tcp_port_count++ if ( $proto eq 'tcp' );
383        $udp_port_count++ if ( $proto eq 'udp' );
384
385        $port_hashref->{$proto}{$portid}{state} = $state->{att}->{state}
386          || 'unknown'
387          if ( $state ne '' );
388
389        $port_hashref->{$proto}{$portid}{reason_ttl} = $state->{att}->{reason_ttl}
390          || 'unknown'
391          if($state ne '');
392
393        #GET SERVICE INFORMATION
394        $port_hashref->{$proto}{$portid}{service} =
395          __host_service_tag_hdlr( $port_tag, $portid )
396          if ( defined($proto) && defined($portid) );
397
398        #GET SCRIPT INFORMATION
399        $port_hashref->{$proto}{$portid}{service}{script} =
400          __host_script_tag_hdlr( $port_tag, $portid)
401          if ( defined($proto) && defined($portid) );
402
403        #GET OWNER INFORMATION
404        $port_hashref->{$proto}{$portid}{service}{owner} = $owner->{att}->{name}
405          if ( defined($owner) );
406
407   #These are added at the end, otherwise __host_service_tag_hdlr will overwrite
408   #GET PORT STATE
409
410    }
411
412    $port_hashref->{tcp_port_count} = $tcp_port_count;
413    $port_hashref->{udp_port_count} = $udp_port_count;
414
415    return $port_hashref;
416
417}
418
419sub __host_service_tag_hdlr {
420    my $tag    = shift;
421    my $portid = shift;   #need a way to remember what port this service runs on
422    my $service = $tag->first_child('service[@name]');
423    my $service_hashref;
424    $service_hashref->{port} = $portid;
425
426    if ( defined $service ) {
427        $service_hashref->{name}      = $service->{att}->{name} || 'unknown';
428        $service_hashref->{version}   = $service->{att}->{version};
429        $service_hashref->{product}   = $service->{att}->{product};
430	$service_hashref->{devicetype} = $service->{att}->{devicetype};
431        $service_hashref->{extrainfo} = $service->{att}->{extrainfo};
432        $service_hashref->{proto} =
433             $service->{att}->{proto}
434          || $service->{att}->{protocol}
435          || 'unknown';
436        $service_hashref->{rpcnum}      = $service->{att}->{rpcnum};
437        $service_hashref->{tunnel}      = $service->{att}->{tunnel};
438        $service_hashref->{method}      = $service->{att}->{method};
439        $service_hashref->{confidence}  = $service->{att}->{conf};
440        $service_hashref->{fingerprint} = $service->{att}->{servicefp};
441    }
442
443    return $service_hashref;
444}
445
446sub __host_script_tag_hdlr {
447    my $tag = shift;
448    my $script_hashref;
449
450    for ( $tag->children('script') ) {
451        $script_hashref->{ $_->{att}->{id} } =
452         __script_tag_hdlr($_);
453    }
454
455    return $script_hashref;
456}
457
458sub __host_os_tag_hdlr {
459    my $tag    = shift;
460    my $os_tag = $tag->first_child('os');
461    my $os_hashref;
462    my $portused_tag;
463    my $os_fingerprint;
464
465    if ( defined $os_tag ) {
466
467        #get the open port used to match os
468        $portused_tag = $os_tag->first_child("portused[\@state='open']");
469        $os_hashref->{portused}{open} = $portused_tag->{att}->{portid}
470          if ( defined $portused_tag );
471
472        #get the closed port used to match os
473        $portused_tag = $os_tag->first_child("portused[\@state='closed']");
474        $os_hashref->{portused}{closed} = $portused_tag->{att}->{portid}
475          if ( defined $portused_tag );
476
477        #os fingerprint
478        $os_fingerprint = $os_tag->first_child("osfingerprint");
479        $os_hashref->{os_fingerprint} =
480          $os_fingerprint->{'att'}->{'fingerprint'}
481          if ( defined $os_fingerprint );
482
483        #This will go in Nmap::Parser::Host::OS
484        my $osmatch_index = 0;
485        my $osclass_index = 0;
486        for my $osmatch ( $os_tag->children('osmatch') ) {
487            $os_hashref->{osmatch_name}[$osmatch_index] =
488              $osmatch->{att}->{name};
489            $os_hashref->{osmatch_name_accuracy}[$osmatch_index] =
490              $osmatch->{att}->{accuracy};
491            $osmatch_index++;
492            for my $osclass ( $osmatch->children('osclass') ) {
493                $os_hashref->{osclass_osfamily}[$osclass_index] =
494                  $osclass->{att}->{osfamily};
495                $os_hashref->{osclass_osgen}[$osclass_index] =
496                  $osclass->{att}->{osgen};
497                $os_hashref->{osclass_vendor}[$osclass_index] =
498                  $osclass->{att}->{vendor};
499                $os_hashref->{osclass_type}[$osclass_index] =
500                  $osclass->{att}->{type};
501                $os_hashref->{osclass_class_accuracy}[$osclass_index] =
502                  $osclass->{att}->{accuracy};
503                $osclass_index++;
504            }
505        }
506        $os_hashref->{'osmatch_count'} = $osmatch_index;
507
508        #parse osclass tags
509        for my $osclass ( $os_tag->children('osclass') ) {
510            $os_hashref->{osclass_osfamily}[$osclass_index] =
511              $osclass->{att}->{osfamily};
512            $os_hashref->{osclass_osgen}[$osclass_index] =
513              $osclass->{att}->{osgen};
514            $os_hashref->{osclass_vendor}[$osclass_index] =
515              $osclass->{att}->{vendor};
516            $os_hashref->{osclass_type}[$osclass_index] =
517              $osclass->{att}->{type};
518            $os_hashref->{osclass_class_accuracy}[$osclass_index] =
519              $osclass->{att}->{accuracy};
520            $osclass_index++;
521        }
522        $os_hashref->{'osclass_count'} = $osclass_index;
523    }
524
525    return $os_hashref;
526
527}
528
529sub __host_uptime_tag_hdlr {
530    my $tag    = shift;
531    my $uptime = $tag->first_child('uptime');
532    my $uptime_hashref;
533
534    if ( defined $uptime ) {
535        $uptime_hashref->{seconds}  = $uptime->{att}->{seconds};
536        $uptime_hashref->{lastboot} = $uptime->{att}->{lastboot};
537
538    }
539
540    return $uptime_hashref;
541
542}
543
544sub __host_tcpsequence_tag_hdlr {
545    my $tag      = shift;
546    my $sequence = $tag->first_child('tcpsequence');
547    my $sequence_hashref;
548    return undef unless ($sequence);
549    $sequence_hashref->{class}  = $sequence->{att}->{class};
550    $sequence_hashref->{difficulty}  = $sequence->{att}->{difficulty};
551    $sequence_hashref->{values} = $sequence->{att}->{values};
552    $sequence_hashref->{index}  = $sequence->{att}->{index};
553
554    return $sequence_hashref;
555
556}
557
558sub __host_ipidsequence_tag_hdlr {
559    my $tag      = shift;
560    my $sequence = $tag->first_child('ipidsequence');
561    my $sequence_hashref;
562    return undef unless ($sequence);
563    $sequence_hashref->{class}  = $sequence->{att}->{class};
564    $sequence_hashref->{values} = $sequence->{att}->{values};
565    return $sequence_hashref;
566
567}
568
569sub __host_tcptssequence_tag_hdlr {
570    my $tag      = shift;
571    my $sequence = $tag->first_child('tcptssequence');
572    my $sequence_hashref;
573    return undef unless ($sequence);
574    $sequence_hashref->{class}  = $sequence->{att}->{class};
575    $sequence_hashref->{values} = $sequence->{att}->{values};
576    return $sequence_hashref;
577}
578
579sub __host_hostscript_tag_hdlr {
580    my $tag = shift;
581    my $scripts = $tag->first_child('hostscript');
582    my $scripts_hashref;
583    return undef unless ($scripts);
584    for my $script ( $scripts->children('script') ) {
585        $scripts_hashref->{ $script->{att}->{id} } =
586            __script_tag_hdlr( $script );
587    }
588    return $scripts_hashref;
589}
590
591sub __host_distance_tag_hdlr {
592    my $tag      = shift;
593    my $distance = $tag->first_child('distance');
594    return undef unless ($distance);
595    return $distance->{att}->{value};
596}
597
598sub __host_trace_tag_hdlr {
599    my $tag           = shift;
600    my $trace_tag     = $tag->first_child('trace');
601    my $trace_hashref = { hops => [], };
602
603    if ( defined $trace_tag ) {
604
605        my $proto = $trace_tag->{att}->{proto};
606        $trace_hashref->{proto} = $proto if defined $proto;
607
608        my $port = $trace_tag->{att}->{port};
609        $trace_hashref->{port} = $port if defined $port;
610
611        for my $hop_tag ( $trace_tag->children('hop') ) {
612
613            # Copy the known hop attributes, they will go in
614            # Nmap::Parser::Host::TraceHop
615            my %hop_data;
616            $hop_data{$_} = $hop_tag->{att}->{$_} for qw( ttl rtt ipaddr host );
617            delete $hop_data{rtt} if $hop_data{rtt} !~ /^[\d.]+$/;
618
619            push @{ $trace_hashref->{hops} }, \%hop_data;
620        }
621
622    }
623
624    return $trace_hashref;
625}
626
627sub __host_trace_error_tag_hdlr {
628    my $tag       = shift;
629    my $trace_tag = $tag->first_child('trace');
630
631    if ( defined $trace_tag ) {
632
633        my $error_tag = $trace_tag->first_child('error');
634        if ( defined $error_tag ) {
635
636            # If an error happens, always provide a true value even if
637            # it doesn't contains a useful string
638            my $errorstr = $error_tag->{att}->{errorstr} || 1;
639            return $errorstr;
640        }
641    }
642
643    return;
644}
645
646sub __script_tag_hdlr {
647    my $tag = shift;
648    my $script_hashref = {
649        output => $tag->{att}->{output}
650    };
651    chomp %$script_hashref;
652    if ( not $tag->is_empty()) {
653        $script_hashref->{contents} = __script_table($tag);
654    }
655    return $script_hashref;
656}
657
658sub __script_table {
659    my $tag = shift;
660    my ($ref, $subref);
661    my $fc = $tag->first_child();
662    if ($fc) {
663        if ($fc->is_text) {
664            $ref = $fc->text;
665        }
666        else {
667            if ($fc->{att}->{key}) {
668                $ref = {};
669                $subref = sub {
670                    $ref->{$_->{att}->{key}} = shift;
671                };
672            }
673            else {
674                $ref = [];
675                $subref = sub {
676                    push @$ref, shift;
677                };
678            }
679            for ($tag->children()) {
680                if ($_->tag() eq "table") {
681                    $subref->(__script_table( $_ ));
682                }
683                else {
684                    $subref->($_->text);
685                }
686            }
687        }
688    }
689    return $ref
690}
691
692#/*****************************************************************************/
693# NMAP::PARSER::SESSION
694#/*****************************************************************************/
695
696package Nmap::Parser::Session;
697use vars qw($AUTOLOAD);
698
699sub new {
700    my $class = shift;
701    $class = ref($class) || $class;
702    my $self = shift || {};
703    bless( $self, $class );
704    return $self;
705}
706
707#Support for:
708#start_time, start_str, finish_time, time_str, nmap_version, xml_version, scan_args
709sub AUTOLOAD {
710    ( my $param = $AUTOLOAD ) =~ s{.*::}{}xms;
711    return if ( $param eq 'DESTROY' );
712    no strict 'refs';
713    *$AUTOLOAD = sub { return $_[0]->{ lc $param } };
714    goto &$AUTOLOAD;
715}
716
717sub numservices {
718    my $self = shift;
719    my $type = shift
720      || '';   #(syn|ack|bounce|connect|null|xmas|window|maimon|fin|udp|ipproto)
721
722    return unless ( ref( $self->{numservices} ) eq 'HASH' );
723
724    if ( $type ne '' ) { return $self->{numservices}{$type}; }
725    else {
726        my $total = 0;
727        for ( values %{ $self->{numservices} } ) { $total += $_; }
728        return $total;
729    }          #(else) total number of services together
730}
731
732sub scan_types {
733    return sort { $a cmp $b } ( keys %{ $_[0]->{type} } )
734      if ( ref( $_[0]->{type} ) eq 'HASH' );
735}
736sub scan_type_proto { return $_[1] ? $_[0]->{type}{ $_[1] } : undef; }
737
738sub prescripts {
739    my $self = shift;
740    my $id = shift;
741    unless ( defined $id ) {
742        return sort keys %{ $self->{prescript} };
743    }
744    else {
745        return $self->{prescript}{$id};
746    }
747}
748
749sub postscripts {
750    my $self = shift;
751    my $id = shift;
752    unless ( defined $id ) {
753        return sort keys %{ $self->{postscript} };
754    }
755    else {
756        return $self->{postscript}{$id};
757    }
758}
759
760#/*****************************************************************************/
761# NMAP::PARSER::HOST
762#/*****************************************************************************/
763
764package Nmap::Parser::Host;
765use vars qw($AUTOLOAD);
766
767sub new {
768    my $class = shift;
769    $class = ref($class) || $class;
770    my $self = shift || {};
771    bless( $self, $class );
772    return $self;
773}
774
775sub starttime { return $_[0]->{starttime}; }
776
777sub status { return $_[0]->{status}; }
778
779sub addr {
780    my $default = $_[0]->{addrs}{ipv4} || $_[0]->{addrs}{ipv6};
781    return $default;
782}
783
784sub addrtype {
785    if    ( $_[0]->{addrs}{ipv4} ) { return 'ipv4'; }
786    elsif ( $_[0]->{addrs}{ipv6} ) { return 'ipv6'; }
787}
788
789sub ipv4_addr { return $_[0]->{addrs}{ipv4}; }
790sub ipv6_addr { return $_[0]->{addrs}{ipv6}; }
791
792sub mac_addr   { return $_[0]->{addrs}{mac}{addr}; }
793sub mac_vendor { return $_[0]->{addrs}{mac}{vendor}; }
794
795#returns the first hostname
796sub hostname {
797    my $self = shift;
798    my $index = shift || 0;
799    if ( ref( $self->{hostnames} ) ne 'ARRAY' ) { return ''; }
800    if ( scalar @{ $self->{hostnames} } <= $index ) {
801        $index = scalar @{ $self->{hostnames} } - 1;
802    }
803    return $self->{hostnames}[$index] if ( scalar @{ $self->{hostnames} } );
804}
805
806sub all_hostnames    { return @{ $_[0]->{hostnames} || [] }; }
807sub extraports_state { return $_[0]->{ports}{extraports}{state}; }
808sub extraports_count { return $_[0]->{ports}{extraports}{count}; }
809sub distance         { return $_[0]->{distance}; }
810
811sub hostscripts {
812    my $self = shift;
813    my $id = shift;
814    unless ( defined $id ) {
815        return sort keys %{ $self->{hostscript} };
816    }
817    else {
818        return $self->{hostscript}{$id};
819    }
820}
821
822sub all_trace_hops {
823
824    my $self = shift;
825
826    return unless defined $self->{trace}->{hops};
827    return map { Nmap::Parser::Host::TraceHop->new( $_ ) }
828      @{ $self->{trace}->{hops} };
829}
830
831sub trace_port  { return $_[0]->{trace}->{port} }
832sub trace_proto { return $_[0]->{trace}->{proto} }
833sub trace_error { return $_[0]->{trace_error} }
834
835sub _del_port {
836    my $self    = shift;
837    my $proto   = pop;     #portid might be empty, so this goes first
838    my @portids = @_;
839    @portids = grep { $_ + 0 } @portids;
840
841    unless ( scalar @portids ) {
842        warn "[Nmap-Parser] No port number given to del_port()\n";
843        return undef;
844    }
845
846    delete $self->{ports}{$proto}{$_} for (@portids);
847}
848
849sub _get_ports {
850    my $self          = shift;
851    my $proto         = pop;          #param might be empty, so this goes first
852    my $state         = shift;    #open, filtered, closed or any combination
853    my @matched_ports = ();
854
855    #if $state is undef, then tcp_ports or udp_ports was called for all ports
856    #therefore, only return the keys of all ports found
857    if ( not defined $state ) {
858        return sort { $a <=> $b } ( keys %{ $self->{ports}{$proto} } );
859    }
860    else {
861        $state = lc($state)
862    }
863
864#the port parameter can be set to either any of these also 'open|filtered'
865#can count as 'open' and 'filetered'. Therefore I need to use a regex from now on
866#if $param is empty, then all ports match.
867
868    for my $portid ( keys %{ $self->{ports}{$proto} } ) {
869
870        #escape metacharacters ('|', for example in: open|filtered)
871        #using \Q and \E
872        push( @matched_ports, $portid )
873          if ( $self->{ports}{$proto}{$portid}{state} =~ /\Q$state\E/ );
874
875    }
876
877    return sort { $a <=> $b } @matched_ports;
878
879}
880
881sub _get_port_state {
882    my $self   = shift;
883    my $proto  = pop;         #portid might be empty, so this goes first
884    my $portid = lc(shift);
885
886    return undef unless ( exists $self->{ports}{$proto}{$portid} );
887    return $self->{ports}{$proto}{$portid}{state};
888
889}
890
891sub _get_port_state_ttl {
892    my $self = shift;
893    my $proto = pop;
894    my $portid = lc(shift);
895
896    return undef unless ( exists $self->{ports}{$proto}{$portid} );
897    return $self->{ports}{$proto}{$portid}{reason_ttl};
898}
899
900#changed this to use _get_ports since it was similar code
901sub tcp_ports { return _get_ports( @_, 'tcp' ); }
902sub udp_ports { return _get_ports( @_, 'udp' ); }
903
904sub tcp_port_count { return $_[0]->{ports}{tcp_port_count}; }
905sub udp_port_count { return $_[0]->{ports}{udp_port_count}; }
906
907sub tcp_port_state_ttl { return _get_port_state_ttl( @_, 'tcp' ); }
908
909sub tcp_port_state { return _get_port_state( @_, 'tcp' ); }
910sub udp_port_state { return _get_port_state( @_, 'udp' ); }
911
912sub tcp_del_ports { return _del_port( @_, 'tcp' ); }
913sub udp_del_ports { return _del_port( @_, 'udp' ); }
914
915sub tcp_service {
916    my $self   = shift;
917    my $portid = shift;
918    if ( $portid eq '' ) {
919        warn "[Nmap-Parser] No port number passed to tcp_service()\n";
920        return undef;
921    }
922    return Nmap::Parser::Host::Service->new(
923        $self->{ports}{tcp}{$portid}{service} );
924}
925
926sub udp_service {
927    my $self   = shift;
928    my $portid = shift;
929    if ( $portid eq '' ) {
930        warn "[Nmap-Parser] No port number passed to udp_service()\n";
931        return undef;
932    }
933    return Nmap::Parser::Host::Service->new(
934        $self->{ports}{udp}{$portid}{service} );
935
936}
937
938#usually the first one is the highest accuracy
939
940sub os_sig { return Nmap::Parser::Host::OS->new( $_[0]->{os} ); }
941
942#Support for:
943#tcpsequence_class, tcpsequence_values, tcpsequence_index,
944#ipidsequence_class, ipidsequence_values, tcptssequence_values,
945#tcptssequence_class, uptime_seconds, uptime_lastboot
946#tcp_open_ports, udp_open_ports, tcp_filtered_ports, udp_filtered_ports,
947#tcp_closed_ports, udp_closed_ports
948sub AUTOLOAD {
949    ( my $param = $AUTOLOAD ) =~ s{.*::}{}xms;
950    return if ( $param eq 'DESTROY' );
951    my ( $type, $val ) = split /_/, lc($param);
952
953#splits the given method name by '_'. This will determine the function and param
954    no strict 'refs';
955
956    if (   ( $type eq 'tcp' || $type eq 'udp' )
957        && ( $val eq 'open' || $val eq 'filtered' || $val eq 'closed' ) )
958    {
959
960#they must be looking for port info: tcp or udp. The $val is either open|filtered|closed
961        *$AUTOLOAD = sub { return _get_ports( $_[0], $val, $type ); };
962        goto &$AUTOLOAD;
963
964    }
965    elsif ( defined $type && defined $val ) {
966
967        #must be one of the 'sequence' functions asking for class/values/index
968        *$AUTOLOAD = sub { return $_[0]->{$type}{$val} };
969        goto &$AUTOLOAD;
970    }
971    else { die '[Nmap-Parser] method ->' . $param . "() not defined!\n"; }
972}
973
974#/*****************************************************************************/
975# NMAP::PARSER::HOST::SERVICE
976#/*****************************************************************************/
977
978package Nmap::Parser::Host::Service;
979use vars qw($AUTOLOAD);
980
981sub new {
982    my $class = shift;
983    $class = ref($class) || $class;
984    my $self = shift || {};
985    bless( $self, $class );
986    return $self;
987}
988
989sub scripts {
990    my $self = shift;
991    my $id = shift;
992
993    unless ( defined $id ) {
994        return sort keys %{ $self->{script} };
995    }
996    else {
997        return $self->{script}{$id};
998    }
999}
1000
1001#Support for:
1002#name port proto rpcnum owner version product extrainfo tunnel method confidence
1003#this will now only load functions that will be used. This saves
1004#on delay (increase speed) and memory
1005
1006sub AUTOLOAD {
1007    ( my $param = $AUTOLOAD ) =~ s{.*::}{}xms;
1008    return if ( $param eq 'DESTROY' );
1009    no strict 'refs';
1010
1011    *$AUTOLOAD = sub { return $_[0]->{ lc $param } };
1012    goto &$AUTOLOAD;
1013}
1014
1015#/*****************************************************************************/
1016# NMAP::PARSER::HOST::OS
1017#/*****************************************************************************/
1018
1019package Nmap::Parser::Host::OS;
1020use vars qw($AUTOLOAD);
1021
1022sub new {
1023    my $class = shift;
1024    $class = ref($class) || $class;
1025    my $self = shift || {};
1026    bless( $self, $class );
1027    return $self;
1028}
1029
1030sub portused_open   { return $_[0]->{portused}{open}; }
1031sub portused_closed { return $_[0]->{portused}{closed}; }
1032sub os_fingerprint  { return $_[0]->{os_fingerprint}; }
1033
1034sub name_count { return $_[0]->{osmatch_count}; }
1035
1036sub all_names {
1037    my $self = shift;
1038    @_ = ();
1039    if ( $self->{osclass_count} < 1 ) { return @_; }
1040    if ( ref( $self->{osmatch_name} ) eq 'ARRAY' ) {
1041        return sort @{ $self->{osmatch_name} };
1042    }
1043
1044}    #given by decreasing accuracy
1045
1046sub class_count { return $_[0]->{osclass_count}; }
1047
1048#Support for:
1049#name,names, name_accuracy, osfamily, vendor, type, osgen, class_accuracy
1050sub AUTOLOAD {
1051    ( my $param = $AUTOLOAD ) =~ s{.*::}{}xms;
1052    return if ( $param eq 'DESTROY' );
1053    no strict 'refs';
1054    $param = lc($param);
1055
1056    $param = 'name' if ( $param eq 'names' );
1057    if ( $param eq 'name' || $param eq 'name_accuracy' ) {
1058
1059        *$AUTOLOAD = sub { _get_info( $_[0], $_[1], $param, 'osmatch' ); };
1060        goto &$AUTOLOAD;
1061    }
1062    else {
1063
1064        *$AUTOLOAD = sub { _get_info( $_[0], $_[1], $param, 'osclass' ); };
1065        goto &$AUTOLOAD;
1066    }
1067}
1068
1069sub _get_info {
1070    my ( $self, $index, $param, $type ) = @_;
1071    $index ||= 0;
1072
1073    #type is either osclass or osmatch
1074    if ( $index >= $self->{ $type . '_count' } ) {
1075        $index = $self->{ $type . '_count' } - 1;
1076    }
1077    return $self->{ $type . '_' . $param }[$index];
1078}
1079
1080#/*****************************************************************************/
1081# NMAP::PARSER::HOST::TRACEHOP
1082#/*****************************************************************************/
1083
1084package Nmap::Parser::Host::TraceHop;
1085use vars qw($AUTOLOAD);
1086
1087sub new {
1088    my $class = shift;
1089    $class = ref($class) || $class;
1090    my $self = shift || {};
1091    bless( $self, $class );
1092    return $self;
1093}
1094
1095sub AUTOLOAD {
1096    ( my $param = $AUTOLOAD ) =~ s{.*::}{}xms;
1097    return if ( $param eq 'DESTROY' );
1098    no strict 'refs';
1099    $param = lc($param);
1100
1101    # Supported accessors:
1102    my %subs;
1103    @subs{ qw( ttl rtt ipaddr host ) } = 1;
1104
1105    if ( exists $subs{$param} ) {
1106
1107        *$AUTOLOAD = sub { $_[0]->{$param} };
1108        goto &$AUTOLOAD;
1109    }
1110    else { die '[Nmap-Parser] method ->' . $param . "() not defined!\n"; }
1111}
1112
11131;
1114
1115__END__
1116
1117=pod
1118
1119=head1 NAME
1120
1121Nmap::Parser - parse nmap scan data with perl
1122
1123=head1 SYNOPSIS
1124
1125  use Nmap::Parser;
1126  my $np = new Nmap::Parser;
1127
1128  $np->parsescan($nmap_path, $nmap_args, @ips);
1129    #or
1130  $np->parsefile($file_xml);
1131
1132  my $session    = $np->get_session();
1133    #a Nmap::Parser::Session object
1134
1135  my $host       = $np->get_host($ip_addr);
1136    #a Nmap::Parser::Host object
1137
1138  my $service = $host->tcp_service(80);
1139    #a Nmap::Parser::Host::Service object
1140
1141  my $os         = $host->os_sig();
1142    #a Nmap::Parser::Host::OS object
1143
1144 #---------------------------------------
1145
1146 my $np2 = new Nmap::Parser;
1147
1148 $np2->callback(\&my_callback);
1149
1150 $np2->parsefile($file_xml);
1151    #or
1152 $np2->parsescan($nmap_path, $nmap_args, @ips);
1153
1154 sub my_callback {
1155
1156   my $host = shift;
1157    #Nmap::Parser::Host object
1158    #.. see documentation for all methods ...
1159
1160 }
1161
1162
1163I<For a full listing of methods see the documentation corresponding to each object.>
1164You can also visit the website L<https://github.com/modernistik/Nmap-Parser> for additional installation instructions.
1165
1166=head1 DESCRIPTION
1167
1168This module implements a interface to the information contained in an nmap scan.
1169It is implemented by parsing the xml scan data that is generated by nmap. This
1170will enable anyone who utilizes nmap to quickly create fast and robust security scripts
1171that utilize the powerful port scanning abilities of nmap.
1172
1173The latest version of this module can be found on here L<https://github.com/modernistik/Nmap-Parser>
1174
1175=head1 OVERVIEW
1176
1177This module has an internal framework to make it easy to retrieve the desired information of a scan.
1178Every nmap scan is based on two main sections of informations: the scan session, and the scan information of all hosts.
1179The session information will be stored as a Nmap::Parser::Session object. This object will contain its own methods
1180to obtain the desired information. The same is true for any hosts that were scanned using the Nmap::Parser::Host object.
1181There are two sub objects under Nmap::Parser::Host. One is the Nmap::Parser::Host::Service object which will be used to obtain
1182information of a given service running on a given port. The second is the Nmap::Parser::Host::OS object which contains the
1183operating system signature information (OS guessed names, classes, osfamily..etc).
1184
1185  Nmap::Parser                        -- Core parser
1186     |
1187     +--Nmap::Parser::Session         -- Nmap scan session information
1188     |
1189     +--Nmap::Parser::Host            -- General host information
1190     |  |
1191     |  |-Nmap::Parser::Host::Service -- Port service information
1192     |  |
1193     |  |-Nmap::Parser::Host::OS      -- Operating system signature information
1194
1195
1196=head1 METHODS
1197
1198=head2 Nmap::Parser
1199
1200The main idea behind the core module is, you will first parse the information
1201and then extract data. Therefore, all parse*() methods should be executed before
1202any get_*() methods.
1203
1204=over 4
1205
1206
1207=item B<parse($string)>
1208
1209=item B<parse($filehandle)>
1210
1211Parses the nmap scan information in $string. Note that is usually only used if
1212you have the whole xml scan information in $string or if you are piping the
1213scan information.
1214
1215=item B<parsefile($xml_file)>
1216
1217Parses the nmap scan data in $xml_file. This file can be generated from an nmap
1218scan by using the '-oX filename.xml' option with nmap. If you get an error or your program dies due to parsing, please check that the
1219xml information is compliant. The file is closed no matter how C<parsefile()> returns.
1220
1221=item B<parsescan($nmap,$args,@ips)>
1222
1223This method runs an nmap scan where $nmap is the path to the nmap executable or binary,
1224$args are the nmap command line parameters, and @ips are the list of IP addresses
1225to scan. parsescan() will automagically run the nmap scan and parse the information.
1226
1227If you wish to save the xml output from parsescan(), you must call cache_scan() method B<BEFORE>
1228you start the parsescan() process. This is done to conserve memory while parsing. cache_scan() will
1229let Nmap::Parser know to save the output before parsing the xml since Nmap::Parser purges everything that has
1230been parsed by the script to conserve memory and increase speed.
1231
1232I<See section EXAMPLES for a short tutorial>
1233
1234I<Note: You cannot have one of the nmap options to be '-oX', '-oN' or '-oG'. Your
1235program will die if you try and pass any of these options because it decides the
1236type of output nmap will generate. The IP addresses can be nmap-formatted
1237addresses see nmap(1)>
1238
1239If you get an error or your program dies due to parsing, please check that the
1240xml information is compliant. If you are using parsescan() or an open filehandle
1241, make sure that the nmap scan that you are performing is successful in returning
1242xml information. (Sometimes using loopback addresses causes nmap to fail).
1243
1244=item B<cache_scan($filename)>
1245
1246This function allows you to save the output of a parsescan() (or nmap scan) to the disk. $filename
1247is the name of the file you wish to save the nmap scan information to. It defaults to nmap-parser-cache.xml
1248It returns the name of the file to be used as the cache.
1249
1250 #Must be called before parsescan().
1251 $np->cache_scan($filename); #output set to nmap-parser-cache.xml
1252
1253 #.. do other stuff to prepare for parsescan(), ex. setup callbacks
1254
1255 $np->parsescan('/usr/bin/nmap',$args,@IPS);
1256
1257=item B<purge()>
1258
1259Cleans the xml scan data from memory. This is useful if you have a program where
1260you are parsing lots of nmap scan data files with persistent variables.
1261
1262=item B<callback(\&code_ref)>
1263
1264Sets the parsing mode to be done using the callback function. It takes the parameter
1265of a code reference or a reference to a function. If no code reference is given,
1266it resets the mode to normal (no callback).
1267
1268 $np->callback(\&my_function); #sets callback, my_function() will be called
1269 $np->callback(); #resets it, no callback function called. Back to normal.
1270
1271
1272=item B<get_session()>
1273
1274Obtains the Nmap::Parser::Session object which contains the session scan information.
1275
1276=item B<get_host($ip_addr)>
1277
1278Obtains the Nmap::Parser::Host object for the given $ip_addr.
1279
1280=item B<del_host($ip_addr)>
1281
1282Deletes the stored Nmap::Parser::Host object whose IP is $ip_addr.
1283
1284=item B<all_hosts()>
1285
1286=item B<all_hosts($status)>
1287
1288Returns an array of all the Nmap::Parser::Host objects for the scan. If the optional
1289status is given, it will only return those hosts that match that status. The status
1290can be any of the following: C<(up|down|unknown|skipped)>
1291
1292=item B<get_ips()>
1293
1294=item B<get_ips($status)>
1295
1296Returns the list of IP addresses that were scanned in this nmap session. They are
1297sorted using addr_sort. If the optional status is given, it will only return
1298those IP addresses that match that status. The status can be any of the
1299following: C<(up|down|unknown|skipped)>
1300
1301=item B<addr_sort(@ips)>
1302
1303This function takes a list of IP addresses and returns the correctly sorted
1304version of the list.
1305
1306=back
1307
1308=head2 Nmap::Parser::Session
1309
1310This object contains the scan session information of the nmap scan.
1311
1312
1313=over 4
1314
1315
1316=item B<finish_time()>
1317
1318Returns the numeric time that the nmap scan finished.
1319
1320=item B<nmap_version()>
1321
1322Returns the version of nmap used for the scan.
1323
1324=item B<numservices()>
1325
1326=item B<numservices($type)>
1327
1328If numservices is called without argument, it returns the total number of services
1329that were scanned for all types. If $type is given, it returns the number of services
1330for that given scan type. See scan_types() for more info.
1331
1332=item B<scan_args()>
1333
1334Returns a string which contains the nmap executed command line used to run the
1335scan.
1336
1337=item B<scan_type_proto($type)>
1338
1339Returns the protocol type of the given scan type (provided by $type). See scan_types() for
1340more info.
1341
1342=item B<scan_types()>
1343
1344Returns the list of scan types that were performed. It can be any of the following:
1345C<(syn|ack|bounce|connect|null|xmas|window|maimon|fin|udp|ipproto)>.
1346
1347=item B<start_str()>
1348
1349Returns the human readable format of the start time.
1350
1351=item B<start_time()>
1352
1353Returns the numeric form of the time the nmap scan started.
1354
1355=item B<time_str()>
1356
1357Returns the human readable format of the finish time.
1358
1359=item B<xml_version()>
1360
1361Returns the version of nmap xml file.
1362
1363=item B<prescripts()>
1364
1365=item B<prescripts($name)>
1366
1367A basic call to prescripts() returns a list of the names of the NSE scripts
1368run in the pre-scanning phase. If C<$name> is given, it returns the text output of the
1369a reference to a hash with "output" and "contents" keys for the
1370script with that name, or undef if that script was not run.
1371The value of the "output" key is the text output of the script. The value of the
1372"contents" key is a data structure based on the XML output of the NSE script.
1373
1374=item B<postscripts()>
1375
1376=item B<postscripts($name)>
1377
1378A basic call to postscripts() returns a list of the names of the NSE scripts
1379run in the post-scaning phase. If C<$name> is given, it returns the text output of the
1380a reference to a hash with "output" and "contents" keys for the
1381script with that name, or undef if that script was not run.
1382The value of the "output" key is the text output of the script. The value of the
1383"contents" key is a data structure based on the XML output of the NSE script.
1384
1385=back
1386
1387=head2 Nmap::Parser::Host
1388
1389This object represents the information collected from a scanned host.
1390
1391
1392=over 4
1393
1394=item B<status()>
1395
1396Returns the state of the host. It is usually one of these
1397C<(up|down|unknown|skipped)>.
1398
1399=item B<addr()>
1400
1401Returns the main IP address of the host. This is usually the IPv4 address. If
1402there is no IPv4 address, the IPv6 is returned (hopefully there is one).
1403
1404=item B<addrtype()>
1405
1406Returns the address type of the address given by addr() .
1407
1408=item B<all_hostnames()>
1409
1410Returns a list of all hostnames found for the given host.
1411
1412=item B<extraports_count()>
1413
1414Returns the number of extraports found.
1415
1416=item B<extraports_state()>
1417
1418Returns the state of all the extraports found.
1419
1420=item B<hostname()>
1421
1422=item B<hostname($index)>
1423
1424As a basic call, hostname() returns the first hostname obtained for the given
1425host. If there exists more than one hostname, you can provide a number, which
1426is used as the location in the array. The index starts at 0;
1427
1428 #in the case that there are only 2 hostnames
1429 hostname() eq hostname(0);
1430 hostname(1); #second hostname found
1431 hostname(400) eq hostname(1) #nothing at 400; return the name at the last index
1432
1433
1434=item B<ipv4_addr()>
1435
1436Explicitly return the IPv4 address.
1437
1438=item B<ipv6_addr()>
1439
1440Explicitly return the IPv6 address.
1441
1442=item B<mac_addr()>
1443
1444Explicitly return the MAC address.
1445
1446=item B<mac_vendor()>
1447
1448Return the vendor information of the MAC.
1449
1450=item B<distance()>
1451
1452Return the distance (in hops) of the target machine from the machine that performed the scan.
1453
1454=item B<trace_error()>
1455
1456Returns a true value (usually a meaningful error message) if the traceroute was
1457performed but could not reach the destination. In this case C<all_trace_hops()>
1458contains only the part of the path that could be determined.
1459
1460=item B<all_trace_hops()>
1461
1462Returns an array of Nmap::Parser::Host::TraceHop objects representing the path
1463to the target host. This array may be empty if Nmap did not perform the
1464traceroute for some reason (same network, for example).
1465
1466Some hops may be missing if Nmap could not figure out information about them.
1467In this case there is a gap between the C<ttl()> values of consecutive returned
1468hops. See also C<trace_error()>.
1469
1470=item B<trace_proto()>
1471
1472Returns the name of the protocol used to perform the traceroute.
1473
1474=item B<trace_port()>
1475
1476Returns the port used to perform the traceroute.
1477
1478=item B<os_sig()>
1479
1480Returns an Nmap::Parser::Host::OS object that can be used to obtain all the
1481Operating System signature (fingerprint) information. See Nmap::Parser::Host::OS
1482for more details.
1483
1484 $os = $host->os_sig;
1485 $os->name;
1486 $os->osfamily;
1487
1488=item B<tcpsequence_class()>
1489
1490=item B<tcpsequence_index()>
1491
1492=item B<tcpsequence_values()>
1493
1494Returns the class, index and values information respectively of the tcp sequence.
1495
1496=item B<ipidsequence_class()>
1497
1498=item B<ipidsequence_values()>
1499
1500Returns the class and values information respectively of the ipid sequence.
1501
1502=item B<tcptssequence_class()>
1503
1504=item B<tcptssequence_values()>
1505
1506Returns the class and values information respectively of the tcpts sequence.
1507
1508=item B<uptime_lastboot()>
1509
1510Returns the human readable format of the timestamp of when the host had last
1511rebooted.
1512
1513=item B<uptime_seconds()>
1514
1515Returns the number of seconds that have passed since the host's last boot from
1516when the scan was performed.
1517
1518=item B<hostscripts()>
1519
1520=item B<hostscripts($name)>
1521
1522A basic call to hostscripts() returns a list of the names of the host scripts
1523run. If C<$name> is given, it returns the text output of the
1524a reference to a hash with "output" and "contents" keys for the
1525script with that name, or undef if that script was not run.
1526The value of the "output" key is the text output of the script. The value of the
1527"contents" key is a data structure based on the XML output of the NSE script.
1528
1529=item B<tcp_ports()>
1530
1531=item B<udp_ports()>
1532
1533Returns the sorted list of TCP|UDP ports respectively that were scanned on this host. Optionally
1534a string argument can be given to these functions to filter the list.
1535
1536 $host->tcp_ports('open') #returns all only 'open' ports (even 'open|filtered')
1537 $host->udp_ports('open|filtered'); #matches exactly ports with 'open|filtered'
1538
1539I<Note that if a port state is set to 'open|filtered' (or any combination), it will
1540be counted as an 'open' port as well as a 'filtered' one.>
1541
1542=item B<tcp_port_count()>
1543
1544=item B<udp_port_count()>
1545
1546Returns the total of TCP|UDP ports scanned respectively.
1547
1548=item B<tcp_port_state_ttl()>
1549
1550Returns the 'reason_ttl' value present in nmap xml result.
1551
1552=item B<tcp_del_ports($portid, [$portid, ...])>
1553
1554=item B<udp_del_ports($portid, [ $portid, ...])>
1555
1556Deletes the current $portid from the list of ports for given protocol.
1557
1558=item B<tcp_port_state($portid)>
1559
1560=item B<udp_port_state($portid)>
1561
1562Returns the state of the given port, provided by the port number in $portid.
1563
1564=item B<tcp_open_ports()>
1565
1566=item B<udp_open_ports()>
1567
1568Returns the list of open TCP|UDP ports respectively. Note that if a port state is
1569for example, 'open|filtered', it will appear on this list as well.
1570
1571=item B<tcp_filtered_ports()>
1572
1573=item B<udp_filtered_ports()>
1574
1575Returns the list of filtered TCP|UDP ports respectively. Note that if a port state is
1576for example, 'open|filtered', it will appear on this list as well.
1577
1578=item B<tcp_closed_ports()>
1579
1580=item B<udp_closed_ports()>
1581
1582Returns the list of closed TCP|UDP ports respectively. Note that if a port state is
1583for example, 'closed|filtered', it will appear on this list as well.
1584
1585=item B<tcp_service($portid)>
1586
1587=item B<udp_service($portid)>
1588
1589Returns the Nmap::Parser::Host::Service object of a given service running on port,
1590provided by $portid. See Nmap::Parser::Host::Service for more info.
1591
1592 $svc = $host->tcp_service(80);
1593 $svc->name;
1594 $svc->proto;
1595
1596
1597=back
1598
1599=head3 Nmap::Parser::Host::Service
1600
1601This object represents the service running on a given port in a given host. This
1602object is obtained by using the tcp_service($portid) or udp_service($portid) method from the
1603Nmap::Parser::Host object. If a portid is given that does not exist on the given
1604host, these functions will still return an object (so your script doesn't die).
1605Its good to use tcp_ports() or udp_ports() to see what ports were collected.
1606
1607=over 4
1608
1609
1610=item B<confidence()>
1611
1612Returns the confidence level in service detection.
1613
1614=item B<extrainfo()>
1615
1616Returns any additional information nmap knows about the service.
1617
1618=item B<method()>
1619
1620Returns the detection method.
1621
1622=item B<name()>
1623
1624Returns the service name.
1625
1626=item B<owner()>
1627
1628Returns the process owner of the given service. (If available)
1629
1630=item B<port()>
1631
1632Returns the port number where the service is running on.
1633
1634=item B<product()>
1635
1636Returns the product information of the service.
1637
1638=item B<proto()>
1639
1640Returns the protocol type of the service.
1641
1642=item B<rpcnum()>
1643
1644Returns the RPC number.
1645
1646=item B<tunnel()>
1647
1648Returns the tunnel value. (If available)
1649
1650=item B<fingerprint()>
1651
1652Returns the service fingerprint. (If available)
1653
1654=item B<version()>
1655
1656Returns the version of the given product of the running service.
1657
1658=item B<scripts()>
1659
1660=item B<scripts($name)>
1661
1662A basic call to scripts() returns a list of the names of the NSE scripts
1663run for this port. If C<$name> is given, it returns
1664a reference to a hash with "output" and "contents" keys for the
1665script with that name, or undef if that script was not run.
1666The value of the "output" key is the text output of the script. The value of the
1667"contents" key is a data structure based on the XML output of the NSE script.
1668
1669=back
1670
1671=head3 Nmap::Parser::Host::OS
1672
1673This object represents the Operating System signature (fingerprint) information
1674of the given host. This object is obtained from an Nmap::Parser::Host object
1675using the C<os_sig()> method. One important thing to note is that the order of OS
1676names and classes are sorted by B<DECREASING ACCURACY>. This is more important than
1677alphabetical ordering. Therefore, a basic call
1678to any of these functions will return the record with the highest accuracy.
1679(Which is probably the one you want anyways).
1680
1681=over 4
1682
1683=item B<all_names()>
1684
1685Returns the list of all the guessed OS names for the given host.
1686
1687=item B<class_accuracy()>
1688
1689=item B<class_accuracy($index)>
1690
1691A basic call to class_accuracy() returns the osclass accuracy of the first record.
1692If C<$index> is given, it returns the osclass accuracy for the given record. The
1693index starts at 0.
1694
1695=item B<class_count()>
1696
1697Returns the total number of OS class records obtained from the nmap scan.
1698
1699=item B<name()>
1700
1701=item B<name($index)>
1702
1703=item B<names()>
1704
1705=item B<names($index)>
1706
1707A basic call to name() returns the OS name of the first record which is the name
1708with the highest accuracy. If C<$index> is given, it returns the name for the given record. The
1709index starts at 0.
1710
1711=item B<name_accuracy()>
1712
1713=item B<name_accuracy($index)>
1714
1715A basic call to name_accuracy() returns the OS name accuracy of the first record. If C<$index> is given, it returns the name for the given record. The
1716index starts at 0.
1717
1718=item B<name_count()>
1719
1720Returns the total number of OS names (records) for the given host.
1721
1722=item B<osfamily()>
1723
1724=item B<osfamily($index)>
1725
1726A basic call to osfamily() returns the OS family information of the first record.
1727If C<$index> is given, it returns the OS family information for the given record. The
1728index starts at 0.
1729
1730=item B<osgen()>
1731
1732=item B<osgen($index)>
1733
1734A basic call to osgen() returns the OS generation information of the first record.
1735If C<$index> is given, it returns the OS generation information for the given record. The
1736index starts at 0.
1737
1738=item B<portused_closed()>
1739
1740Returns the closed port number used to help identify the OS signatures. This might not
1741be available for all hosts.
1742
1743=item B<portused_open()>
1744
1745Returns the open port number used to help identify the OS signatures. This might
1746not be available for all hosts.
1747
1748=item B<os_fingerprint()>
1749
1750Returns the OS fingerprint used to help identify the OS signatures. This might not be available for all hosts.
1751
1752=item B<type()>
1753
1754=item B<type($index)>
1755
1756A basic call to type() returns the OS type information of the first record.
1757If C<$index> is given, it returns the OS type information for the given record. The
1758index starts at 0.
1759
1760=item B<vendor()>
1761
1762=item B<vendor($index)>
1763
1764A basic call to vendor() returns the OS vendor information of the first record.
1765If C<$index> is given, it returns the OS vendor information for the given record. The
1766index starts at 0.
1767
1768=back
1769
1770=head3 Nmap::Parser::Host::TraceHop
1771
1772This object represents a router on the IP path towards the destination or the
1773destination itself. This is similar to what the C<traceroute> command outputs.
1774
1775Nmap::Parser::Host::TraceHop objects are obtained through the
1776C<all_trace_hops()> and C<trace_hop()> Nmap::Parser::Host methods.
1777
1778=over 4
1779
1780=item B<ttl()>
1781
1782The Time To Live is the network distance of this hop.
1783
1784=item B<rtt()>
1785
1786The Round Trip Time is roughly equivalent to the "ping" time towards this hop.
1787It is not always available (in which case it will be undef).
1788
1789=item B<ipaddr()>
1790
1791The known IP address of this hop.
1792
1793=item B<host()>
1794
1795The host name of this hop, if known.
1796
1797=back
1798
1799=head1 EXAMPLES
1800
1801I think some of us best learn from examples. These are a couple of examples to help
1802create custom security audit tools using some of the nice features
1803of the Nmap::Parser module. Hopefully this can double as a tutorial.
1804More tutorials (articles) can be found at L<https://github.com/modernistik/Nmap-Parser>
1805
1806=head2 Real-Time Scanning
1807
1808You can run a nmap scan and have the parser parse the information automagically.
1809The only constraint is that you cannot use '-oX', '-oN', or '-oG' as one of your
1810arguments for nmap command line parameters passed to parsescan().
1811
1812 use Nmap::Parser;
1813
1814 my $np = new Nmap::Parser;
1815 my @hosts = @ARGV; #get hosts from cmd line
1816
1817 #runs the nmap command with hosts and parses it automagically
1818 $np->parsescan('/usr/bin/nmap','-sS O -p 1-1023',@hosts);
1819
1820 for my $host ($np->all_hosts()){
1821 	print $host->hostname."\n";
1822	#do mor stuff...
1823 }
1824
1825If you would like to run the scan using parsescan() but also save the scan xml output,
1826you can use cache_scan(). You must call cache_scan() BEFORE you initiate the parsescan() method.
1827
1828 use Nmap::Parser;
1829 my $np = new Nmap::Parser;
1830
1831 #telling np to save output
1832 $np->cache_scan('nmap.localhost.xml');
1833 $np->parsescan('/usr/bin/nmap','-F','localhost');
1834 #do other stuff...
1835
1836=head2 Callbacks
1837
1838This is probably the easiest way to write a script with using Nmap::Parser,
1839if you don't need the general scan session information. During the parsing
1840process, the parser will obtain information of every host. The
1841callback function (in this case 'booyah()')  is called after the parsing of
1842every host (sequentially). When the callback returns, the parser will delete all
1843information of the host it had sent to the callback. This callback function is
1844called for every host that the parser encounters. I<The callback function must be
1845setup before parsing>
1846
1847 use Nmap::Parser;
1848 my $np = new Nmap::Parser;
1849
1850
1851 $np->callback( \&booyah );
1852
1853 $np->parsefile('nmap_results.xml');
1854    # or use parsescan()
1855
1856 sub booyah {
1857    my $host = shift; #Nmap::Parser::Host object, just parsed
1858    print 'IP: ',$host->addr,"\n";
1859	 # ... do more stuff with $host ...
1860
1861    #when it returns, host object will be deleted from memory
1862    #(good for processing VERY LARGE files or scans)
1863 }
1864
1865
1866=head2 Multiple Instances - (C<no less 'of'; my $self>)
1867
1868Using multiple instances of Nmap::Parser is extremely useful in helping
1869audit/monitor the network B<P>olicy (ohh noo! its that 'P' word!).
1870In this example, we have a set of hosts that had been scanned previously for tcp
1871services where the image was saved in I<base_image.xml>. We now will scan the
1872same hosts, and compare if any new tcp have been open since then
1873(good way to look for suspicious new services). Easy security B<C>ompliance detection.
1874(ooh noo! The 'C' word too!).
1875
1876
1877 use Nmap::Parser;
1878 use vars qw($nmap_exe $nmap_args @ips);
1879 my $base = new Nmap::Parser;
1880 my $curr = new Nmap::Parser;
1881
1882
1883 $base->parsefile('base_image.xml'); #load previous state
1884 $curr->parsescan($nmap_exe, $nmap_args, @ips); #scan current hosts
1885
1886 for my $ip ($curr->get_ips )
1887 {
1888 	#assume that IPs in base == IPs in curr scan
1889 	my $ip_base = $base->get_host($ip);
1890 	my $ip_curr = $curr->get_host($ip);
1891 	my %port = ();
1892
1893 	#find ports that are open that were not open before
1894 	#by finding the difference in port lists
1895	my @diff =  grep { $port{$_} < 2}
1896		   (map {$port{$_}++; $_}
1897		   ( $ip_curr->tcp_open_ports , $ip_base->tcp_open_ports ));
1898
1899	print "$ip has these new ports open: ".join(',',@diff) if(scalar @diff);
1900
1901	for (@diff){print "$_ seems to be ",$ip_curr->tcp_service($_)->name,"\n";}
1902
1903 }
1904
1905
1906=head1 SUPPORT
1907
1908=head2 Discussion Forum
1909
1910If you have questions about how to use the module, or any of its features, you
1911can post messages to the Nmap::Parser module forum on CPAN::Forum.
1912L<https://github.com/modernistik/Nmap-Parser/issues>
1913
1914=head2 Bug Reports, Enhancements, Merge Requests
1915
1916Please submit any bugs or feature requests to:
1917L<https://github.com/modernistik/Nmap-Parser/issues>
1918
1919B<Please make sure that you submit the xml-output file of the scan which you are having
1920trouble with.> This can be done by running your scan with the I<-oX filename.xml> nmap switch.
1921Please remove any important IP addresses for security reasons. It saves time in reproducing issues.
1922
1923=head1 SEE ALSO
1924
1925 nmap, XML::Twig
1926
1927The Nmap::Parser page can be found at: L<https://github.com/modernistik/Nmap-Parser>.
1928It contains the latest developments on the module. The nmap security scanner
1929homepage can be found at: L<http://www.insecure.org/nmap/>.
1930
1931=head1 AUTHORS
1932
1933Origiinal author, Anthony Persaud L<https://www.modernistik.com>. However, special thanks to: Daniel Miller L<https://github.com/bonsaiviking> and Robin Bowes L<http://robinbowes.com>.
1934Please see Changes.md file for a list of other great contributors.
1935
1936=head1 COPYRIGHT
1937Copyright (c) <2003-2017> <Anthony Persaud> L<https://www.modernistik.com>
1938
1939MIT License
1940
1941Permission is hereby granted, free of charge, to any person obtaining a copy
1942of this software and associated documentation files (the "Software"), to deal
1943in the Software without restriction, including without limitation the rights
1944to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1945copies of the Software, and to permit persons to whom the Software is
1946furnished to do so, subject to the following conditions:
1947
1948The above copyright notice and this permission notice shall be included in
1949all copies or substantial portions of the Software.
1950
1951THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1952IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1953FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1954AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1955LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1956OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1957THE SOFTWARE.
1958
1959=cut
1960