Skip Menu |

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

Report information
The Basics
Id: 103423
Status: resolved
Priority: 0/
Queue: IO-Socket-SSL

People
Owner: Nobody in particular
Requestors: w.phillip.moore [...] gmail.com
Cc: ether [...] cpan.org
AdminCc:

Bug Information
Severity: Important
Broken in: 2.012
Fixed in: (no value)



Subject: IO::Socket::IP and IO::Socket::SSL do not play well together
I'm using the latest IO::Socket::SSL 2.012 with perl 5.20.1, which includes IO::Socket::IP 0.29, and I've discovered that if IO::Socket::SSL::connect fails, then the error is never displayed. I have a rather complex application with uses IO::Socket::SSL with a lot of autogenerated and automanaged SSL certificates, and it started to fail use to what was an issue with how one of the certificates was being created. However, it took me quite a while to figure this out, because failed calls to IO::Socket::SSL->new() were returning undef, and not setting either $! or $@, but instead the very non-standard $SSL_ERROR, which had this value: IO::Socket::IP configuration failed In years of developing IO::Socket::SSL apps I had never seen this one before. I did some digging, and found that the problem is that IO::Socket::IP makes an assumption about IO::Socket::SSL::connect which is not true. Namely, that if it fails, it will set $!, which I don't think has ever been true. The offending code is in IO::Socket::IP::setup 603 if( defined( my $addr = $info->{peeraddr} ) ) { 604 if( $self->connect( $addr ) ) { 605 $! = 0; 606 return 1; 607 } 608 609 if( $! == EINPROGRESS or HAVE_MSWIN32 && $! == Errno::EWOULDBLOCK() ) { 610 ${*$self}{io_socket_ip_connect_in_progress} = 1; 611 return 0; 612 } 613 614 ${*$self}{io_socket_ip_errors}[0] = $!; 615 next; 616 } When IO::Socket::SSL::connect fails, $! is an empty string, which is defined, so at the end of the subroutine: 621 # Pick the most appropriate error, stringified 622 $! = ( grep defined, @{ ${*$self}{io_socket_ip_errors}} )[0]; 623 $@ = "$!"; 624 return undef; But that results in both $! and $@ being the empty string, and the real error is lost. In my case, the real error, found only by stepping through the code in the debugger, is: SSL connect attempt failed error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed The root cause of that problem is an issue in my test suite, so I own that. However, it would really be nice if IO::Socket::SSL and IO::Socket::IP worked together correctly, especially since IO::Socket::SSL prefers IO::Socket::IP it if is available. IO::Socket::SSL also has no means of controlling which IO::Socket::* class gets used, so users of perl5.20 end up being forced to use IO::Socket::IP. I'm going to post this in the IO::Socket::SSL queue as well, and hopefully I can get the two authors to collaborate on the best solution. Personally, I think the fact that IO::Socket::SSL sets a totally non-standard error variable is a serious mistake in that code, since it means that code like IO::Socket::IP has to handle that as a special case. I think it would be cleanest if IO::Socket::SSL::connect set $!, or $@, in additional to $SSL_ERROR whenever the latter is true. I haven't yet chased down why I'm seeing $SSL_ERROR but not $!, so I don't know if that is expected behavior or not. Now to figure out why my certs are broken.....
Am Do 09. Apr 2015, 12:44:33, WPMOORE schrieb: Show quoted text
> I'm using the latest IO::Socket::SSL 2.012 with perl 5.20.1, which > includes IO::Socket::IP 0.29, and I've discovered that if > IO::Socket::SSL::connect fails, then the error is never displayed.
Please use at least IO::Socket::IP version 0.31 (current version is 0.37). As you might see from the Changelog of IO::Socket::IP there were changes made to work better with IO::Socket::SSL. See also https://rt.cpan.org/Public/Bug/Display.html?id=95983
On 2015-04-09 13:24:03, SULLR wrote: Show quoted text
> > > > Am Do 09. Apr 2015, 12:44:33, WPMOORE schrieb:
> > I'm using the latest IO::Socket::SSL 2.012 with perl 5.20.1, which > > includes IO::Socket::IP 0.29, and I've discovered that if > > IO::Socket::SSL::connect fails, then the error is never displayed.
> > Please use at least IO::Socket::IP version 0.31 (current version is > 0.37). > As you might see from the Changelog of IO::Socket::IP there were > changes made to work better with IO::Socket::SSL. > See also https://rt.cpan.org/Public/Bug/Display.html?id=95983
In this case, shouldn't IO::Socket::SSL's Makefile.PL specify a minimum version?
Show quoted text
> In this case, shouldn't IO::Socket::SSL's Makefile.PL specify a > minimum version?
IO::Socket::SSL does not depend on IO::Socket::IP at all, but will use it if it exists to have IPv6 support. Thus specifying a minimal version in Makefile.PL will not work. It actually looks at the version when trying to load the module in IO/Socket/SSL.pm and requires at least 0.20 (and excludes the broken 0.30). It does not require at least 0.31 because lower version mostly work, the only problem is with error propagation on connect.
On 2015-04-10 00:10:14, SULLR wrote: Show quoted text
>
> > In this case, shouldn't IO::Socket::SSL's Makefile.PL specify a > > minimum version?
> > IO::Socket::SSL does not depend on IO::Socket::IP at all, but will use > it if it exists to have IPv6 support. > Thus specifying a minimal version in Makefile.PL will not work.
I thought about doing something like this in Makefile.PL: my %additional_PREREQ_PM; if (eval { require IO::Socket::IP; $IO::Socket::IP::VERSION < 0.31 }) { $additional_PREREQ_PM{'IO::Socket::IP'} = 0.31; } Additionally the IO::Socket::SSL module itself should probably not use IO::Socket::IP if it's too old. Show quoted text
> It > actually looks at the version when trying to load the module in > IO/Socket/SSL.pm and requires at least 0.20 (and excludes the broken > 0.30). It does not require at least 0.31 because lower version mostly > work, the only problem is with error propagation on connect.
Maybe "mostly work" is not enough --- see the existence of this ticket.
Subject: Re: [rt.cpan.org #103423] IO::Socket::IP and IO::Socket::SSL do not play well together
Date: Fri, 10 Apr 2015 09:33:11 -0400
To: bug-IO-Socket-SSL [...] rt.cpan.org
From: Phillip Moore <w.phillip.moore [...] gmail.com>
In this case, the workaround for me was to declare a dependency on IO::Socket::IP that I don't really have, in order to force the use of the newer version, and get my code to work. I understand why you guys have to add all this insanely complex code in the Makefile.PL, but I have for decades been opposed to the use of dynamic, runtime dependency decisions. When you have no choice I get it (conditionally depending on modules that only work on Windows, for example), but is there any reason you can't simplify this and just assert the dependency on IO::Socket::IP? Right now, you only "see" IO::Socket::IP if you use perl5.20, since that is the first core that the module appears in. If someone installs a fresh perl5.20, and then installs IO::Socket::SSL with cpanp, or one of the similar tools, they will not upgrade IO::Socket::IP for you, and this means that the default behavior in a clean 5.20 installation is buggy. And BTW, the test suite doesn't expose this bug (perhaps it should), so it will go unnoticed until someone has a connection problem, and they have NO diagnostics to figure it out. That makes this bug a tad more severe in my opinion. Unless you need to support very old core versions for which IO::Socket::IP might not work (and I was able to install it cleanly for everything back to 5.16, which is the oldest perl core I currently support), it seems to me that asserting the dependency to ensure that installation of IO::Socket::SSL always gets the latest IO::Socket::IP would be the better solution. This lets you remove some significant complexity from the code as well, but again, this might require dropping support in the newer code for some older perls, or perhaps older platforms. Your code, your call.... I can live with my workaround for now. On Fri, Apr 10, 2015 at 1:37 AM, Slaven_Rezic via RT < bug-IO-Socket-SSL@rt.cpan.org> wrote: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=103423 > > > On 2015-04-10 00:10:14, SULLR wrote:
> >
> > > In this case, shouldn't IO::Socket::SSL's Makefile.PL specify a > > > minimum version?
> > > > IO::Socket::SSL does not depend on IO::Socket::IP at all, but will use > > it if it exists to have IPv6 support. > > Thus specifying a minimal version in Makefile.PL will not work.
> > I thought about doing something like this in Makefile.PL: > > my %additional_PREREQ_PM; > if (eval { require IO::Socket::IP; $IO::Socket::IP::VERSION < 0.31 }) { > $additional_PREREQ_PM{'IO::Socket::IP'} = 0.31; > } > > Additionally the IO::Socket::SSL module itself should probably not use > IO::Socket::IP if it's too old. >
> > It > > actually looks at the version when trying to load the module in > > IO/Socket/SSL.pm and requires at least 0.20 (and excludes the broken > > 0.30). It does not require at least 0.31 because lower version mostly > > work, the only problem is with error propagation on connect.
> > Maybe "mostly work" is not enough --- see the existence of this ticket. > >
Am Fr 10. Apr 2015, 01:37:58, SREZIC schrieb: Show quoted text
> I thought about doing something like this in Makefile.PL: > > my %additional_PREREQ_PM; > if (eval { require IO::Socket::IP; $IO::Socket::IP::VERSION < 0.31 }) > { > $additional_PREREQ_PM{'IO::Socket::IP'} = 0.31; > } >
That might be a good idea.
Am Fr 10. Apr 2015, 09:33:35, WPMOORE schrieb: Show quoted text
> > Right now, you only "see" IO::Socket::IP if you use perl5.20, since > that is > the first core that the module appears in. If someone installs a
Actually you see IO::Socket::IP also if you installed it yourself to get IPv6 support in earlier versions of Perl. Or you might have installed IO::Socket::INET6 instead which was the preferred module for IPv6 before IO::Socket::IP came. Show quoted text
> Unless you need to support very old core versions for which > IO::Socket::IP > might not work (and I was able to install it cleanly for everything > back to > 5.16, which is the oldest perl core I currently support), it seems to > me
IO::Socket::SSL supports older Perl versions down to 5.8 and I have no intention to limit the support in the near future. This also means that I have to deal with installations not having any IPv6 support, having IO::Socket::INET6 for IPv6 or having IO::Socket::IP. I don't like to enforce use of IO::Socket::IP if the user has either another working IPv6 module or has no need for IPv6 at all, because installing IO::Socket::IP requires a lot more changes in the current installation then the user might like. Especially it requires a newer Socket version which then needs a compiler to install and which might also behave slightly different to the Socket module coming with the original Perl installation.
I wonder if this is the problem I've been seeing with Test::LWP::UserAgent's tests: http://matrix.cpantesters.org/?dist=Test-LWP-UserAgent+0.027 I've been meaning to do a re-release that also includes the installed versions of IO::Socket::*, but haven't yet gotten around to it. Indeed all the test failures are during making network connections to example.com. I'm in favour of dynamic prereqs in Makefile.PL when they make sense. I'd much rather have those than have a too-high prereq imposed when it's *not* actually needed, as that can cause a burden downstream with packagers as well as when juggling large repositories for application deployments (something I'm involved with at $work). I'm also in favour of adding a test that explicitly checks for the type of error that can occur when the version combination is bad. Failing earlier would make it a lot easier to figure out what's going on. If you know the exact combination of upgrades that needs to occur to resolve this connection issue, can you leave it in this ticket so I can make the appropriate modifications for Test::LWP::UserAgent's Makefile.PL? much appreciated!!
Am Fr 10. Apr 2015, 12:58:50, ETHER schrieb: Show quoted text
> I wonder if this is the problem I've been seeing with > Test::LWP::UserAgent's tests: > > http://matrix.cpantesters.org/?dist=Test-LWP-UserAgent+0.027 > > I've been meaning to do a re-release that also includes the installed > versions of IO::Socket::*, but haven't yet gotten around to it. > Indeed all the test failures are during making network connections to > example.com.
Yes, but they are to example.com:80 already, so no https and thus no IO::Socket::SSL is involved. For me these tests simply look like a connectivity problem, i.e. somebody enabling live tests without having the proper environment to do live tests. I have live tests enabled by default but these are written in a way, that they will detect connectivity and other problems (like SSL intercepting firewalls) and skip the tests in these cases. Show quoted text
> I'm in favour of dynamic prereqs in Makefile.PL when they make sense. > I'd much rather have those than have a too-high prereq imposed when > it's *not* actually needed, as that can cause a burden downstream with > packagers as well as when juggling large repositories for application > deployments (something I'm involved with at $work).
I though again about it: I think it is not useful to add IO::Socket::IP to prereq, because either the user has already the correct version or has IO::Socket::INET6 or does not need IPv6 support. In the just released 2.013 I've upped the required version of IO::Socket::IP to 0.31, but still does not require the module as prerequisite. If the user has this module not installed or has a lower version IPv6 support will simply not be available. I've also reworked error propagation in 2.013, so that follow-up errors like "configuration failed" don't replace more specific errors like "hostname verification failed". This should help in solving the original problem too.
With 2.013 the issue should hopefully be resolved, i.e. it will use IO::Socket::IP only if at least version 0.31 is installed and it will not replace the original error ("hostname verification failed") with follow-up errors ("configuration failed").
On 2015-05-01 08:51:26, SULLR wrote: Show quoted text
> Am Fr 10. Apr 2015, 12:58:50, ETHER schrieb:
> > I wonder if this is the problem I've been seeing with > > Test::LWP::UserAgent's tests: > > > > http://matrix.cpantesters.org/?dist=Test-LWP-UserAgent+0.027 > > > > I've been meaning to do a re-release that also includes the installed > > versions of IO::Socket::*, but haven't yet gotten around to it. > > Indeed all the test failures are during making network connections to > > example.com.
> > Yes, but they are to example.com:80 already, so no https and thus no > IO::Socket::SSL > is involved. For me these tests simply look like a connectivity > problem, i.e. somebody > enabling live tests without having the proper environment to do live > tests.
Agreed! I'm trying to get in touch with the testers in question, to get them to set NO_NETWORK_TESTING if they are smoking behind a firewall, but I'm thinking that the real solution here is to use Test::RequiresInternet (which attempts to make a connection to the same host, and skips tests if that fails). Show quoted text
> I've also reworked error propagation in 2.013, so that follow-up > errors like > "configuration failed" don't replace more specific errors like > "hostname verification > failed". This should help in solving the original problem too.
Awesome!