File: HostEnumeration.pm

package info (click to toggle)
munin 2.0.76-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 7,064 kB
  • sloc: perl: 11,684; java: 1,924; sh: 1,632; makefile: 636; javascript: 365; python: 267
file content (126 lines) | stat: -rw-r--r-- 2,837 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package Munin::Node::Configure::HostEnumeration;

use strict;
use warnings;

use Socket;

use Munin::Node::Configure::Debug;

use Exporter ();
our @ISA = qw/Exporter/;
our @EXPORT = qw/expand_hosts/;


### Network address manipulation ###############################################

# converts a hostname or IP and an optional netmask into a list of the
# hostnames and/or IPs in that network.
#
# If you haven't guessed, this is IPv4 only.
sub _hosts_in_net
{
    my ($host, $mask) = @_;
    my @ret;

    # avoid losing the hostname that was provided.  makes for more appropriate
    # links in the servicedir.
    #
    # FIXME: this is very limited.  make it work in the case when a netmask is
    # provided (substitute the hostname for the corresponding IP in the list
    # that is returned.
    unless (defined $mask) {
        return $host;
    }

    my $addr = _resolve($host);

    die "Invalid netmask: $mask\n"
        unless ($mask =~ /^\d+$/ and $mask <= 32);

    my $net = unpack('N', $addr);  # ntohl()

    # Evil maths courtesy of nmap's TargetGroup.cc
    my $low  = $net & (0 - (1 << (32 - $mask)));
    my $high = $net | ((1 << (32 - $mask)) - 1);

    # Note that the .. operator uses signed integers.  Hence the loop.
    for (my $ip = $low; $ip <= $high; $ip++) {
        push @ret, inet_ntoa(pack 'N', $ip);
    }
    return @ret;
}


# Resolves a hostname or IP, and returns the address as a bitstring in
# network byte order.
sub _resolve
{
    my ($host) = @_;

    my ($name, $aliases, $addrtype, $length, @addrs) = gethostbyname($host);
    die "Unable to resolve $host\n" unless $name;

    if (scalar @addrs > 1) {
        warn sprintf "# Hostname %s resolves to %u IPs.  Using %s\n",
                           $host,
                           scalar(@addrs),
                           inet_ntoa($addrs[0]);
    }
    DEBUG(sprintf "# Resolved %s to %s", $host, inet_ntoa($addrs[0]));

    return $addrs[0];
}


sub expand_hosts
{
    my (@unexpanded) = @_;
    my @hosts;

    foreach my $item (@unexpanded) {
        DEBUG("Processing $item");
        my ($host, $mask) = split '/', $item, 2;
        push @hosts, _hosts_in_net($host, $mask);
    }
    return @hosts;
}


1;

__END__

=head1 NAME

Munin::Node::Configure::HostEnumeration - Takes a list of hosts, and returns
the corresponding IPs in dotted-quad form.


=head1 SYNOPSIS

  @hosts = ('switch1', 'host1/24', '10.0.0.60/30');
  foreach my $host (expand_hosts(@hosts)) {
      # ...
  }


=head1 SUBROUTINES

=over

=item B<expand_hosts>

  @expanded = expand_hosts(@list);

Takes a list of hosts, and returns the corresponding IPs in dotted-quad form.

Items can be specified as a hostname or dotted-quad IP, either with or
without a netmask.

Currently only IPv4 addresses are supported.

=back

=cut
# vim: ts=4 : sw=4 : expandtab