1#!/usr/bin/perl
2
3use v5.14;
4use warnings;
5
6use Test::More;
7
8use Socket qw(PF_INET6 PF_INET IPPROTO_IPV6 IPV6_V6ONLY);
9use IO::Socket::IP;
10
11eval { IO::Socket::IP->new( LocalHost => "::1" ) } or
12   plan skip_all => "Unable to bind to ::1";
13
14eval { defined IPV6_V6ONLY } or
15   plan skip_all => "IPV6_V6ONLY not available";
16
17# https://rt.cpan.org/Ticket/Display.html?id=102662
18$^O eq "irix" and
19   plan skip_all => "$^O: IPV6_V6ONLY exists but getnameinfo() fails with EAI_NONAME";
20
21# Don't be locale-sensitive
22$! = Errno::ECONNREFUSED;
23my $ECONNREFUSED_STR = "$!";
24
25{
26   my $listensock = IO::Socket::IP->new(
27      Listen    => 1,
28      Family    => PF_INET6,
29      LocalPort => 0,
30      Type      => SOCK_STREAM,
31      V6Only    => 1,
32      GetAddrInfoFlags => 0, # disable AI_ADDRCONFIG
33   ) or die "Cannot listen on PF_INET6 - $IO::Socket::errstr";
34
35   is( $listensock->getsockopt( IPPROTO_IPV6, IPV6_V6ONLY ), 1, 'IPV6_V6ONLY is 1 on $listensock' );
36
37   my $testsock = IO::Socket::IP->new(
38      Family   => PF_INET,
39      PeerHost => "127.0.0.1",
40      PeerPort => $listensock->sockport,
41      Type     => SOCK_STREAM,
42      GetAddrInfoFlags => 0, # disable AI_ADDRCONFIG
43   );
44   my $err = "$IO::Socket::errstr";
45
46   ok( !defined $testsock, 'Unable to connect PF_INET socket to PF_INET6 socket with V6Only true' );
47   like( $err, qr/\Q$ECONNREFUSED_STR/, 'Socket creation fails with connection refused' );
48}
49
50SKIP: {
51   skip "This platform does not allow turning IPV6_V6ONLY off", 3 unless IO::Socket::IP->CAN_DISABLE_V6ONLY;
52
53   local $ENV{LANG} = "C"; # avoid locale-dependent error messages
54
55   my $listensock = IO::Socket::IP->new(
56      Listen    => 1,
57      Family    => PF_INET6,
58      LocalPort => 0,
59      Type      => SOCK_STREAM,
60      V6Only    => 0,
61      GetAddrInfoFlags => 0, # disable AI_ADDRCONFIG
62   ) or die "Cannot listen on PF_INET6 - $IO::Socket::errstr";
63
64   is( $listensock->getsockopt( IPPROTO_IPV6, IPV6_V6ONLY ), 0, 'IPV6_V6ONLY is 0 on $listensock' );
65
66   my $testsock = IO::Socket::IP->new(
67      Family   => PF_INET,
68      PeerHost => "127.0.0.1",
69      PeerPort => $listensock->sockport,
70      Type     => SOCK_STREAM,
71      GetAddrInfoFlags => 0, # disable AI_ADDRCONFIG
72   );
73   my $err = "$IO::Socket::errstr";
74
75   ok( defined $testsock, 'Connected PF_INET socket to PF_INET6 socket with V6Only false' ) or
76      diag( "IO::Socket::IP->new failed - $err" );
77   is( $testsock->peerport, $listensock->sockport, 'Test socket connected to correct peer port' );
78}
79
80done_testing;
81