After a bit of poking around different flavors of IPv6 systems, I've encountered a few situations where Apache::Test ends up configuring httpd in a way that can't be tested.
This typically only happens on a system that has IPv4-mapped IPv6 addresses disabled, i.e. OpenBSD. If the hostname that is picked to form the Listen directives happens to have both an IPv4 and an IPv6 address, i.e localhot on OpenBSD, the server will start but will only be listening on an IPv6 address. And since LWP doesn't do requests over IPv6, all tests will fail. The following patch attempts to do handle all this by doing one of a few many things. If the server has ipv4-mapped addresses, Listen to *:port, forcing the use of ipv4-mapped addresses and insuring that the server will be available over it's ipv4 address. Otherwise try to use Socket6 to see if the hostname is both v4 and v6 and Listen to *:port as well. Without Socket6 (not part of the Perl core), just warn the user about possible problems he/she will run into if the selected hostname happens to be ipv6. Tested for me under Linux (w and w/o ipv6), FreeBSD & OpenBSD. Index: lib/Apache/TestConfigPerl.pm =================================================================== RCS file: /home/cvs/httpd-test/perl-framework/Apache-Test/lib/Apache/TestConfigPerl.pm,v retrieving revision 1.85 diff -u -I$Id -r1.85 TestConfigPerl.pm --- lib/Apache/TestConfigPerl.pm 16 Mar 2004 03:10:32 -0000 1.85 +++ lib/Apache/TestConfigPerl.pm 29 Mar 2004 23:26:43 -0000 @@ -222,7 +222,7 @@ my($self, $module, $args) = @_; my $port = $self->new_vhost($module); my $vars = $self->{vars}; - $self->postamble(Listen => $vars->{servername} . ':' . $port); + $self->postamble(Listen => $vars->{listen_addr} . ':' . $port); } my %add_hook_config = ( Index: lib/Apache/TestConfig.pm =================================================================== RCS file: /home/cvs/httpd-test/perl-framework/Apache-Test/lib/Apache/TestConfig.pm,v retrieving revision 1.213 diff -u -I$Id -r1.213 TestConfig.pm --- lib/Apache/TestConfig.pm 4 Mar 2004 05:51:31 -0000 1.213 +++ lib/Apache/TestConfig.pm 29 Mar 2004 23:26:43 -0000 @@ -63,6 +63,7 @@ documentroot => 'DocumentRoot (default is $ServerRoot/htdocs', port => 'Port [port_number|select] (default ' . DEFAULT_PORT . ')', servername => 'ServerName (default is localhost)', + listen_addr => 'The address to use in Listen directives', user => 'User to run test server as (default is $USER)', group => 'Group to run test server as (default is $GROUP)', bindir => 'Apache bin/ dir (default is apxs -q BINDIR)', @@ -272,7 +273,7 @@ $vars->{servername} ||= $self->default_servername; $vars->{port} = $self->select_first_port; $vars->{remote_addr} ||= $self->our_remote_addr; - + $vars->{listen_addr} ||= $self->default_localhost; $vars->{user} ||= $self->default_user; $vars->{group} ||= $self->default_group; $vars->{serveradmin} ||= $self->default_serveradmin; @@ -286,6 +287,8 @@ $self->inherit_config; #see TestConfigParse.pm $self->configure_httpd_eapi; #must come after inherit_config + $self->check_ipv6; + $self->default_module(cgi => [qw(mod_cgi mod_cgid)]); $self->default_module(thread => [qw(worker threaded)]); $self->default_module(ssl => [qw(mod_ssl)]); @@ -637,6 +640,45 @@ $remote_addr ||= Socket::inet_ntoa($iaddr); } +my $apr_ipv6; +sub apr_has_ipv6 { + my $self = shift; + return $apr_ipv6 if defined $apr_ipv6; + foreach my $key (keys %{$self->{httpd_defines}}) { + return $apr_ipv6 = $key if $key =~ /^APR_HAVE_IPV6/; + } +} + +sub apr_has_ipv4_mapped { + my $self = shift; + return $self->apr_has_ipv6 =~ /IPv4-mapped addresses enabled/; +} + +sub check_ipv6 { + my $self = shift; + + return if $self->{vars}{listen_addr} ne $self->default_localhost; + + my $name = $self->{vars}{servername}; + + if ($self->apr_has_ipv6) { + if ($self->apr_has_ipv4_mapped) { + $self->{vars}{listen_addr} = '*'; + } + else { + if (eval { require Socket6 }) { + if (Socket6::gethostbyname2($name, Socket6::AF_INET6())) { + $self->{vars}{listen_addr} = '*'; + } + } + else { + warning "Socket6 not installed"; + warning "Test might fail if your hostname: '$name' has an IPv6 address"; + } + } + } +} + sub default_loopback { '127.0.0.1'; } @@ -1017,7 +1059,7 @@ my @out_config = (); if ($self->{vhosts}->{$module}->{namebased} < 2) { #extra config that should go *outside* the <VirtualHost ...> - @out_config = ([Listen => $vars->{servername} . ':' . $port]); + @out_config = ([Listen => $vars->{listen_addr} . ':' . $port]); if ($self->{vhosts}->{$module}->{namebased}) { push @out_config => [NameVirtualHost => "*:$port"]; @@ -1785,7 +1827,7 @@ __DATA__ -Listen @ServerName@:@Port@ +Listen @Listen_Addr@:@Port@ ServerRoot "@ServerRoot@" DocumentRoot "@DocumentRoot@" -- Philippe M. Chiasson m/gozer\@(apache|cpan|ectoplasm)\.org/ GPG KeyID : 88C3A5A5 http://gozer.ectoplasm.org/ F9BF E0C2 480E 7680 1AE5 3631 CB32 A107 88C3A5A5
signature.asc
Description: This is a digitally signed message part