Skip Menu |

This queue is for tickets about the IO-Socket-IP CPAN distribution.

Report information
The Basics
Id: 132760
Status: open
Priority: 0/
Queue: IO-Socket-IP

People
Owner: Nobody in particular
Requestors: dom [...] earth.li
Cc: gregoa [...] cpan.org
AdminCc:

Bug Information
Severity: Normal
Broken in: 0.39
Fixed in: (no value)



Subject: Test failures with ipv6-only host
As seen on the Debian buildd network (see https://bugs.debian.org/962047) many tests fail when run on a machine with only IPv6 networking. The attached patch fixes them by forcing no address lookups to take place.
Subject: 0001-Fix-test-failures-with-an-IPv6-only-host.patch
From c710a8aa2d8f7ee14bb811fd89f34d45fd56e2fe Mon Sep 17 00:00:00 2001 From: Dominic Hargreaves <dom@earth.li> Date: Tue, 2 Jun 2020 20:56:42 +0100 Subject: [PATCH] Fix test failures with an IPv6-only host This can be tested with: # unshare -n # ip li set lo up # ip li add dummy0 type dummy # ip li set dummy0 up Bug-Debian: https://bugs.debian.org/962047 --- t/01local-client-v4.t | 4 +++- t/02local-server-v4.t | 3 ++- t/03local-cross-v4.t | 3 +++ t/11sockopts.t | 6 +++++- t/18fdopen.t | 3 ++- t/20subclass.t | 3 +++ t/21as-inet.t | 3 +++ t/22timeout.t | 3 +++ t/30nonblocking-connect.t | 4 +++- 9 files changed, 27 insertions(+), 5 deletions(-) diff --git a/t/01local-client-v4.t b/t/01local-client-v4.t index 7ab7156..f6aeac4 100644 --- a/t/01local-client-v4.t +++ b/t/01local-client-v4.t @@ -8,7 +8,7 @@ use Test::More; use IO::Socket::IP; use IO::Socket::INET; -use Socket qw( inet_aton inet_ntoa pack_sockaddr_in unpack_sockaddr_in ); +use Socket qw( inet_aton inet_ntoa pack_sockaddr_in unpack_sockaddr_in AI_NUMERICHOST ); # Some odd locations like BSD jails might not like INADDR_LOOPBACK. We'll # establish a baseline first to test against @@ -29,12 +29,14 @@ foreach my $socktype (qw( SOCK_STREAM SOCK_DGRAM )) { LocalHost => "127.0.0.1", Type => Socket->$socktype, Proto => ( $socktype eq "SOCK_STREAM" ? "tcp" : "udp" ), # Because IO::Socket::INET is stupid and always presumes tcp + GetAddrInfoFlags => AI_NUMERICHOST, ) or die "Cannot listen on PF_INET - $@"; my $socket = IO::Socket::IP->new( PeerHost => "127.0.0.1", PeerService => $testserver->sockport, Type => Socket->$socktype, + GetAddrInfoFlags => AI_NUMERICHOST, ); ok( defined $socket, "IO::Socket::IP->new constructs a $socktype socket" ) or diff --git a/t/02local-server-v4.t b/t/02local-server-v4.t index c0d349f..fb711f0 100644 --- a/t/02local-server-v4.t +++ b/t/02local-server-v4.t @@ -8,7 +8,7 @@ use Test::More; use IO::Socket::IP; use IO::Socket::INET; -use Socket qw( inet_aton inet_ntoa pack_sockaddr_in unpack_sockaddr_in ); +use Socket qw( inet_aton inet_ntoa pack_sockaddr_in unpack_sockaddr_in AI_NUMERICHOST ); # Some odd locations like BSD jails might not like INADDR_LOOPBACK. We'll # establish a baseline first to test against @@ -29,6 +29,7 @@ foreach my $socktype (qw( SOCK_STREAM SOCK_DGRAM )) { LocalHost => "127.0.0.1", LocalPort => "0", Type => Socket->$socktype, + GetAddrInfoFlags => AI_NUMERICHOST, ); ok( defined $testserver, "IO::Socket::IP->new constructs a $socktype socket" ) or diff --git a/t/03local-cross-v4.t b/t/03local-cross-v4.t index 8cac72a..3e8174e 100644 --- a/t/03local-cross-v4.t +++ b/t/03local-cross-v4.t @@ -6,6 +6,7 @@ use warnings; use Test::More; use IO::Socket::IP; +use Socket qw(AI_NUMERICHOST); foreach my $socktype (qw( SOCK_STREAM SOCK_DGRAM )) { my $testserver = IO::Socket::IP->new( @@ -13,12 +14,14 @@ foreach my $socktype (qw( SOCK_STREAM SOCK_DGRAM )) { LocalHost => "127.0.0.1", LocalPort => "0", Type => Socket->$socktype, + GetAddrInfoFlags => AI_NUMERICHOST, ) or die "Cannot listen on PF_INET - $@"; my $socket = IO::Socket::IP->new( PeerHost => "127.0.0.1", PeerService => $testserver->sockport, Type => Socket->$socktype, + GetAddrInfoFlags => AI_NUMERICHOST, ) or die "Cannot connect on PF_INET - $@"; my $testclient = ( $socktype eq "SOCK_STREAM" ) ? diff --git a/t/11sockopts.t b/t/11sockopts.t index 5b85092..28daada 100644 --- a/t/11sockopts.t +++ b/t/11sockopts.t @@ -8,7 +8,7 @@ use Test::More; use IO::Socket::IP; use Errno qw( EACCES ); -use Socket qw( SOL_SOCKET SO_REUSEADDR SO_REUSEPORT SO_BROADCAST ); +use Socket qw( SOL_SOCKET SO_REUSEADDR SO_REUSEPORT SO_BROADCAST AI_NUMERICHOST); TODO: { local $TODO = "SO_REUSEADDR doesn't appear to work on cygwin smokers" if $^O eq "cygwin"; @@ -21,6 +21,7 @@ TODO: { Type => SOCK_STREAM, Listen => 1, ReuseAddr => 1, + GetAddrInfoFlags => AI_NUMERICHOST, ) or die "Cannot socket() - $@"; ok( $sock->getsockopt( SOL_SOCKET, SO_REUSEADDR ), 'SO_REUSEADDR set' ); @@ -32,6 +33,7 @@ TODO: { Sockopts => [ [ SOL_SOCKET, SO_REUSEADDR ], ], + GetAddrInfoFlags => AI_NUMERICHOST, ) or die "Cannot socket() - $@"; ok( $sock->getsockopt( SOL_SOCKET, SO_REUSEADDR ), 'SO_REUSEADDR set via Sockopts' ); @@ -50,6 +52,7 @@ SKIP: { Type => SOCK_STREAM, Listen => 1, ReusePort => 1, + GetAddrInfoFlags => AI_NUMERICHOST, ) or die "Cannot socket() - $@"; ok( $sock->getsockopt( SOL_SOCKET, SO_REUSEPORT ), 'SO_REUSEPORT set' ); @@ -62,6 +65,7 @@ SKIP: { LocalHost => "127.0.0.1", Type => SOCK_DGRAM, Broadcast => 1, + GetAddrInfoFlags => AI_NUMERICHOST, ); skip "Privileges required to set broadcast on datagram socket", 1 if !$sock and $! == EACCES; die "Cannot socket() - $@" unless $sock; diff --git a/t/18fdopen.t b/t/18fdopen.t index 20cbe46..6843a2c 100644 --- a/t/18fdopen.t +++ b/t/18fdopen.t @@ -6,12 +6,13 @@ use warnings; use Test::More; use IO::Socket::IP; -use Socket qw( SOCK_STREAM ); +use Socket qw( SOCK_STREAM AI_NUMERICHOST ); my $s1 = IO::Socket::IP->new( LocalHost => "127.0.0.1", Type => SOCK_STREAM, Listen => 1, + GetAddrInfoFlags => AI_NUMERICHOST, ) or die "Cannot listen on AF_INET - $@"; my $s2 = IO::Socket::IP->new; diff --git a/t/20subclass.t b/t/20subclass.t index 231bd52..fbc9cff 100644 --- a/t/20subclass.t +++ b/t/20subclass.t @@ -6,16 +6,19 @@ use warnings; use Test::More; use IO::Socket::IP; +use Socket qw( AI_NUMERICHOST ); my $server = IO::Socket::IP->new( Listen => 1, LocalHost => "127.0.0.1", LocalPort => 0, + GetAddrInfoFlags => AI_NUMERICHOST, ) or die "Cannot listen on PF_INET - $!"; my $client = IO::Socket::IP->new( PeerHost => $server->sockhost, PeerPort => $server->sockport, + GetAddrInfoFlags => AI_NUMERICHOST, ) or die "Cannot connect on PF_INET - $!"; my $accepted = $server->accept( 'MySubclass' ) diff --git a/t/21as-inet.t b/t/21as-inet.t index 2b8713d..fedb8be 100644 --- a/t/21as-inet.t +++ b/t/21as-inet.t @@ -6,16 +6,19 @@ use warnings; use Test::More; use IO::Socket::IP; +use Socket qw( AI_NUMERICHOST ); my $server = IO::Socket::IP->new( Listen => 1, LocalHost => "127.0.0.1", LocalPort => 0, + GetAddrInfoFlags => AI_NUMERICHOST, ) or die "Cannot listen on PF_INET - $!"; my $client = IO::Socket::IP->new( PeerHost => $server->sockhost, PeerPort => $server->sockport, + GetAddrInfoFlags => AI_NUMERICHOST, ) or die "Cannot connect on PF_INET - $!"; my $accepted = $server->accept diff --git a/t/22timeout.t b/t/22timeout.t index a4c28b3..c4a08f5 100644 --- a/t/22timeout.t +++ b/t/22timeout.t @@ -6,17 +6,20 @@ use warnings; use Test::More; use IO::Socket::IP; +use Socket qw( AI_NUMERICHOST ); my $server = IO::Socket::IP->new( Listen => 1, LocalHost => "127.0.0.1", LocalPort => 0, + GetAddrInfoFlags => AI_NUMERICHOST, ) or die "Cannot listen on PF_INET - $!"; my $client = IO::Socket::IP->new( PeerHost => $server->sockhost, PeerPort => $server->sockport, Timeout => 0.1, + GetAddrInfoFlags => AI_NUMERICHOST, ) or die "Cannot connect on PF_INET - $!"; ok( defined $client, 'client constructed with Timeout' ); diff --git a/t/30nonblocking-connect.t b/t/30nonblocking-connect.t index 518bd2e..ade8349 100644 --- a/t/30nonblocking-connect.t +++ b/t/30nonblocking-connect.t @@ -8,7 +8,7 @@ use Test::More; use IO::Socket::IP; use IO::Socket::INET; -use Socket qw( inet_aton inet_ntoa pack_sockaddr_in unpack_sockaddr_in ); +use Socket qw( inet_aton inet_ntoa pack_sockaddr_in unpack_sockaddr_in AI_NUMERICHOST ); use Errno qw( EINPROGRESS EWOULDBLOCK ); # Some odd locations like BSD jails might not like INADDR_LOOPBACK. We'll @@ -27,6 +27,7 @@ my $testserver = IO::Socket::INET->new( Listen => 1, LocalHost => "127.0.0.1", Type => SOCK_STREAM, + GetAddrInfoFlags => AI_NUMERICHOST, ) or die "Cannot listen on PF_INET - $@"; my $socket = IO::Socket::IP->new( @@ -34,6 +35,7 @@ my $socket = IO::Socket::IP->new( PeerService => $testserver->sockport, Type => SOCK_STREAM, Blocking => 0, + GetAddrInfoFlags => AI_NUMERICHOST, ); ok( defined $socket, 'IO::Socket::IP->new( Blocking => 0 ) constructs a socket' ) or -- 2.20.1
Niko Tyni did more investigation and tests: https://bugs.debian.org/964902 and came up with a new patch (replacing the one attached here earlier), available in the Debian bug report and also attached for convenience. Cheers, gregor
Subject: 0001-Disable-getaddrinfo-3-AI_ADDRCONFIG-for-localhost-an.patch
From fbed100b2501f9ba1537acd65f160353fc3acd73 Mon Sep 17 00:00:00 2001 From: Niko Tyni <ntyni@debian.org> Date: Sat, 4 Jul 2020 22:17:41 +0100 Subject: [PATCH] Disable getaddrinfo(3) AI_ADDRCONFIG for localhost and IPv4 numeric addresses AI_ADDRCONFIG can be a bad default for systems with a dual protocol loopback device but just IPv6 connectivity. In such a case, getaddrinfo(3) on 127.0.0.1 or 0.0.0.0 will fail with EAI_ADDRFAMILY even though the loopback device is able to handle them. --- lib/IO/Socket/IP.pm | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/lib/IO/Socket/IP.pm b/lib/IO/Socket/IP.pm index 5a5ee7d..2481c63 100755 --- a/lib/IO/Socket/IP.pm +++ b/lib/IO/Socket/IP.pm @@ -30,6 +30,7 @@ use Socket 1.97 qw( ); my $AF_INET6 = eval { Socket::AF_INET6() }; # may not be defined my $AI_ADDRCONFIG = eval { Socket::AI_ADDRCONFIG() } || 0; +my $AI_NUMERICHOST = eval { Socket::AI_NUMERICHOST() } || 0; use POSIX qw( dup2 ); use Errno qw( EINVAL EINPROGRESS EISCONN ENOTCONN ETIMEDOUT EWOULDBLOCK EOPNOTSUPP ); @@ -409,6 +410,8 @@ sub _io_socket_ip__configure my ( $arg ) = @_; my %hints; + my $localflags; + my $peerflags; my @localinfos; my @peerinfos; @@ -420,9 +423,20 @@ sub _io_socket_ip__configure if( defined $arg->{GetAddrInfoFlags} ) { $hints{flags} = $arg->{GetAddrInfoFlags}; + $localflags = $arg->{GetAddrInfoFlags}; + $peerflags = $arg->{GetAddrInfoFlags}; } else { - $hints{flags} = $AI_ADDRCONFIG; + if (defined $arg->{LocalHost} and $arg->{LocalHost} =~ /^\d+\.\d+\.\d+\.\d+$/) { + $localflags = $AI_NUMERICHOST; + } else { + $localflags = $AI_ADDRCONFIG; + } + if (defined $arg->{PeerHost} and $arg->{PeerHost} =~ /^\d+\.\d+\.\d+\.\d+$/) { + $peerflags = $AI_NUMERICHOST; + } elsif (defined $arg->{PeerHost} and $arg->{PeerHost} ne 'localhost') { + $peerflags = $AI_ADDRCONFIG; + } } if( defined( my $family = $arg->{Family} ) ) { @@ -479,6 +493,7 @@ sub _io_socket_ip__configure my $fallback_port = $1; my %localhints = %hints; + $localhints{flags} = $localflags; $localhints{flags} |= AI_PASSIVE; ( my $err, @localinfos ) = getaddrinfo( $host, $service, \%localhints ); @@ -507,10 +522,12 @@ sub _io_socket_ip__configure defined $service and $service =~ s/\((\d+)\)$// and my $fallback_port = $1; - ( my $err, @peerinfos ) = getaddrinfo( $host, $service, \%hints ); + my %peerhints = %hints; + $peerhints{flags} = $peerflags; + ( my $err, @peerinfos ) = getaddrinfo( $host, $service, \%peerhints ); if( $err and defined $fallback_port ) { - ( $err, @peerinfos ) = getaddrinfo( $host, $fallback_port, \%hints ); + ( $err, @peerinfos ) = getaddrinfo( $host, $fallback_port, \%peerhints ); } if( $err ) { @@ -590,6 +607,7 @@ sub _io_socket_ip__configure # If there wasn't, use getaddrinfo()'s AI_ADDRCONFIG side-effect to guess a # suitable family first. else { + $hints{flags} |= $AI_ADDRCONFIG; ( my $err, @infos ) = getaddrinfo( "", "0", \%hints ); if( $err ) { $@ = "$err"; -- 2.26.2
As a heads up, there was some discussion on debian-devel about how this is something which should be fixed in libc. This is the Debian bug about the issue from this perspective: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=952740 There doesn't seem any prospect of this being fixed in the near future, so we're planning to apply the last patch gregoa forwarded to IO-Socket-IP in Debian to solve the immediate issues of failing tests.