IPv6 allowed address matching fixes
authorJamie Cameron <jcameron@webmin.com>
Sun, 7 Nov 2010 20:46:13 +0000 (12:46 -0800)
committerJamie Cameron <jcameron@webmin.com>
Sun, 7 Nov 2010 20:46:13 +0000 (12:46 -0800)
miniserv.pl
webmin/change_access.cgi
webmin/edit_access.cgi
webmin/lang/en
webmin/webmin-lib.pl

index f955fea..5929df5 100755 (executable)
@@ -2575,8 +2575,7 @@ for($i=2; $i<@_; $i++) {
                $_[$i] = $1."/".&prefix_to_mask($2);
                }
        if ($_[$i] =~ /^(\S+)\/(\S+)$/) {
-               # Compare with network/mask
-               # XXX IPv6 support
+               # Compare with IPv4 network/mask
                @mo = split(/\./, $1); @ms = split(/\./, $2);
                for($j=0; $j<4; $j++) {
                        if ((int($io[$j]) & int($ms[$j])) != int($mo[$j])) {
@@ -2588,9 +2587,8 @@ for($i=2; $i<@_; $i++) {
                # Compare with hostname regexp
                $mismatch = 1 if ($hn !~ /$1$/);
                }
-       elsif ($_[$i] eq 'LOCAL') {
-               # Compare with local network
-               # XXX IPv6 support
+       elsif ($_[$i] eq 'LOCAL' && &check_ipaddress($_[1])) {
+               # Compare with local IPv4 network
                local @lo = split(/\./, $_[1]);
                if ($lo[0] < 128) {
                        $mismatch = 1 if ($lo[0] != $io[0]);
@@ -2605,6 +2603,13 @@ for($i=2; $i<@_; $i++) {
                                          $lo[2] != $io[2]);
                        }
                }
+       elsif ($_[$i] eq 'LOCAL' && &check_ip6address($_[1])) {
+               # Compare with local IPv6 network, which is always first 4 words
+               local @lo = split(/:/, $_[1]);
+               for(my $i=0; $i<4; $i++) {
+                       $mismatch = 1 if ($lo[$i] ne $io[$i]);
+                       }
+               }
        elsif ($_[$i] =~ /^[0-9\.]+$/) {
                # Compare with IPv4 address or network
                @mo = split(/\./, $_[$i]);
@@ -2620,7 +2625,7 @@ for($i=2; $i<@_; $i++) {
                @mo = split(/:/, $_[$i]);
                while(@mo && !$mo[$#mo]) { pop(@mo); }
                for($j=0; $j<@mo; $j++) {
-                       if ($mo[$j] != $io[$j]) {
+                       if ($mo[$j] ne $io[$j]) {
                                $mismatch = 1;
                                }
                        }
index f005bdd..aefd21d 100755 (executable)
@@ -9,6 +9,7 @@ require './webmin-lib.pl';
 $raddr = $ENV{'REMOTE_ADDR'};
 if ($in{"access"}) {
        @hosts = split(/\s+/, $in{"ip"});
+       push(@hosts, "LOCAL") if ($in{'local'});
        if (!@hosts) { &error($text{'access_enone'}); }
        foreach $h (@hosts) {
                $err = &valid_allow($h);
index e9083cc..4b692bc 100755 (executable)
@@ -12,15 +12,17 @@ print &ui_form_start("change_access.cgi", "post");
 print &ui_table_start($text{'access_header'}, undef, 2, [ "width=30%" ]);
 
 $access = $miniserv{"allow"} ? 1 : $miniserv{"deny"} ? 2 : 0;
+@list = $access == 1 ? split(/\s+/, $miniserv{"allow"}) :
+       $access == 2 ? split(/\s+/, $miniserv{"deny"}) : ( );
+$idx = &indexof("LOCAL", @list);
+splice(@list, $idx, 1) if ($idx >= 0);
 print &ui_table_row($text{'access_ip'},
        &ui_radio("access", $access,
                  [ [ 0, $text{'access_all'} ],
                    [ 1, $text{'access_allow'} ],
                    [ 2, $text{'access_deny'} ] ])."<br>\n".
-       &ui_textarea("ip",
-               $access == 1 ? join("\n", split(/\s+/, $miniserv{"allow"})) :
-               $access == 2 ? join("\n", split(/\s+/, $miniserv{"deny"})) : "",
-               6, 30));
+       &ui_textarea("ip", join("\n", @list), 6, 30)."<br>\n".
+       &ui_checkbox("local", 1, $text{'access_local'}, $idx >= 0));
 
 print &ui_table_row($text{'access_always'},
        &ui_yesno_radio("alwaysresolve", int($miniserv{'alwaysresolve'})));
index 54bb73b..71647e0 100644 (file)
@@ -15,6 +15,7 @@ index_refreshmsg=Re-check all Webmin modules for installed servers, and update t
 access_title=IP Access Control
 access_desc=The Webmin server can be configured to deny or allow access only from certain IP addresses using this form. Hostnames (like foo.bar.com) and IP networks (like 10.254.3.0 or 10.254.1.0/255.255.255.128) can also be entered. You should limit access to your server to trusted addresses, especially if it is accessible from the Internet. Otherwise, anyone who guesses your password will have complete control of your system.
 access_ip=Allowed IP addresses
+access_local=Include local network in list
 access_header=Access control options
 access_all=Allow from all addresses
 access_allow=Only allow from listed addresses
@@ -28,6 +29,7 @@ access_enet='$1' is not a valid network address
 access_emask='$1' is not a valid netmask
 access_ecidr='$1' is not a valid CIDR number
 access_eip='$1' is not a complete IP or network address
+access_eip6='$1' is not a complete IPv6 or network address
 access_ehost=Failed to find IP address for '$1'
 access_eself=Your current IP address ($1) would be denied
 access_always=Resolve hostnames on every request?
index 0db25cd..3dd18fd 100755 (executable)
@@ -1407,8 +1407,7 @@ for($i=1; $i<@_; $i++) {
                 $ip = $1."/".&prefix_to_mask($2);
                 }
        if ($ip =~ /^(\S+)\/(\S+)$/) {
-               # Compare with network/mask
-               # XXX IPv6 support
+               # Compare with IPv4 network/mask
                @mo = split(/\./, $1); @ms = split(/\./, $2);
                for($j=0; $j<4; $j++) {
                        if ((int($io[$j]) & int($ms[$j])) != int($mo[$j])) {
@@ -1438,7 +1437,7 @@ for($i=1; $i<@_; $i++) {
                @mo = split(/:/, $_[$i]);
                while(@mo && !$mo[$#mo]) { pop(@mo); }
                for($j=0; $j<@mo; $j++) {
-                       if ($mo[$j] != $io[$j]) {
+                       if ($mo[$j] ne $io[$j]) {
                                $mismatch = 1;
                                }
                        }
@@ -1474,7 +1473,6 @@ allowed IPs, or an error message if not
 sub valid_allow
 {
 local ($h) = @_;
-local $i;
 if ($h =~ /^([0-9\.]+)\/(\d+)$/) {
        &check_ipaddress($1) ||
                return &text('access_enet', "$1");
@@ -1491,15 +1489,18 @@ elsif ($h =~ /^[0-9\.]+$/) {
        &check_ipaddress($h) ||
                return &text('access_eip', $h);
        }
+elsif ($h =~ /^[a-f0-9:]+$/) {
+       &check_ip6address($h) ||
+               return &text('access_eip6', $h);
+       }
 elsif ($h =~ /^\*\.(\S+)$/) {
        # *.domain is OK
        }
 elsif ($h eq 'LOCAL') {
        # Local means any on local nets
        }
-elsif ($i = join('.', unpack("CCCC", inet_aton($h)))) {
-       # Resolve a hostname
-       $h = $i;
+elsif (&to_ipaddress($h) || &to_ip6address($h)) {
+       # Resolvable hostname
        }
 else {
        return &text('access_ehost', $h);