mirror of
https://github.com/webmin/webmin.git
synced 2026-06-19 10:50:21 +01:00
266 lines
5.4 KiB
Perl
266 lines
5.4 KiB
Perl
# Networking functions for Ubuntu 17+, which uses Netplan by default
|
|
|
|
$netplan_dir = "/etc/netplan";
|
|
|
|
do 'linux-lib.pl';
|
|
|
|
sub boot_interfaces
|
|
{
|
|
my @rv;
|
|
foreach my $f (glob("$netplan_dir/*.yaml")) {
|
|
my $yaml = &read_yaml_file($f);
|
|
next if (!$yaml || !@$yaml);
|
|
my ($network) = grep { $_->{'name'} eq 'network' } @$yaml;
|
|
next if (!$network);
|
|
my ($ens) = grep { $_->{'name'} eq 'ethernets' }
|
|
@{$network->{'members'}};
|
|
next if (!$ens);
|
|
foreach my $e (@{$ens->{'members'}}) {
|
|
my $cfg = { 'name' => $e->{'name'},
|
|
'fullname' => $e->{'name'},
|
|
'file' => $f,
|
|
'up' => 1 };
|
|
my ($dhcp) = grep { $_->{'name'} eq 'dhcp4' }
|
|
@{$e->{'members'}};
|
|
if (&is_true_value($dhcp)) {
|
|
$cfg->{'dhcp'} = 1;
|
|
}
|
|
|
|
# IPv4 and v6 addresses
|
|
my ($addresses) = grep { $_->{'name'} eq 'addresses' }
|
|
@{$e->{'members'}};
|
|
my @addrs;
|
|
my @addrs6;
|
|
if ($addresses) {
|
|
@addrs = grep { !&check_ip6address($_) }
|
|
@{$addresses->{'value'}};
|
|
@addrs6 = grep { &check_ip6address($_) }
|
|
@{$addresses->{'value'}};
|
|
my $a = shift(@addrs);
|
|
($cfg->{'address'}, $cfg->{'netmask'}) =
|
|
&split_addr_netmask($a);
|
|
}
|
|
foreach my $a6 (@addrs6) {
|
|
if ($a6 =~ /^(\S+)\/(\d+)$/) {
|
|
push(@{$cfg->{'address6'}}, $1);
|
|
push(@{$cfg->{'netmask6'}}, $2);
|
|
}
|
|
else {
|
|
push(@{$cfg->{'address6'}}, $a6);
|
|
push(@{$cfg->{'netmask6'}}, 64);
|
|
}
|
|
}
|
|
|
|
# IPv4 and v4 gateways
|
|
my ($gateway4) = grep { $_->{'name'} eq 'gateway4' }
|
|
@{$e->{'members'}};
|
|
if ($gateway4) {
|
|
$cfg->{'gateway'} = $gateway4->{'value'};
|
|
}
|
|
my ($gateway6) = grep { $_->{'name'} eq 'gateway6' }
|
|
@{$e->{'members'}};
|
|
if ($gateway6) {
|
|
$cfg->{'gateway6'} = $gateway6->{'value'};
|
|
}
|
|
push(@rv, $cfg);
|
|
|
|
# Nameservers (which are used to generate resolv.conf)
|
|
my ($nameservers) = grep { $_->{'name'} eq 'nameservers' }
|
|
@{$e->{'members'}};
|
|
if ($nameservers) {
|
|
my ($nsa) = grep { $_->{'name'} eq 'addresses' }
|
|
@{$nameservers->{'members'}};
|
|
my ($search) = grep { $_->{'name'} eq 'search' }
|
|
@{$nameservers->{'members'}};
|
|
if ($nsa) {
|
|
$cfg->{'nameserver'} = $nsa->{'value'};
|
|
}
|
|
if ($search) {
|
|
$cfg->{'search'} = $search->{'value'};
|
|
}
|
|
}
|
|
|
|
# Add IPv4 alias interfaces
|
|
foreach my $aa (@addrs) {
|
|
# XXX
|
|
}
|
|
}
|
|
}
|
|
return @rv;
|
|
}
|
|
|
|
sub supports_bonding
|
|
{
|
|
return 0; # XXX fix later
|
|
}
|
|
|
|
sub supports_vlans
|
|
{
|
|
return 0; # XXX fix later
|
|
}
|
|
|
|
sub boot_iface_hardware
|
|
{
|
|
return $_[0] =~ /^(eth|em)/;
|
|
}
|
|
|
|
# supports_address6([&iface])
|
|
# Returns 1 if managing IPv6 interfaces is supported
|
|
sub supports_address6
|
|
{
|
|
local ($iface) = @_;
|
|
return !$iface || $iface->{'virtual'} eq '';
|
|
}
|
|
|
|
# Returns 1, as boot-time interfaces on Debian can exist without an IP (such as
|
|
# for bridging)
|
|
sub supports_no_address
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
# Bridge interfaces can be created on debian
|
|
sub supports_bridges
|
|
{
|
|
return 0; # XXX fix later
|
|
}
|
|
|
|
# can_edit(what)
|
|
# Can some boot-time interface parameter be edited?
|
|
sub can_edit
|
|
{
|
|
return $_[0];
|
|
}
|
|
|
|
# valid_boot_address(address)
|
|
# Is some address valid for a bootup interface
|
|
sub valid_boot_address
|
|
{
|
|
return &check_ipaddress_any($_[0]);
|
|
}
|
|
|
|
# get_hostname()
|
|
sub get_hostname
|
|
{
|
|
local $hn = &read_file_contents("/etc/hostname");
|
|
$hn =~ s/\r|\n//g;
|
|
if ($hn) {
|
|
return $hn;
|
|
}
|
|
return &get_system_hostname(1);
|
|
}
|
|
|
|
# save_hostname(name)
|
|
sub save_hostname
|
|
{
|
|
local (%conf, $f);
|
|
&system_logged("hostname $_[0] >/dev/null 2>&1");
|
|
foreach $f ("/etc/hostname", "/etc/HOSTNAME", "/etc/mailname") {
|
|
if (-r $f) {
|
|
&open_lock_tempfile(HOST, ">$f");
|
|
&print_tempfile(HOST, $_[0],"\n");
|
|
&close_tempfile(HOST);
|
|
}
|
|
}
|
|
undef(@main::get_system_hostname); # clear cache
|
|
}
|
|
|
|
# get_domainname()
|
|
sub get_domainname
|
|
{
|
|
local $d;
|
|
&execute_command("domainname", undef, \$d, undef);
|
|
chop($d);
|
|
return $d;
|
|
}
|
|
|
|
# save_domainname(domain)
|
|
sub save_domainname
|
|
{
|
|
local %conf;
|
|
&execute_command("domainname ".quotemeta($_[0]));
|
|
}
|
|
|
|
sub routing_config_files
|
|
{
|
|
return ( $netplan_dir, $sysctl_config );
|
|
}
|
|
|
|
sub network_config_files
|
|
{
|
|
return ( "/etc/hostname", "/etc/HOSTNAME", "/etc/mailname" );
|
|
}
|
|
|
|
# read_yaml_file(file)
|
|
# Converts a YAML file into a nested hash ref
|
|
sub read_yaml_file
|
|
{
|
|
my ($file) = @_;
|
|
my $lref = &read_file_lines($file, 1);
|
|
my $lnum = 0;
|
|
my $rv = [ ];
|
|
my $parent = { 'members' => $rv,
|
|
'indent' => -1 };
|
|
foreach my $origl (@$lref) {
|
|
my $l = $origl;
|
|
$l =~ s/#.*$//;
|
|
if ($l =~ /^(\s*)(\S+):\s*(\S.*)/) {
|
|
# Value line
|
|
my $i = length($1);
|
|
my $dir = { 'indent' => length($1),
|
|
'name' => $2,
|
|
'value' => $3,
|
|
};
|
|
if ($dir->{'value'} =~ /^\[(.*)\]$/) {
|
|
$dir->{'value'} = [ split(/,/, $1) ];
|
|
}
|
|
push(@{$parent->{'members'}}, $dir);
|
|
}
|
|
elsif ($l =~ /^(\s*)(\S+):\s*$/) {
|
|
# Section header line
|
|
my $i = length($1);
|
|
my $dir = { 'indent' => length($1),
|
|
'name' => $2,
|
|
'members' => [ ],
|
|
};
|
|
if ($i > $parent->{'indent'}) {
|
|
# Start of a sub-section inside the current directive
|
|
push(@{$parent->{'members'}}, $dir);
|
|
$dir->{'parent'} = $parent;
|
|
$parent = $dir;
|
|
}
|
|
else {
|
|
# Pop up a level (or more)
|
|
while($i <= $parent->{'indent'}) {
|
|
$parent = $parent->{'parent'};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return $rv;
|
|
}
|
|
|
|
# split_addr_netmask(addr-string)
|
|
# Splits a string like 1.2.3.4/24 into an address and netmask
|
|
sub split_addr_netmask
|
|
{
|
|
my ($a) = @_;
|
|
if ($a =~ /^([0-9\.]+)\/(\d+)$/) {
|
|
return ($1, &prefix_to_mask($2));
|
|
}
|
|
elsif ($a =~ /^([0-9\.]+)\/([0-9\.]+)$/) {
|
|
return ($1, $2);
|
|
}
|
|
else {
|
|
return $a;
|
|
}
|
|
}
|
|
|
|
sub is_true_value
|
|
{
|
|
my ($dir) = @_;
|
|
return $dir && $dir->{'value'} =~ /true|yes|1/i;
|
|
}
|
|
|
|
1;
|