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