2010-05-07 01:58:02 +00:00
|
|
|
#!/usr/bin/env perl
|
|
|
|
# IBM(c) 2010 EPL license http://www.eclipse.org/legal/epl-v10.html
|
2010-05-07 01:59:49 +00:00
|
|
|
package xCAT::NetworkUtils;
|
2010-05-07 01:58:02 +00:00
|
|
|
|
|
|
|
BEGIN
|
|
|
|
{
|
|
|
|
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
|
|
|
|
}
|
|
|
|
|
|
|
|
# if AIX - make sure we include perl 5.8.2 in INC path.
|
|
|
|
# Needed to find perl dependencies shipped in deps tarball.
|
|
|
|
if ($^O =~ /^aix/i) {
|
|
|
|
use lib "/usr/opt/perl5/lib/5.8.2/aix-thread-multi";
|
|
|
|
use lib "/usr/opt/perl5/lib/5.8.2";
|
|
|
|
use lib "/usr/opt/perl5/lib/site_perl/5.8.2/aix-thread-multi";
|
|
|
|
use lib "/usr/opt/perl5/lib/site_perl/5.8.2";
|
|
|
|
}
|
|
|
|
|
|
|
|
use lib "$::XCATROOT/lib/perl";
|
|
|
|
use POSIX qw(ceil);
|
|
|
|
use File::Path;
|
|
|
|
use Socket;
|
|
|
|
use strict;
|
|
|
|
use warnings "all";
|
2010-05-07 09:27:18 +00:00
|
|
|
my $netipmodule = eval {require Net::IP;};
|
2010-08-26 15:46:11 +00:00
|
|
|
my $socket6support = eval { require Socket6 };
|
2010-05-07 01:58:02 +00:00
|
|
|
|
|
|
|
our @ISA = qw(Exporter);
|
|
|
|
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
=head1 xCAT::NetworkUtils
|
|
|
|
|
|
|
|
=head2 Package Description
|
|
|
|
|
|
|
|
This program module file, is a set of network utilities used by xCAT commands.
|
|
|
|
|
|
|
|
=cut
|
|
|
|
|
|
|
|
#-------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
=head3 gethostnameandip
|
|
|
|
Works for both IPv4 and IPv6.
|
|
|
|
Takes either a host name or an IP address string
|
|
|
|
and performs a lookup on that name,
|
|
|
|
returns an array with two elements: the hostname, the ip address
|
|
|
|
if the host name or ip address can not be resolved,
|
|
|
|
the corresponding element in the array will be undef
|
|
|
|
Arguments:
|
|
|
|
hostname or ip address
|
|
|
|
Returns: the hostname and the ip address
|
|
|
|
Globals:
|
|
|
|
|
|
|
|
Error:
|
|
|
|
none
|
|
|
|
Example:
|
2010-05-13 11:59:49 +00:00
|
|
|
my ($host, $ip) = xCAT::NetworkUtils->gethostnameandip($iporhost);
|
2010-05-07 01:58:02 +00:00
|
|
|
Comments:
|
|
|
|
none
|
|
|
|
=cut
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
sub gethostnameandip()
|
|
|
|
{
|
|
|
|
my ($class, $iporhost) = @_;
|
|
|
|
|
|
|
|
if (($iporhost =~ /\d+\.\d+\.\d+\.\d+/) || ($iporhost =~ /:/)) #ip address
|
|
|
|
{
|
2010-05-07 02:53:44 +00:00
|
|
|
return (xCAT::NetworkUtils->gethostname($iporhost), $iporhost);
|
2010-05-07 01:58:02 +00:00
|
|
|
}
|
|
|
|
else #hostname
|
|
|
|
{
|
2010-05-07 02:53:44 +00:00
|
|
|
return ($iporhost, xCAT::NetworkUtils->getipaddr($iporhost));
|
2010-05-07 01:58:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
=head3 gethostname
|
|
|
|
Works for both IPv4 and IPv6.
|
|
|
|
Takes an IP address string and performs a lookup on that name,
|
|
|
|
returns the hostname of the ip address
|
|
|
|
if the ip address can not be resolved, returns undef
|
|
|
|
Arguments:
|
|
|
|
ip address
|
|
|
|
Returns: the hostname
|
|
|
|
Globals:
|
|
|
|
cache: %::iphosthash
|
|
|
|
Error:
|
|
|
|
none
|
|
|
|
Example:
|
2010-05-07 02:53:44 +00:00
|
|
|
my $host = xCAT::NetworkUtils->gethostname($ip);
|
2010-05-07 01:58:02 +00:00
|
|
|
Comments:
|
|
|
|
none
|
|
|
|
=cut
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
sub gethostname()
|
|
|
|
{
|
|
|
|
my ($class, $iporhost) = @_;
|
|
|
|
|
2010-09-29 21:12:51 +00:00
|
|
|
if (!defined($iporhost))
|
|
|
|
{
|
|
|
|
return undef;
|
|
|
|
}
|
2010-09-25 03:08:46 +00:00
|
|
|
|
2010-09-29 21:12:51 +00:00
|
|
|
if (ref($iporhost) eq 'ARRAY')
|
|
|
|
{
|
2010-05-11 14:03:58 +00:00
|
|
|
$iporhost = @{$iporhost}[0];
|
|
|
|
if (!$iporhost)
|
|
|
|
{
|
|
|
|
return undef;
|
|
|
|
}
|
2010-09-29 21:12:51 +00:00
|
|
|
}
|
2010-05-11 14:03:58 +00:00
|
|
|
|
2010-05-07 01:58:02 +00:00
|
|
|
if (($iporhost !~ /\d+\.\d+\.\d+\.\d+/) && ($iporhost !~ /:/))
|
|
|
|
{
|
|
|
|
#why you do so? pass in a hostname and only want a hostname??
|
|
|
|
return $iporhost;
|
|
|
|
}
|
|
|
|
#cache, do not lookup DNS each time
|
|
|
|
if (defined($::iphosthash{$iporhost}) && $::iphosthash{$iporhost})
|
|
|
|
{
|
|
|
|
return $::iphosthash{$iporhost};
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ($socket6support) # the getaddrinfo and getnameinfo supports both IPv4 and IPv6
|
|
|
|
{
|
2010-05-07 09:56:01 +00:00
|
|
|
my ($family, $socket, $protocol, $ip, $name) = Socket6::getaddrinfo($iporhost,0);
|
|
|
|
my $host = (Socket6::getnameinfo($ip))[0];
|
2010-05-07 01:58:02 +00:00
|
|
|
if ($host eq $iporhost) # can not resolve
|
|
|
|
{
|
|
|
|
return undef;
|
|
|
|
}
|
|
|
|
if ($host)
|
|
|
|
{
|
|
|
|
$host =~ s/\..*//; #short hostname
|
|
|
|
}
|
|
|
|
return $host;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-05-14 01:36:40 +00:00
|
|
|
#it is possible that no Socket6 available,
|
|
|
|
#but passing in IPv6 address, such as ::1 on loopback
|
|
|
|
if ($iporhost =~ /:/)
|
|
|
|
{
|
|
|
|
return undef;
|
|
|
|
}
|
2010-05-07 01:58:02 +00:00
|
|
|
my $hostname = gethostbyaddr(inet_aton($iporhost), AF_INET);
|
|
|
|
$hostname =~ s/\..*//; #short hostname
|
|
|
|
return $hostname;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
=head3 getipaddr
|
|
|
|
Works for both IPv4 and IPv6.
|
|
|
|
Takes a hostname string and performs a lookup on that name,
|
|
|
|
returns the the ip address of the hostname
|
|
|
|
if the hostname can not be resolved, returns undef
|
|
|
|
Arguments:
|
|
|
|
hostname
|
|
|
|
Returns: ip address
|
|
|
|
Globals:
|
|
|
|
cache: %::hostiphash
|
|
|
|
Error:
|
|
|
|
none
|
|
|
|
Example:
|
2010-05-07 02:53:44 +00:00
|
|
|
my $ip = xCAT::NetworkUtils->getipaddr($hostname);
|
2010-05-07 01:58:02 +00:00
|
|
|
Comments:
|
|
|
|
none
|
|
|
|
=cut
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
sub getipaddr()
|
|
|
|
{
|
|
|
|
my ($class, $iporhost) = @_;
|
|
|
|
|
2010-09-25 03:08:46 +00:00
|
|
|
if (!defined($iporhost))
|
|
|
|
{
|
|
|
|
return undef;
|
|
|
|
}
|
|
|
|
|
2010-05-11 14:03:58 +00:00
|
|
|
if (ref($iporhost) eq 'ARRAY')
|
|
|
|
{
|
|
|
|
$iporhost = @{$iporhost}[0];
|
|
|
|
if (!$iporhost)
|
|
|
|
{
|
|
|
|
return undef;
|
|
|
|
}
|
|
|
|
}
|
2010-05-07 01:58:02 +00:00
|
|
|
|
2010-09-29 21:12:51 +00:00
|
|
|
if ($iporhost and ($iporhost =~ /\d+\.\d+\.\d+\.\d+/) || ($iporhost =~ /:/))
|
2010-05-07 01:58:02 +00:00
|
|
|
{
|
|
|
|
#pass in an ip and only want an ip??
|
|
|
|
return $iporhost;
|
|
|
|
}
|
|
|
|
|
|
|
|
#cache, do not lookup DNS each time
|
2010-09-29 21:12:51 +00:00
|
|
|
if ($::hostiphash and defined($::hostiphash{$iporhost}) && $::hostiphash{$iporhost})
|
2010-05-07 01:58:02 +00:00
|
|
|
{
|
|
|
|
return $::hostiphash{$iporhost};
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ($socket6support) # the getaddrinfo and getnameinfo supports both IPv4 and IPv6
|
|
|
|
{
|
2010-05-07 09:56:01 +00:00
|
|
|
my ($family, $socket, $protocol, $ip, $name) = Socket6::getaddrinfo($iporhost,0);
|
2010-05-07 01:58:02 +00:00
|
|
|
if ($ip)
|
|
|
|
{
|
2010-05-07 09:56:01 +00:00
|
|
|
return (Socket6::getnameinfo($ip, Socket6::NI_NUMERICHOST()))[0];
|
2010-05-07 01:58:02 +00:00
|
|
|
}
|
|
|
|
return undef;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-05-11 14:03:58 +00:00
|
|
|
#return inet_ntoa(inet_aton($iporhost))
|
2010-05-14 01:36:40 +00:00
|
|
|
#TODO, what if no scoket6 support, but passing in a IPv6 hostname?
|
2010-09-29 21:12:51 +00:00
|
|
|
my $packed_ip;
|
|
|
|
$iporhost and $packed_ip = inet_aton($iporhost);
|
2010-05-11 14:03:58 +00:00
|
|
|
if (!$packed_ip)
|
|
|
|
{
|
|
|
|
return undef;
|
|
|
|
}
|
|
|
|
return inet_ntoa($packed_ip);
|
2010-05-07 01:58:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
=head3 linklocaladdr
|
|
|
|
Only for IPv6.
|
|
|
|
Takes a mac address, calculate the IPv6 link local address
|
|
|
|
Arguments:
|
|
|
|
mac address
|
|
|
|
Returns:
|
|
|
|
ipv6 link local address. returns undef if passed in a invalid mac address
|
|
|
|
Globals:
|
|
|
|
Error:
|
|
|
|
none
|
|
|
|
Example:
|
2010-05-07 02:53:44 +00:00
|
|
|
my $linklocaladdr = xCAT::NetworkUtils->linklocaladdr($mac);
|
2010-05-07 01:58:02 +00:00
|
|
|
Comments:
|
|
|
|
none
|
|
|
|
=cut
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
sub linklocaladdr {
|
|
|
|
my ($class, $mac) = @_;
|
|
|
|
$mac = lc($mac);
|
|
|
|
my $localprefix = "fe80";
|
|
|
|
|
|
|
|
my ($m1, $m2, $m3, $m6, $m7, $m8);
|
|
|
|
# mac address can be 00215EA376B0 or 00:21:5E:A3:76:B0
|
|
|
|
if($mac =~ /^([0-9A-Fa-f]{2}).*?([0-9A-Fa-f]{2}).*?([0-9A-Fa-f]{2}).*?([0-9A-Fa-f]{2}).*?([0-9A-Fa-f]{2}).*?([0-9A-Fa-f]{2})$/)
|
|
|
|
{
|
|
|
|
($m1, $m2, $m3, $m6, $m7, $m8) = ($1, $2, $3, $4, $5, $6);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#not a valid mac address
|
|
|
|
return undef;
|
|
|
|
}
|
|
|
|
my ($m4, $m5) = ("ff","fe");
|
|
|
|
|
2010-05-27 07:40:10 +00:00
|
|
|
#my $bit = (int $m1) & 2;
|
|
|
|
#if ($bit) {
|
|
|
|
# $m1 = $m1 - 2;
|
|
|
|
#} else {
|
|
|
|
# $m1 = $m1 + 2;
|
|
|
|
#}
|
|
|
|
$m1 = hex($m1);
|
|
|
|
$m1 = $m1 ^ 2;
|
|
|
|
$m1 = sprintf("%x", $m1);
|
2010-05-07 01:58:02 +00:00
|
|
|
|
|
|
|
$m1 = $m1 . $m2;
|
|
|
|
$m3 = $m3 . $m4;
|
|
|
|
$m5 = $m5 . $m6;
|
|
|
|
$m7 = $m7 . $m8;
|
|
|
|
|
|
|
|
my $laddr = join ":", $m1, $m3, $m5, $m7;
|
|
|
|
$laddr = join "::", $localprefix, $laddr;
|
|
|
|
|
|
|
|
return $laddr;
|
|
|
|
}
|
|
|
|
|
2010-05-07 03:49:05 +00:00
|
|
|
|
2010-05-07 01:58:02 +00:00
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
=head3 ishostinsubnet
|
|
|
|
Works for both IPv4 and IPv6.
|
|
|
|
Takes an ip address, the netmask and a subnet,
|
|
|
|
chcek if the ip address is in the subnet
|
|
|
|
Arguments:
|
|
|
|
ip address, netmask, subnet
|
|
|
|
Returns:
|
|
|
|
1 - if the ip address is in the subnet
|
|
|
|
0 - if the ip address is NOT in the subnet
|
|
|
|
Globals:
|
|
|
|
Error:
|
|
|
|
none
|
|
|
|
Example:
|
2010-05-07 02:53:44 +00:00
|
|
|
if(xCAT::NetworkUtils->ishostinsubnet($ip, $netmask, $subnet);
|
2010-05-07 01:58:02 +00:00
|
|
|
Comments:
|
|
|
|
none
|
|
|
|
=cut
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
sub ishostinsubnet {
|
2010-05-07 03:49:05 +00:00
|
|
|
my ($class, $ip, $mask, $subnet) = @_;
|
2010-05-07 01:58:02 +00:00
|
|
|
|
|
|
|
if ($ip =~ /\d+\.\d+\.\d+\.\d+/) {# ipv4 address
|
|
|
|
$ip =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/;
|
|
|
|
my $ipnum = ($1<<24)+($2<<16)+($3<<8)+$4;
|
|
|
|
|
|
|
|
$mask =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/;
|
|
|
|
my $masknum = ($1<<24)+($2<<16)+($3<<8)+$4;
|
|
|
|
|
|
|
|
$subnet =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/;
|
|
|
|
my $netnum = ($1<<24)+($2<<16)+($3<<8)+$4;
|
|
|
|
|
|
|
|
if (($ipnum & $masknum) == $netnum) {
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else { # for ipv6
|
2010-05-07 09:27:18 +00:00
|
|
|
if ($netipmodule) {
|
|
|
|
my $eip = Net::IP::ip_expand_address ($ip,6);
|
|
|
|
my $enet = Net::IP::ip_expand_address ($subnet,6);
|
|
|
|
my $bmask = Net::IP::ip_get_mask($mask,6);
|
|
|
|
my $bip = Net::IP::ip_iptobin($eip,6);
|
|
|
|
my $bipnet = $bip & $bmask;
|
|
|
|
my $bnet = Net::IP::ip_iptobin($enet,6);
|
2010-06-02 03:20:38 +00:00
|
|
|
if (!$bipnet || !$bnet)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2010-05-07 09:27:18 +00:00
|
|
|
if ($bipnet == $bnet) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
} # else, can not check without Net::IP module
|
|
|
|
return 0;
|
2010-05-07 01:58:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-27 15:13:26 +00:00
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
=head3 setup_ip_forwarding
|
|
|
|
|
|
|
|
Sets up ip forwarding on localhost
|
|
|
|
|
|
|
|
=cut
|
|
|
|
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
sub setup_ip_forwarding
|
|
|
|
{
|
|
|
|
my ($class, $enable)=@_;
|
|
|
|
if (xCAT::Utils->isLinux()) {
|
|
|
|
my $conf_file="/etc/sysctl.conf";
|
|
|
|
`grep "net.ipv4.ip_forward" $conf_file`;
|
|
|
|
if ($? == 0) {
|
|
|
|
`sed -i "s/^net.ipv4.ip_forward = .*/net.ipv4.ip_forward = $enable/" $conf_file`;
|
|
|
|
} else {
|
|
|
|
`echo "net.ipv4.ip_forward = $enable" >> $conf_file`;
|
|
|
|
}
|
|
|
|
`sysctl -p $conf_file`;
|
|
|
|
}
|
|
|
|
else
|
2010-06-01 14:27:13 +00:00
|
|
|
{
|
|
|
|
`no -o ipforwarding=$enable`;
|
2010-05-27 15:13:26 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-06-17 07:18:00 +00:00
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
=head3 prefixtomask
|
|
|
|
Convert the IPv6 prefix length(e.g. 64) to the netmask(e.g. ffff:ffff:ffff:ffff:0000:0000:0000:0000).
|
|
|
|
Till now, the netmask format ffff:ffff:ffff:: only works for AIX NIM
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
prefix length
|
|
|
|
Returns:
|
|
|
|
netmask - netmask like ffff:ffff:ffff:ffff:0000:0000:0000:0000
|
|
|
|
0 - if the prefix length is not correct
|
|
|
|
Globals:
|
|
|
|
Error:
|
|
|
|
none
|
|
|
|
Example:
|
|
|
|
my #netmask = xCAT::NetworkUtils->prefixtomask($prefixlength);
|
|
|
|
Comments:
|
|
|
|
none
|
|
|
|
=cut
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
sub prefixtomask {
|
|
|
|
my ($class, $prefixlength) = @_;
|
|
|
|
|
|
|
|
if (($prefixlength < 1) || ($prefixlength > 128))
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
# can not do this without Net::IP module
|
|
|
|
if (!$netipmodule)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
my $ip = new Net::IP ("fe80::/$prefixlength") or die (Net::IP::Error());
|
|
|
|
|
|
|
|
my $mask = $ip->mask();
|
|
|
|
|
|
|
|
return $mask;
|
|
|
|
|
|
|
|
}
|
2010-05-07 01:58:02 +00:00
|
|
|
1;
|