IPv6 address management for active interfaces
authorJamie Cameron <jcameron@webmin.com>
Wed, 19 Jan 2011 05:42:45 +0000 (21:42 -0800)
committerJamie Cameron <jcameron@webmin.com>
Wed, 19 Jan 2011 05:42:45 +0000 (21:42 -0800)
net/edit_aifc.cgi
net/lang/en
net/linux-lib.pl
net/redhat-linux-lib.pl
net/save_aifc.cgi
net/save_bifc.cgi

index b945cfe..b2e4a52 100755 (executable)
@@ -93,6 +93,21 @@ if ($in{'new'} || !&is_ipv6_address($a->{'address'})) {
        print &ui_table_row($text{'ifcs_broad'}, $broadfield);
        }
 
+# Show the IPv6 field
+if (&supports_address6($a)) {
+       $table6 = &ui_columns_start([ $text{'ifcs_address6'},
+                                     $text{'ifcs_netmask6'} ], 50);
+       for($i=0; $i<=@{$a->{'address6'}}; $i++) {
+               $table6 .= &ui_columns_row([
+                   &ui_textbox("address6_$i",
+                               $a->{'address6'}->[$i], 40),
+                   &ui_textbox("netmask6_$i",
+                               $a->{'netmask6'}->[$i] || 64, 10) ]);
+               }
+       $table6 .= &ui_columns_end();
+       print &ui_table_row($text{'ifcs_mode6a'}, $table6, 3);
+       }
+
 # Show MTU
 if (!$access{'mtu'}) {
        # Cannot be edited
index 491efba..04f75bc 100644 (file)
@@ -44,6 +44,7 @@ ifcs_mode=IPv4 address
 ifcs_mode6=Static IPv6 addresses
 ifcs_address6=IPv6 address
 ifcs_netmask6=Netmask
+ifcs_mode6a=IPv6 addresses
 
 aifc_create=Create Active Interface
 aifc_edit=Edit Active Interface
index 666244f..d7dd75f 100755 (executable)
@@ -28,7 +28,7 @@ foreach $l (@lines) {
        $ifc{'up'}++ if ($l =~ /\sUP\s/);
        $ifc{'promisc'}++ if ($l =~ /\sPROMISC\s/);
        local (@address6, @netmask6, @scope6);
-       while($l =~ s/inet6 addr:\s*(\S+)\/(\d+)\s+Scope:(\S+)//) {
+       while($l =~ s/inet6 addr:\s*(\S+)\/(\d+)\s+Scope:(Global)//i) {
                local ($address6, $netmask6, $scope6) = ($1, $2, $3);
                push(@address6, $address6);
                push(@netmask6, $netmask6);
@@ -69,14 +69,9 @@ else {
                }
        else {
                $cmd .= "ifconfig $a->{'name'}";
-               if ($a->{'virtual'} ne "") { $cmd .= ":$a->{'virtual'}"; }
-               if (&is_ipv6_address($a->{'address'})) { 
-                       $cmd .= " inet6 add ";
-                       if ($a->{'netmask'}) {
-                                 $a->{'address'} .= "/$a->{'netmask'}";
-                                 $a->{'netmask'} = ''; 
-                               }
-                       } 
+               if ($a->{'virtual'} ne "") {
+                       $cmd .= ":$a->{'virtual'}";
+                       }
                }
        $cmd .= " $a->{'address'}";
        if ($a->{'netmask'}) { $cmd .= " netmask $a->{'netmask'}"; }
@@ -87,36 +82,61 @@ else {
        }
 local $out = &backquote_logged("$cmd 2>&1");
 if ($?) { &error($out); }
+
+# Apply ethernet address
 if ($a->{'ether'} && !&use_ifup_command($a)) {
-       # Apply ethernet address
        $out = &backquote_logged(
                "ifconfig $a->{'name'} hw ether $a->{'ether'} 2>&1");
        if ($?) { &error($out); }
        }
+
+if ($a->{'virtual'} eq '') {
+       # Remove old IPv6 addresses
+       local $l = &backquote_command("ifconfig $a->{'name'}");
+       while($l =~ s/inet6 addr:\s*(\S+)\/(\d+)\s+Scope:(\S+)//) {
+               local $cmd = "ifconfig $a->{'name'} inet6 del $1/$2 2>&1";
+               $out = &backquote_logged($cmd);
+               &error("Failed to remove old IPv6 address : $out") if ($?);
+               }
+
+       # Add IPv6 addresses
+       for(my $i=0; $i<@{$a->{'address6'}}; $i++) {
+               local $cmd = "ifconfig $a->{'name'} inet6 add ".
+                    $a->{'address6'}->[$i]."/".$a->{'netmask6'}->[$i]." 2>&1";
+               $out = &backquote_logged($cmd);
+               &error("Failed to add IPv6 address : $out") if ($?);
+               }
+       }
 }
 
 # deactivate_interface(&details)
 # Shutdown some active interface
 sub deactivate_interface
 {
-local $name = $_[0]->{'name'}.
-             ($_[0]->{'virtual'} ne "" ? ":$_[0]->{'virtual'}" : "");
-local $address = $_[0]->{'address'}.
-        ($_[0]->{'virtual'} ne "" ? ":$_[0]->{'virtual'}" : "");
-local $netmask = $_[0]->{'netmask'};
+local $a = $_[0];
+local $name = $a->{'name'}.
+             ($a->{'virtual'} ne "" ? ":$a->{'virtual'}" : "");
+local $address = $a->{'address'}.
+        ($a->{'virtual'} ne "" ? ":$a->{'virtual'}" : "");
+local $netmask = $a->{'netmask'};
  
-if ($_[0]->{'virtual'} ne "") {
+if ($a->{'virtual'} ne "") {
        # Shutdown virtual interface by setting address to 0
        local $out = &backquote_logged("ifconfig $name 0 2>&1");
        }
-elsif (&is_ipv6_address($address)){
-       local $out = &backquote_logged("ifconfig $name inet6 del $address/$netmask 2>&1");
+# Delete all v6 addresses
+for(my $i=0; $i<@{$a->{'address6'}}; $i++) {
+       local $cmd = "ifconfig $a->{'name'} inet6 del ".
+                    $a->{'address6'}->[$i]."/".$a->{'netmask6'}->[$i];
+       &backquote_logged("$cmd 2>&1");
        }
+
+# Check if still up somehow
 local ($still) = grep { $_->{'fullname'} eq $name } &active_interfaces();
-if ($still && !&is_ipv6_address($address)) {
+if ($still) {
        # Old version of ifconfig or non-virtual interface.. down it
        local $out;
-       if (&use_ifup_command($_[0])) {
+       if (&use_ifup_command($a)) {
                $out = &backquote_logged("ifdown $name 2>&1");
                }
        else {
@@ -168,6 +188,7 @@ return "VmWare" if ($_[0] =~ /^vmnet/);
 return "Wireless" if ($_[0] =~ /^wlan/);
 return "Bonded" if ($_[0] =~ /^bond/);
 return "OpenVZ" if ($_[0] =~ /^venet/);
+return "Bridge" if ($_[0] =~ /^br/);
 return $text{'ifcs_unknown'};
 }
 
@@ -253,22 +274,23 @@ sub list_interfaces
 sub delete_route
 {
 local ($route) = @_;
-       local $cmd = "route " . (&is_ipv6_address($route->{'dest'})? "-A inet6 ":"-A inet ") . "del ";
-       
-       if (!$route->{'dest'} || $route->{'dest'} eq '0.0.0.0' || $route->{'dest'} eq '::') {
-       $cmd .= " default";
+local $cmd = "route ".
+       (&check_ip6address($route->{'dest'}) ? "-A inet6 ":"-A inet ")."del ";
+if (!$route->{'dest'} || $route->{'dest'} eq '0.0.0.0' ||
+    $route->{'dest'} eq '::') {
+               $cmd .= " default";
        }
 elsif ($route->{'netmask'} eq '255.255.255.255') {
        $cmd .= " -host $route->{'dest'}";
        }
-       elsif (!&is_ipv6_address($route->{'dest'})) {
+elsif (!&check_ip6address($route->{'dest'})) {
        $cmd .= " -net $route->{'dest'}";
        if ($route->{'netmask'} && $route->{'netmask'} ne '0.0.0.0') {
                $cmd .= " netmask $route->{'netmask'}";
                }
        }
-       else{
-               $cmd .= "$route->{'dest'}/$route->{'netmask'}";
+else {
+       $cmd .= "$route->{'dest'}/$route->{'netmask'}";
        }
 if ($route->{'gateway'}) {
        $cmd .= " gw $route->{'gateway'}";
@@ -285,27 +307,28 @@ return $? ? $out : undef;
 sub create_route
 {
 local ($route) = @_;
-       local $cmd = "route " . (&is_ipv6_address($route->{'dest'})? "-A inet6 ":"-A inet ") . "add ";
-       
-       if (!$route->{'dest'} || $route->{'dest'} eq '0.0.0.0' || $route->{'dest'} eq '::') {
+local $cmd = "route ".
+       (&check_ip6address($route->{'dest'}) ? "-A inet6 ":"-A inet ")."add ";
+if (!$route->{'dest'} || $route->{'dest'} eq '0.0.0.0' ||
+    $route->{'dest'} eq '::') {
        $cmd .= " default";
        }
-       elsif ($route->{'netmask'} eq '255.255.255.255') {
-               $cmd .= " -host $route->{'dest'}";
-               }
-       elsif (!&is_ipv6_address($route->{'dest'})) {
-               $cmd .= " -net $route->{'dest'}";
-               if ($route->{'netmask'} && $route->{'netmask'} ne '0.0.0.0') {
-                       $cmd .= " netmask $route->{'netmask'}";
-               }
+elsif ($route->{'netmask'} eq '255.255.255.255') {
+       $cmd .= " -host $route->{'dest'}";
+       }
+elsif (!&check_ip6address($route->{'dest'})) {
+       $cmd .= " -net $route->{'dest'}";
+       if ($route->{'netmask'} && $route->{'netmask'} ne '0.0.0.0') {
+               $cmd .= " netmask $route->{'netmask'}";
                }
-       else{
-               $cmd .= "$route->{'dest'}/$route->{'netmask'}";
+       }
+else {
+       $cmd .= "$route->{'dest'}/$route->{'netmask'}";
        }
 if ($route->{'gateway'}) {
        $cmd .= " gw $route->{'gateway'}";
        }
-       elsif ($route->{'iface'}) {
+elsif ($route->{'iface'}) {
        $cmd .= " dev $route->{'iface'}";
        }
 local $out = &backquote_logged("$cmd 2>&1 </dev/null");
index 237202c..b13a6b2 100755 (executable)
@@ -168,7 +168,7 @@ else {
        delete($conf{'IPV6ADDR'});
        delete($conf{'IPV6ADDR_SECONDARIES'});
        local @ip6s;
-       for(my $i=0; $i<@{$b->{'address6'}}; $b++) {
+       for(my $i=0; $i<@{$b->{'address6'}}; $i++) {
                push(@ip6s, $b->{'address6'}->[$i]."/".
                            $b->{'netmask6'}->[$i]);
                }
index 82118ae..84f25aa 100755 (executable)
@@ -18,9 +18,11 @@ else {
        # Validate and save inputs
        &error_setup($text{'aifc_err2'});
        if (!$in{'new'}) {
+               # Editing existing interface
                $olda = $acts[$in{'idx'}];
                &can_iface($olda) || &error($text{'ifcs_ecannot_this'});
                $a->{'name'} = $olda->{'name'};
+               $a->{'fullname'} = $olda->{'fullname'};
                $a->{'virtual'} = $olda->{'virtual'}
                        if (defined($olda->{'virtual'}));
                }
@@ -39,6 +41,7 @@ else {
                        }
                $a->{'name'} = $in{'name'};
                $a->{'virtual'} = $in{'virtual'};
+               $a->{'fullname'} = $a->{'name'}.":".$a->{'virtual'};
                &can_create_iface() || &error($text{'ifcs_ecannot'});
                &can_iface($a) || &error($text{'ifcs_ecannot'});
                }
@@ -54,17 +57,19 @@ else {
                        &error(&text('aifc_evirtmin', $min_virtual_number));
                $a->{'name'} = $1;
                $a->{'virtual'} = $3;
+               $a->{'fullname'} = $a->{'name'}.":".$a->{'virtual'};
                &can_create_iface() || &error($text{'ifcs_ecannot'});
                &can_iface($a) || &error($text{'ifcs_ecannot'});
                }
        elsif ($in{'name'} =~ /^[a-z]+\d*(\.\d+)?$/) {
                # creating a real interface
                foreach $ea (@acts) {
-                       if ($ea->{'name'} eq $in{'name'} && !&is_ipv6_address($ea->{'address'}) && !&is_ipv6_address($in{'address'}) ) {
+                       if ($ea->{'name'} eq $in{'name'}) {
                                &error(&text('aifc_edup', $in{'name'}));
                                }
                        }
                $a->{'name'} = $in{'name'};
+               $a->{'fullname'} = $in{'name'};
                &can_create_iface() || &error($text{'ifcs_ecannot'});
                &can_iface($a) || &error($text{'ifcs_ecannot'});
                }
@@ -109,7 +114,7 @@ else {
                        $olda->{'broadcast'};
                }
        elsif (!$in{'broadcast_def'}) {
-               &is_ipv6_address($a->{address})|| &check_ipaddress_any($in{'broadcast'}) ||
+               &check_ipaddress_any($in{'broadcast'}) ||
                        &error(&text('aifc_ebroad', $in{'broadcast'}));
                $a->{'broadcast'} = $in{'broadcast'};
                }
@@ -125,6 +130,7 @@ else {
                $a->{'mtu'} = $in{'mtu'} if ($olda->{'mtu'} ne $in{'mtu'});
                }
 
+       # Save active flag
        if (!$access{'up'}) {
                $a->{'up'} = $in{'new'} ? 1 : $olda->{'up'};
                }
@@ -132,6 +138,36 @@ else {
                $a->{'up'}++;
                }
 
+       # Save IPv6 addresses
+       if (&supports_address6($a) && defined($in{'address6_0'})) {
+               @address6 = ( );
+               @netmask6 = ( );
+               %clash6 = ( );
+               foreach $eb (@acts) {
+                       if ($eb->{'fullname'} ne $a->{'fullname'}) {
+                               foreach $a6 (@{$eb->{'address6'}}) {
+                                       $clash6{$a6} = $eb;
+                                       }
+                               }
+                       }
+               for($i=0; defined($in{'address6_'.$i}); $i++) {
+                       next if ($in{'address6_'.$i} !~ /\S/);
+                       &check_ip6address($in{'address6_'.$i}) ||
+                               &error(&text('aifc_eaddress6', $i+1));
+                       $c = $clash6{$in{'address6_'.$i}};
+                       $c && &error(&text('aifc_eclash6', $i+1, $c->{'name'}));
+                       push(@address6, $in{'address6_'.$i});
+                       $in{'netmask6_'.$i} =~ /^\d+$/ &&
+                           $in{'netmask6_'.$i} > 0 &&
+                           $in{'netmask6_'.$i} <= 128 ||
+                               &error(&text('aifc_enetmask6', $i+1));
+                       push(@netmask6, $in{'netmask6_'.$i});
+                       $clash6{$in{'address6_'.$i}} = $a;
+                       }
+               $a->{'address6'} = \@address6;
+               $a->{'netmask6'} = \@netmask6;
+               }
+
        if (!$in{'ether_def'} && $a->{'virtual'} eq "" &&
            &iface_hardware($a->{'name'})) {
                $in{'ether'} =~ /^[A-Fa-f0-9:]+$/ ||
@@ -143,15 +179,9 @@ else {
                           ($a->{'virtual'} eq '' ? '' : ':'.$a->{'virtual'});
 
        # Bring it up
-       if( !is_ipv6_address($a->{'address'}) || (&is_ipv6_address($a->{'address'}) && $olda->{'address'} ne $a->{'address'}) ){
        &activate_interface($a);
        &webmin_log($in{'new'} ? 'create' : 'modify',
                    "aifc", $a->{'fullname'}, $a);
-       }elsif(&is_ipv6_address($a->{'address'}) && $olda->{'address'} eq $a->{'address'}){
-     &deactivate_interface($olda);
-     &activate_interface($a);
-       
-  }
-}
+       }
 &redirect("list_ifcs.cgi?mode=active");
 
index 5ff61dc..82a5702 100755 (executable)
@@ -44,6 +44,7 @@ else {
                $b->{'virtual'} = $oldb->{'virtual'}
                        if (defined($oldb->{'virtual'}));
                $b->{'code'} = $oldb->{'code'};
+               $b->{'fullname'} = $oldb->{'fullname'};
                }
        elsif (defined($in{'virtual'})) {
                # creating a virtual interface
@@ -60,6 +61,7 @@ else {
                        }
                $b->{'name'} = $in{'name'};
                $b->{'virtual'} = $in{'virtual'};
+               $b->{'fullname'} = $b->{'name'}.":".$b->{'virtual'};
                &can_create_iface() || &error($text{'ifcs_ecannot'});
                &can_iface($b) || &error($text{'ifcs_ecannot'});
                }
@@ -75,6 +77,7 @@ else {
                        &error(&text('aifc_evirtmin', $min_virtual_number));
                $b->{'name'} = $1;
                $b->{'virtual'} = $3;
+               $b->{'fullname'} = $b->{'name'}.":".$b->{'virtual'};
                &can_create_iface() || &error($text{'ifcs_ecannot'});
                &can_iface($b) || &error($text{'ifcs_ecannot'});
                }
@@ -86,6 +89,7 @@ else {
                                }
                        }
                $b->{'name'} = $in{'name'};
+               $b->{'fullname'} = $in{'name'};
                &can_create_iface() || &error($text{'ifcs_ecannot'});
                &can_iface($b) || &error($text{'ifcs_ecannot'});
                }
@@ -97,6 +101,7 @@ else {
                                }
                        }
                $b->{'name'} = $in{'name'};
+               $b->{'fullname'} = $in{'name'};
                &can_create_iface() || &error($text{'ifcs_ecannot'});
                &can_iface($b) || &error($text{'ifcs_ecannot'});
                }
@@ -197,10 +202,10 @@ else {
                @address6 = ( );
                @netmask6 = ( );
                %clash6 = ( );
-               foreach $e (@boot) {
-                       if ($e->{'fullname'} ne $b->{'fullname'}) {
-                               foreach $a6 (@{$e->{'address6'}}) {
-                                       $clash6{$a6} = $e;
+               foreach $eb (@boot) {
+                       if ($eb->{'fullname'} ne $b->{'fullname'}) {
+                               foreach $a6 (@{$eb->{'address6'}}) {
+                                       $clash6{$a6} = $eb;
                                        }
                                }
                        }