pve-installer/Proxmox/Sys/Net.pm
Thomas Lamprecht 625e8f60ee factor out network parser and sys-info helpers
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2023-06-09 09:36:58 +02:00

191 lines
4.8 KiB
Perl

package Proxmox::Sys::Net;
use strict;
use warnings;
use base qw(Exporter);
our @EXPORT_OK = qw(parse_ip_address parse_ip_mask);
my $IPV4OCTET = "(?:25[0-5]|(?:2[0-4]|1[0-9]|[1-9])?[0-9])";
my $IPV4RE = "(?:(?:$IPV4OCTET\\.){3}$IPV4OCTET)";
my $IPV6H16 = "(?:[0-9a-fA-F]{1,4})";
my $IPV6LS32 = "(?:(?:$IPV4RE|$IPV6H16:$IPV6H16))";
my $IPV6RE = "(?:" .
"(?:(?:" . "(?:$IPV6H16:){6})$IPV6LS32)|" .
"(?:(?:" . "::(?:$IPV6H16:){5})$IPV6LS32)|" .
"(?:(?:(?:" . "$IPV6H16)?::(?:$IPV6H16:){4})$IPV6LS32)|" .
"(?:(?:(?:(?:$IPV6H16:){0,1}$IPV6H16)?::(?:$IPV6H16:){3})$IPV6LS32)|" .
"(?:(?:(?:(?:$IPV6H16:){0,2}$IPV6H16)?::(?:$IPV6H16:){2})$IPV6LS32)|" .
"(?:(?:(?:(?:$IPV6H16:){0,3}$IPV6H16)?::(?:$IPV6H16:){1})$IPV6LS32)|" .
"(?:(?:(?:(?:$IPV6H16:){0,4}$IPV6H16)?::" . ")$IPV6LS32)|" .
"(?:(?:(?:(?:$IPV6H16:){0,5}$IPV6H16)?::" . ")$IPV6H16)|" .
"(?:(?:(?:(?:$IPV6H16:){0,6}$IPV6H16)?::" . ")))";
my $IPRE = "(?:$IPV4RE|$IPV6RE)";
my $ipv4_mask_hash = {
'128.0.0.0' => 1,
'192.0.0.0' => 2,
'224.0.0.0' => 3,
'240.0.0.0' => 4,
'248.0.0.0' => 5,
'252.0.0.0' => 6,
'254.0.0.0' => 7,
'255.0.0.0' => 8,
'255.128.0.0' => 9,
'255.192.0.0' => 10,
'255.224.0.0' => 11,
'255.240.0.0' => 12,
'255.248.0.0' => 13,
'255.252.0.0' => 14,
'255.254.0.0' => 15,
'255.255.0.0' => 16,
'255.255.128.0' => 17,
'255.255.192.0' => 18,
'255.255.224.0' => 19,
'255.255.240.0' => 20,
'255.255.248.0' => 21,
'255.255.252.0' => 22,
'255.255.254.0' => 23,
'255.255.255.0' => 24,
'255.255.255.128' => 25,
'255.255.255.192' => 26,
'255.255.255.224' => 27,
'255.255.255.240' => 28,
'255.255.255.248' => 29,
'255.255.255.252' => 30,
'255.255.255.254' => 31,
'255.255.255.255' => 32
};
my $ipv4_reverse_mask = [
'0.0.0.0',
'128.0.0.0',
'192.0.0.0',
'224.0.0.0',
'240.0.0.0',
'248.0.0.0',
'252.0.0.0',
'254.0.0.0',
'255.0.0.0',
'255.128.0.0',
'255.192.0.0',
'255.224.0.0',
'255.240.0.0',
'255.248.0.0',
'255.252.0.0',
'255.254.0.0',
'255.255.0.0',
'255.255.128.0',
'255.255.192.0',
'255.255.224.0',
'255.255.240.0',
'255.255.248.0',
'255.255.252.0',
'255.255.254.0',
'255.255.255.0',
'255.255.255.128',
'255.255.255.192',
'255.255.255.224',
'255.255.255.240',
'255.255.255.248',
'255.255.255.252',
'255.255.255.254',
'255.255.255.255',
];
# returns (addr, version) tuple
sub parse_ip_address {
my ($text) = @_;
if ($text =~ m!^\s*($IPV4RE)\s*$!) {
return ($1, 4);
} elsif ($text =~ m!^\s*($IPV6RE)\s*$!) {
return ($1, 6);
}
return (undef, undef);
}
sub parse_ip_mask {
my ($text, $ip_version) = @_;
$text =~ s/^\s+//;
$text =~ s/\s+$//;
if ($ip_version == 6 && ($text =~ m/^(\d+)$/) && $1 >= 8 && $1 <= 126) {
return $text;
} elsif ($ip_version == 4 && ($text =~ m/^(\d+)$/) && $1 >= 8 && $1 <= 32) {
return $text;
} elsif ($ip_version == 4 && defined($ipv4_mask_hash->{$text})) {
# costs nothing to handle 255.x.y.z style masks, so continue to allow it
return $ipv4_mask_hash->{$text};
}
return;
}
sub get_ip_config {
my $ifaces = {};
my $default;
my $links = `ip -o l`;
foreach my $l (split /\n/,$links) {
my ($index, $name, $flags, $state, $mac) = $l =~ m/^(\d+):\s+(\S+):\s+<(\S+)>.*\s+state\s+(\S+)\s+.*\s+link\/ether\s+(\S+)\s+/;
next if !$name || $name eq 'lo';
my $driver = readlink "/sys/class/net/$name/device/driver" || 'unknown';
$driver =~ s!^.*/!!;
$ifaces->{"$index"} = {
name => $name,
driver => $driver,
flags => $flags,
state => $state,
mac => $mac,
};
my $addresses = `ip -o a s $name`;
foreach my $a (split /\n/,$addresses) {
my ($family, $ip, $prefix) = $a =~ m/^\Q$index\E:\s+\Q$name\E\s+(inet|inet6)\s+($IPRE)\/(\d+)\s+/;
next if !$ip;
next if $a =~ /scope\s+link/; # ignore link local
my $mask = $prefix;
if ($family eq 'inet') {
next if !$ip =~ /$IPV4RE/;
next if $prefix < 8 || $prefix > 32;
$mask = @$ipv4_reverse_mask[$prefix];
} else {
next if !$ip =~ /$IPV6RE/;
}
$default = $index if !$default;
$ifaces->{"$index"}->{"$family"} = {
prefix => $prefix,
mask => $mask,
addr => $ip,
};
}
}
my $route = `ip route`;
my ($gateway) = $route =~ m/^default\s+via\s+(\S+)\s+/m;
my $resolvconf = `cat /etc/resolv.conf`;
my ($dnsserver) = $resolvconf =~ m/^nameserver\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/m;
my ($domain) = $resolvconf =~ m/^domain\s+(\S+)$/m;
return {
default => $default,
ifaces => $ifaces,
gateway => $gateway,
dnsserver => $dnsserver,
domain => $domain,
}
}
1;