mirror of
https://github.com/webmin/webmin.git
synced 2026-02-12 18:12:05 +00:00
More progress on Webmin IPv6 support
This commit is contained in:
141
miniserv.pl
141
miniserv.pl
@@ -421,14 +421,15 @@ if ($config{'inetd'}) {
|
||||
(undef, $locala) = &get_socket_ip(SOCK, 0);
|
||||
|
||||
print DEBUG "main: Starting handle_request loop pid=$$\n";
|
||||
while(&handle_request($peera, $locala)) { }
|
||||
while(&handle_request($peera, $locala, 0)) { }
|
||||
print DEBUG "main: Done handle_request loop pid=$$\n";
|
||||
close(SOCK);
|
||||
exit;
|
||||
}
|
||||
|
||||
# Build list of sockets to listen on
|
||||
if ($config{"bind"} && $config{"bind"} ne "*") {
|
||||
$config{'bind'} = '' if ($config{'bind'} eq '*');
|
||||
if ($config{'bind'}) {
|
||||
# Listening on a specific IP
|
||||
if (&check_ip6address($config{'bind'})) {
|
||||
# IP is v6
|
||||
@@ -446,31 +447,31 @@ if ($config{"bind"} && $config{"bind"} ne "*") {
|
||||
}
|
||||
else {
|
||||
# Listening on all IPs
|
||||
push(@sockets, [ INADDR_ANY, $config{'port'}, PF_INET ]);
|
||||
if ($use_ipv6) {
|
||||
# Accept IPv6 and v4 connections
|
||||
# Also IPv6
|
||||
push(@sockets, [ in6addr_any(), $config{'port'},
|
||||
Socket6::PF_INET6() ]);
|
||||
}
|
||||
else {
|
||||
# Accept IPv4 only
|
||||
push(@sockets, [ INADDR_ANY, $config{'port'}, PF_INET ]);
|
||||
}
|
||||
}
|
||||
foreach $s (split(/\s+/, $config{'sockets'})) {
|
||||
if ($s =~ /^(\d+)$/) {
|
||||
# Just listen on another port on the main IP
|
||||
push(@sockets, [ $sockets[0]->[0], $s, $sockets[0]->[2] ]);
|
||||
if ($use_ipv6 && !$config{'bind'}) {
|
||||
# Also listen on that port on the main IPv6 address
|
||||
push(@sockets, [ $sockets[1]->[0], $s,
|
||||
$sockets[1]->[2] ]);
|
||||
}
|
||||
}
|
||||
elsif ($s =~ /^\*:(\d+)$/) {
|
||||
# Listening on all IPs on some port
|
||||
push(@sockets, [ INADDR_ANY, $config{'port'},
|
||||
PF_INET ]);
|
||||
if ($use_ipv6) {
|
||||
push(@sockets, [ in6addr_any(), $config{'port'},
|
||||
Socket6::PF_INET6() ]);
|
||||
}
|
||||
else {
|
||||
push(@sockets, [ INADDR_ANY, $config{'port'},
|
||||
PF_INET ]);
|
||||
}
|
||||
}
|
||||
elsif ($s =~ /^(\S+):(\d+)$/) {
|
||||
# Listen on a specific port and IP
|
||||
@@ -510,11 +511,13 @@ for($i=0; $i<@sockets; $i++) {
|
||||
socket($fh, $sockets[$i]->[2], SOCK_STREAM, $proto) ||
|
||||
die "Failed to open socket family $sockets[$i]->[2] : $!";
|
||||
setsockopt($fh, SOL_SOCKET, SO_REUSEADDR, pack("l", 1));
|
||||
$pack = $sockets[$i]->[2] eq PF_INET ?
|
||||
pack_sockaddr_in($sockets[$i]->[1],
|
||||
$sockets[$i]->[0]) :
|
||||
pack_sockaddr_in6($sockets[$i]->[1],
|
||||
$sockets[$i]->[0]);
|
||||
if ($sockets[$i]->[2] eq PF_INET) {
|
||||
$pack = pack_sockaddr_in($sockets[$i]->[1], $sockets[$i]->[0]);
|
||||
}
|
||||
else {
|
||||
$pack = pack_sockaddr_in6($sockets[$i]->[1], $sockets[$i]->[0]);
|
||||
setsockopt($fh, 41, 26, pack("l", 1)); # IPv6 only
|
||||
}
|
||||
for($j=0; $j<5; $j++) {
|
||||
last if (bind($fh, $pack));
|
||||
sleep(1);
|
||||
@@ -863,10 +866,12 @@ while(1) {
|
||||
&close_all_sockets();
|
||||
close(LISTEN);
|
||||
|
||||
# XXX IPv6 - refactor to not resolve IP again
|
||||
print DEBUG
|
||||
"main: Starting handle_request loop pid=$$\n";
|
||||
while(&handle_request($peera, $locala)) { }
|
||||
while(&handle_request($peera, $locala,
|
||||
$ipv6fhs{$s})) {
|
||||
# Loop until keepalive stops
|
||||
}
|
||||
print DEBUG
|
||||
"main: Done handle_request loop pid=$$\n";
|
||||
shutdown(SOCK, 1);
|
||||
@@ -1168,14 +1173,14 @@ while(1) {
|
||||
@passout = grep { defined($_) } @passout;
|
||||
}
|
||||
|
||||
# handle_request(remoteaddress, localaddress)
|
||||
# handle_request(remoteaddress, localaddress, ipv6-flag)
|
||||
# Where the real work is done
|
||||
sub handle_request
|
||||
{
|
||||
local ($acptip, $localip) = @_;
|
||||
print DEBUG "handle_request: from $acptip to $localip\n";
|
||||
local ($acptip, $localip, $ipv6) = @_;
|
||||
print DEBUG "handle_request: from $acptip to $localip ipv6=$ipv6\n";
|
||||
if ($config{'loghost'}) {
|
||||
$acpthost = gethostbyaddr(inet_aton($acptip), AF_INET);
|
||||
$acpthost = &to_hostname($acptip);
|
||||
$acpthost = $acptip if (!$acpthost);
|
||||
}
|
||||
else {
|
||||
@@ -2155,6 +2160,7 @@ if (&get_type($full) eq "internal/cgi" && $validated != 4) {
|
||||
$ENV{"SERVER_PORT"} = $port;
|
||||
$ENV{"REMOTE_HOST"} = $acpthost;
|
||||
$ENV{"REMOTE_ADDR"} = $acptip;
|
||||
$ENV{"REMOTE_ADDR_PROTOCOL"} = $ipv6 ? 6 : 4;
|
||||
$ENV{"REMOTE_USER"} = $authuser;
|
||||
$ENV{"BASE_REMOTE_USER"} = $authuser ne $baseauthuser ?
|
||||
$baseauthuser : undef;
|
||||
@@ -2547,13 +2553,20 @@ sub b64decode
|
||||
sub ip_match
|
||||
{
|
||||
local(@io, @mo, @ms, $i, $j, $hn, $needhn);
|
||||
@io = split(/\./, $_[0]);
|
||||
@io = &check_ip6address($_[0]) ? split(/:/, $_[0])
|
||||
: split(/\./, $_[0]);
|
||||
for($i=2; $i<@_; $i++) {
|
||||
$needhn++ if ($_[$i] =~ /^\*(\S+)$/);
|
||||
}
|
||||
if ($needhn && !defined($hn = $ip_match_cache{$_[0]})) {
|
||||
$hn = gethostbyaddr(inet_aton($_[0]), AF_INET);
|
||||
$hn = "" if (&to_ipaddress($hn) ne $_[0]);
|
||||
# Reverse-lookup hostname if any rules match based on it
|
||||
$hn = &to_hostname($_[0]);
|
||||
if (&check_ip6address($_[0])) {
|
||||
$hn = "" if (&to_ip6address($hn) ne $_[0]);
|
||||
}
|
||||
else {
|
||||
$hn = "" if (&to_ipaddress($hn) ne $_[0]);
|
||||
}
|
||||
$ip_match_cache{$_[0]} = $hn;
|
||||
}
|
||||
for($i=2; $i<@_; $i++) {
|
||||
@@ -2564,6 +2577,7 @@ for($i=2; $i<@_; $i++) {
|
||||
}
|
||||
if ($_[$i] =~ /^(\S+)\/(\S+)$/) {
|
||||
# Compare with network/mask
|
||||
# XXX IPv6 support
|
||||
@mo = split(/\./, $1); @ms = split(/\./, $2);
|
||||
for($j=0; $j<4; $j++) {
|
||||
if ((int($io[$j]) & int($ms[$j])) != int($mo[$j])) {
|
||||
@@ -2577,6 +2591,7 @@ for($i=2; $i<@_; $i++) {
|
||||
}
|
||||
elsif ($_[$i] eq 'LOCAL') {
|
||||
# Compare with local network
|
||||
# XXX IPv6 support
|
||||
local @lo = split(/\./, $_[1]);
|
||||
if ($lo[0] < 128) {
|
||||
$mismatch = 1 if ($lo[0] != $io[0]);
|
||||
@@ -2591,12 +2606,8 @@ for($i=2; $i<@_; $i++) {
|
||||
$lo[2] != $io[2]);
|
||||
}
|
||||
}
|
||||
elsif ($_[$i] !~ /^[0-9\.]+$/) {
|
||||
# Compare with hostname
|
||||
$mismatch = 1 if ($_[0] ne &to_ipaddress($_[$i]));
|
||||
}
|
||||
else {
|
||||
# Compare with IP or network
|
||||
elsif ($_[$i] =~ /^[0-9\.]+$/) {
|
||||
# Compare with IPv4 address or network
|
||||
@mo = split(/\./, $_[$i]);
|
||||
while(@mo && !$mo[$#mo]) { pop(@mo); }
|
||||
for($j=0; $j<@mo; $j++) {
|
||||
@@ -2605,6 +2616,20 @@ for($i=2; $i<@_; $i++) {
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif ($_[$i] =~ /^[a-f0-9:]+$/) {
|
||||
# Compare with IPv6 address or network
|
||||
@mo = split(/:/, $_[$i]);
|
||||
while(@mo && !$mo[$#mo]) { pop(@mo); }
|
||||
for($j=0; $j<@mo; $j++) {
|
||||
if ($mo[$j] != $io[$j]) {
|
||||
$mismatch = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif ($_[$i] !~ /^[0-9\.]+$/) {
|
||||
# Compare with hostname
|
||||
$mismatch = 1 if ($_[0] ne &to_ipaddress($_[$i]));
|
||||
}
|
||||
return 1 if (!$mismatch);
|
||||
}
|
||||
return 0;
|
||||
@@ -2659,17 +2684,65 @@ sub trigger_reload
|
||||
$need_reload = 1;
|
||||
}
|
||||
|
||||
# to_ipaddress(address, ...)
|
||||
sub to_ipaddress
|
||||
{
|
||||
local (@rv, $i);
|
||||
foreach $i (@_) {
|
||||
if ($i =~ /(\S+)\/(\S+)/ || $i =~ /^\*\S+$/ ||
|
||||
$i eq 'LOCAL' || $i =~ /^[0-9\.]+$/) { push(@rv, $i); }
|
||||
else { push(@rv, join('.', unpack("CCCC", inet_aton($i)))); }
|
||||
$i eq 'LOCAL' || $i =~ /^[0-9\.]+$/ || $i =~ /^[a-f0-9:]+$/) {
|
||||
# A pattern or IP, not a hostname, so don't change
|
||||
push(@rv, $i);
|
||||
}
|
||||
else {
|
||||
# Lookup IP address
|
||||
push(@rv, join('.', unpack("CCCC", inet_aton($i))));
|
||||
}
|
||||
}
|
||||
return wantarray ? @rv : $rv[0];
|
||||
}
|
||||
|
||||
# to_ip6address(address, ...)
|
||||
sub to_ip6address
|
||||
{
|
||||
local (@rv, $i);
|
||||
foreach $i (@_) {
|
||||
if ($i =~ /(\S+)\/(\S+)/ || $i =~ /^\*\S+$/ ||
|
||||
$i eq 'LOCAL' || $i =~ /^[0-9\.]+$/ || $i =~ /^[a-f0-9:]+$/) {
|
||||
# A pattern, not a hostname, so don't change
|
||||
push(@rv, $i);
|
||||
}
|
||||
else {
|
||||
# Lookup IPv6 address
|
||||
local ($inaddr, $addr);
|
||||
(undef, undef, undef, $inaddr) =
|
||||
getaddrinfo($i, undef, Socket6::AF_INET6(), SOCK_STREAM);
|
||||
if ($inaddr) {
|
||||
push(@rv, undef);
|
||||
}
|
||||
else {
|
||||
(undef, $addr) = unpack_sockaddr_in6($inaddr);
|
||||
push(@rv, inet_ntop(Socket6::AF_INET6(), $addr));
|
||||
}
|
||||
}
|
||||
}
|
||||
return wantarray ? @rv : $rv[0];
|
||||
}
|
||||
|
||||
# to_hostname(ipv4|ipv6-address)
|
||||
# Reverse-resolves an IPv4 or 6 address to a hostname
|
||||
sub to_hostname
|
||||
{
|
||||
local ($addr) = @_;
|
||||
if (&check_ip6address($_[0])) {
|
||||
return gethostbyaddr(inet_pton(Socket6::AF_INET6(), $addr),
|
||||
Socket6::AF_INET6());
|
||||
}
|
||||
else {
|
||||
return gethostbyaddr(inet_aton($addr), AF_INET);
|
||||
}
|
||||
}
|
||||
|
||||
# read_line(no-wait, no-limit)
|
||||
# Reads one line from SOCK or SSL
|
||||
sub read_line
|
||||
@@ -3517,7 +3590,7 @@ if ($ipv6) {
|
||||
}
|
||||
else {
|
||||
local ($p, $b) = unpack_sockaddr_in($sn);
|
||||
return ($b, inet_ntoa($myaddr), $p);
|
||||
return ($b, inet_ntoa($b), $p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,9 @@ for($i=0; defined($in{"ip_def_$i"}); $i++) {
|
||||
}
|
||||
else {
|
||||
$ip = $in{"ip_$i"};
|
||||
&check_ipaddress($ip) || &error(&text('bind_eip2', $ip));
|
||||
&check_ipaddress($ip) ||
|
||||
$in{'ipv6'} && &check_ip6address($ip) ||
|
||||
&error(&text('bind_eip2', $ip));
|
||||
}
|
||||
if ($in{"port_def_$i"} == 1) {
|
||||
$port = $in{"port_$i"};
|
||||
@@ -32,6 +34,10 @@ for($i=0; defined($in{"ip_def_$i"}); $i++) {
|
||||
$in{'listen_def'} || $in{'listen'} =~ /^\d+$/ || &error($text{'bind_elisten'});
|
||||
$in{'hostname_def'} || $in{'hostname'} =~ /^[a-z0-9\.\-]+$/i ||
|
||||
&error($text{'bind_ehostname'});
|
||||
if ($in{'ipv6'}) {
|
||||
eval "use Socket6";
|
||||
@$ && &error(&text('bind_eipv6', "<tt>Socket6</tt>"));
|
||||
}
|
||||
|
||||
# Update config file
|
||||
&lock_file($ENV{'MINISERV_CONFIG'});
|
||||
@@ -44,6 +50,7 @@ else {
|
||||
$miniserv{'bind'} = $first->[0];
|
||||
}
|
||||
$miniserv{'sockets'} = join(" ", map { "$_->[0]:$_->[1]" } @sockets);
|
||||
$miniserv{'ipv6'} = $in{'ipv6'};
|
||||
if ($in{'listen_def'}) {
|
||||
delete($miniserv{'listen'});
|
||||
}
|
||||
@@ -89,6 +96,7 @@ if ($tconfig{'inframe'}) {
|
||||
# Theme uses frames, so we need to redirect the whole frameset
|
||||
$url .= ":$miniserv{'port'}";
|
||||
&ui_print_header(undef, $text{'bind_title'}, "");
|
||||
print $text{'bind_redirecting'},"<p>\n";
|
||||
print "<script>\n";
|
||||
print "top.location = '$url';\n";
|
||||
print "</script>\n";
|
||||
|
||||
@@ -38,7 +38,11 @@ foreach $s (@sockets, [ undef, "*" ]) {
|
||||
$stable .= &ui_columns_end();
|
||||
print &ui_table_row($text{'bind_sockets'}, $stable);
|
||||
|
||||
# Show listen address
|
||||
# IPv6 enabled?
|
||||
print &ui_table_row($text{'bind_ipv6'},
|
||||
&ui_yesno_radio("ipv6", $miniserv{'ipv6'}));
|
||||
|
||||
# Show UDP listen address
|
||||
print &ui_table_row($text{'bind_listen'},
|
||||
&ui_radio("listen_def", $miniserv{"listen"} ? 0 : 1,
|
||||
[ [ 1, $text{'bind_none'} ],
|
||||
|
||||
@@ -54,6 +54,9 @@ bind_erestart=An error occurring starting Webmin with the new address and port s
|
||||
bind_elisten=Missing or invalid port to listen for UDP broadcasts on
|
||||
bind_ehostname=Missing or invalid web server hostname
|
||||
bind_resolv_myname=Reverse-resolve connected IP address?
|
||||
bind_ipv6=Accept IPv6 connections?
|
||||
bind_eipv6=IPv6 cannot be enabled unless the $1 Perl module is installed
|
||||
bind_redirecting=Redirecting to new URL ..
|
||||
|
||||
log_title=Logging
|
||||
log_desc=Webmin can be configured to write a log of web server hits, in the standard CLF log file format. If logging is enabled, you can also choose whether IP addresses or hostnames are recorded, and how often the log file is cleared. When enabled, logs are written to the file $1.
|
||||
|
||||
@@ -787,7 +787,8 @@ foreach $s (split(/\s+/, $_[0]->{'sockets'})) {
|
||||
# Listen on a specific port and IP
|
||||
push(@sockets, [ $1, $2 ]);
|
||||
}
|
||||
elsif ($s =~ /^([0-9\.]+):\*$/ || $s =~ /^([0-9\.]+)$/) {
|
||||
elsif ($s =~ /^([0-9\.]+):\*$/ || $s =~ /^([0-9\.]+)$/ ||
|
||||
$s =~ /^([a-f0-9:]+):\*$/ || $s =~ /^([a-f0-9:]+)$/) {
|
||||
# Listen on the main port on another IP
|
||||
push(@sockets, [ $1, "*" ]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user