File Coverage

blib/lib/NetworkInfo/Discovery/Nmap.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package NetworkInfo::Discovery::Nmap;
2 5     5   69356 use strict;
  5         12  
  5         183  
3 5     5   27 use Carp;
  5         11  
  5         385  
4 5     5   9495 use Nmap::Scanner;
  0            
  0            
5             use NetworkInfo::Discovery::Detect;
6              
7             { no strict;
8             $VERSION = '0.02';
9             @ISA = qw(NetworkInfo::Discovery::Detect);
10             }
11              
12             =head1 NAME
13              
14             NetworkInfo::Discovery::Nmap - NetworkInfo::Discovery extension using Nmap
15              
16             =head1 VERSION
17              
18             Version 0.02
19              
20             =head1 SYNOPSIS
21              
22             use NetworkInfo::Discovery::Nmap;
23              
24             my $scanner = NetworkInfo::Discovery::Nmap->new(
25             hosts => [ qw( 192.168.0.0/24 192.168.1.0/24 ) ],
26             );
27             $scanner->do_it;
28              
29             See F for a more complete example.
30              
31             =head1 DESCRIPTION
32              
33             This module is an extension to C which uses the
34             Nmap utility to scan networks, find active hosts, their services and
35             operating system.
36              
37             =head1 METHODS
38              
39             =over 4
40              
41             =item new()
42              
43             Creates and returns a new C object, which
44             derives from C.
45              
46             B
47              
48             =over 4
49              
50             =item *
51              
52             C - expects a scalar or an arrayref of IP addresses in CIDR notation
53              
54             =item *
55              
56             C - expects a scalar or an arrayref with a port or a ports range
57              
58             =item *
59              
60             C - when enabled, tells nmap to use TCP/IP fingerprinting
61             to guess remote operating system (note: root privileges required).
62             Default is 0 (disabled).
63              
64             =back
65              
66             B
67              
68             # specify one host
69             my $scanner = new NetworkInfo::Discovery::Nmap hosts => '192.168.0.0/24';
70            
71             # specify several hosts
72             my $scanner = new NetworkInfo::Discovery::Nmap hosts => [ qw(192.168.0.0/24) ];
73              
74             =cut
75              
76             sub new {
77             my $class = shift;
78             my $self = $class->SUPER::new();
79             my %args = @_;
80            
81             $class = ref($class) || $class;
82             bless $self, $class;
83            
84             # add private fields
85             $self->{_hosts_to_scan} = [];
86             $self->{_ports_to_scan} = [];
87            
88             # treat given arguments
89             for my $attr (keys %args) {
90             $self->$attr($args{$attr}) if $self->can($attr);
91             }
92            
93             return $self
94             }
95              
96             =item do_it()
97              
98             Run the scan.
99              
100             =cut
101              
102             sub do_it {
103             my $self = shift;
104             my @hosts = ();
105            
106             # initialize the scanner
107             my $scanner = new Nmap::Scanner;
108             map { $scanner->add_target($_) } $self->hosts;
109             map { $scanner->add_scan_port($_) } $self->ports;
110             $scanner->no_ping;
111             $scanner->version_scan;
112             $scanner->guess_os if $self->{_nmap_options}{guess_system};
113            
114             # run the scan
115             my $results = $scanner->scan;
116            
117             # add found information
118             my $list = $results->get_host_list;
119             while(my $host = $list->get_next) {
120             next unless $host->status eq 'up';
121             my %host_info = ( services => [] );
122            
123             # get its address
124             my %addrs = map { $_->addr => $_->addrtype } $host->addresses;
125             for my $addr (keys %addrs) {
126             $host_info{ip} = $addr if $addrs{$addr} eq 'ipv4';
127             $host_info{mac} = $addr if $addrs{$addr} eq 'mac';
128             }
129             $host_info{smurf} = $host->smurf;
130            
131             # get ports information
132             my $portlist = $host->get_port_list;
133             while(my $port = $portlist->get_next) {
134             my %port_info = ();
135             $port_info{port} = $port->portid;
136             map { $port_info{$_} = $port->$_ || '' } qw(owner protocol state);
137             $port_info{name} = $port->service->name || '';
138             $port_info{rpcnum} = $port->service->rpcnum || '';
139             $port_info{application} = {};
140             map { $port_info{application}{$_} = $port->service->$_ || '' } qw(product version extrainfo);
141             push @{$host_info{services}}, { %port_info };
142             }
143            
144             # get operating system information
145             if(my $guess_os = $host->os) {
146             $host_info{system_info} = {
147             os_classes => [],
148             os_matches => [],
149             uptime => $guess_os->uptime->seconds || 0,
150             last_boot => $guess_os->uptime->lastboot || '',
151             };
152            
153             for my $os_class ($guess_os->osclasses) {
154             push @{$host_info{system_info}{os_classes}}, {
155             vendor => $os_class->vendor, type => $os_class->type,
156             family => $os_class->osfamily, version => $os_class->osgen,
157             accuracy => $os_class->accuracy
158             }
159             }
160            
161             for my $os_match ($guess_os->osmatches) {
162             push @{$host_info{system_info}{os_matches}}, {
163             name => $os_match->name, accuracy => $os_match->accuracy
164             }
165             }
166             }
167            
168             push @hosts, { %host_info };
169             }
170            
171             # add found hosts
172             $self->add_interface(@hosts);
173            
174             # return list of found hosts
175             return $self->get_interfaces
176             }
177              
178             =item hosts()
179              
180             Add hosts or networks to the scan list. Expects addresses in CIDR notation.
181             Return the current list of hosts when called with no argument.
182              
183             B
184              
185             $scanner->hosts('192.168.4.53'); # add one host
186             $scanner->hosts('192.168.5.48/29'); # add a subnet
187             $scanner->hosts(qw(192.168.6.0/30 10.0.0.3/28)); # add two subnets
188              
189             =cut
190              
191             sub hosts {
192             my $self = shift;
193             if(@_ ==0) {
194             return @{$self->{_hosts_to_scan}}
195             } elsif(ref $_[0] eq 'ARRAY') {
196             push @{$self->{_hosts_to_scan}}, @{$_[0]}
197             } elsif(ref $_[0]) {
198             croak "Don't know how to deal with a ", lc(ref($_[0])), "ref."
199             } else {
200             push @{$self->{_hosts_to_scan}}, @_
201             }
202             }
203              
204             =item ports()
205              
206             Add ports to the scan list.
207             Expects single ports (e.g. '8080') or ports ranges (e.g. '1-123').
208             Return the current list of ports when called with no argument.
209              
210             B
211              
212             $scanner->ports('8080'); # add one port
213             $scanner->ports('1-123'); # add a ports range
214             $scanner->ports(qw(137-139 201-208)); # add two ports ranges
215              
216             =cut
217              
218             sub ports {
219             my $self = shift;
220             if(@_ ==0) {
221             return @{$self->{_ports_to_scan}}
222             } elsif(ref $_[0] eq 'ARRAY') {
223             push @{$self->{_ports_to_scan}}, @{$_[0]}
224             } elsif(ref $_[0]) {
225             croak "Don't know how to deal with a ", lc(ref($_[0])), "ref."
226             } else {
227             push @{$self->{_ports_to_scan}}, @_
228             }
229             }
230              
231             =item guess_system()
232              
233             When enabled, tells nmap to use TCP/IP fingerprinting to guess remote
234             operating system (note: root privileges required).
235             Default is 0 (disabled).
236              
237             =cut
238              
239             # accessors
240             for my $attr (qw(guess_system)) {
241             no strict 'refs';
242             *{__PACKAGE__.'::'.$attr} = sub {
243             my $self = shift;
244             my $old = $self->{_nmap_options}{$attr};
245             $self->{_nmap_options}{$attr} = $_[0] if $_[0];
246             return $old;
247             }
248             }
249              
250             =back
251              
252             =head1 SEE ALSO
253              
254             L, L
255              
256             =head1 AUTHOR
257              
258             SEbastien Aperghis-Tramoni, Esebastien@aperghis.netE
259              
260             =head1 BUGS
261              
262             Please report any bugs or feature requests to
263             C, or through the web interface at
264             L.
265             I will be notified, and then you'll automatically be notified of progress
266             on your bug as I make changes.
267              
268             =head1 COPYRIGHT & LICENSE
269              
270             Copyright 2004 SEbastien Aperghis-Tramoni, All Rights Reserved.
271              
272             This program is free software; you can redistribute it and/or modify it
273             under the same terms as Perl itself.
274              
275             =cut
276              
277             1; # End of NetworkInfo::Discovery::Nmap