This is probably the least portable version because it uses Linux-specific data structures, but for the fun of it and for completeness, I'll post it:
#!/usr/bin/perl
use strict;
use warnings;
require 'sys/ioctl.ph';
use Socket;
my %interfaces;
my $max_addrs = 30;
socket(my $socket, AF_INET, SOCK_DGRAM, 0) or die "socket: $!";
{
my $ifreqpack = 'a16a16';
my $buf = pack($ifreqpack, '', '') x $max_addrs;
my $ifconf = pack('iP', length($buf), $buf);
# This does the actual work
ioctl($socket, SIOCGIFCONF(), $ifconf) or die "ioctl: $!";
my $len = unpack('iP', $ifconf);
substr($buf, $len) = '';
%interfaces = unpack("($ifreqpack)*", $buf);
unless (keys(%interfaces) < $max_addrs) {
# Buffer was too small
$max_addrs += 10;
redo;
}
}
for my $addr (values %interfaces) {
$addr = inet_ntoa((sockaddr_in($addr))[1]);
}
use Data::Dumper;
print Dumper \%interfaces;
The output is:
$VAR1 = {
'eth0:1' => '10.153.26.128',
'eth0' => 'x.y.z.128',
'eth0:3' => '10.153.84.128',
'eth0:4' => '10.153.88.2',
'eth0:2' => 'x.y.z.62',
'lo' => '127.0.0.1'
};
(I've stripped the public addresses.)
I've successfully tested it on Debian etch and sarge.