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

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to