From 72b65aa4cb7fd9a41935a2e057e44cb40fb4faa2 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Wed, 3 Feb 2016 00:57:30 +0100 Subject: [PATCH] Refactoring BIO: add a simple networking test of s_client and s_server This makes use of TLSProxy, which was expanded to use IO::Socket::IP (which is a core perl module) or IO::Socket::INET6 (which is said to be more popular) instead IO::Socket::INET if one of them is installed. Reviewed-by: Viktor Dukhovni --- test/recipes/90-test_networking.t | 108 ++++++++++++++++++++++++++++++ util/TLSProxy/Proxy.pm | 72 +++++++++++++++++--- 2 files changed, 169 insertions(+), 11 deletions(-) create mode 100644 test/recipes/90-test_networking.t diff --git a/test/recipes/90-test_networking.t b/test/recipes/90-test_networking.t new file mode 100644 index 0000000000..f8377c93e0 --- /dev/null +++ b/test/recipes/90-test_networking.t @@ -0,0 +1,108 @@ +#!/usr/bin/perl +# Written by Richard Levitte for the OpenSSL project. +# ==================================================================== +# Copyright (c) 2015-2016 The OpenSSL Project. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# 3. All advertising materials mentioning features or use of this +# software must display the following acknowledgment: +# "This product includes software developed by the OpenSSL Project +# for use in the OpenSSL Toolkit. (http://www.openssl.org/)" +# +# 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to +# endorse or promote products derived from this software without +# prior written permission. For written permission, please contact +# openssl-core@openssl.org. +# +# 5. Products derived from this software may not be called "OpenSSL" +# nor may "OpenSSL" appear in their names without prior written +# permission of the OpenSSL Project. +# +# 6. Redistributions of any form whatsoever must retain the following +# acknowledgment: +# "This product includes software developed by the OpenSSL Project +# for use in the OpenSSL Toolkit (http://www.openssl.org/)" +# +# THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY +# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR +# ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. +# ==================================================================== +# +# This product includes cryptographic software written by Eric Young +# (eay@cryptsoft.com). This product includes software written by Tim +# Hudson (tjh@cryptsoft.com). + +use strict; +use OpenSSL::Test qw/:DEFAULT cmdstr top_file top_dir/; +use TLSProxy::Proxy; + +my $test_name = "test_networking"; +setup($test_name); + +plan skip_all => "$test_name can only be performed with OpenSSL configured shared" + unless (map { s/\R//; s/^SHARED_LIBS=\s*//; $_ } + grep { /^SHARED_LIBS=/ } + do { local @ARGV = ( top_file("Makefile") ); <> })[0] ne ""; + +$ENV{OPENSSL_ENGINES} = top_dir("engines"); +$ENV{OPENSSL_ia32cap} = '~0x200000200000000'; + +my $proxy = TLSProxy::Proxy->new( + undef, + cmdstr(app(["openssl"])), + top_file("apps", "server.pem") +); + +plan tests => 2; + +#Test 1: Try IPv4 +$proxy->clear(); +$proxy->serverflags("-4"); +$proxy->clientflags("-4"); +$proxy->server_addr("127.0.0.1"); +$proxy->proxy_addr("127.0.0.1"); +ok(check_connection(), "Trying IPv4"); + + SKIP: { + skip "No IPv6 support", 1 unless $proxy->supports_IPv6(); + + #Test 2: Try IPv6 + $proxy->clear(); + $proxy->serverflags("-6"); + $proxy->clientflags("-6"); + $proxy->server_addr("[::1]"); + $proxy->proxy_addr("[::1]"); + ok(check_connection(), "Trying IPv6"); +} + +sub check_connection +{ + eval { $proxy->start(); }; + + if ($@ ne "") { + print STDERR "Proxy connection failed: $@\n"; + return 0; + } + + 1; +} diff --git a/util/TLSProxy/Proxy.pm b/util/TLSProxy/Proxy.pm index 8d18dcc7c1..7082486561 100644 --- a/util/TLSProxy/Proxy.pm +++ b/util/TLSProxy/Proxy.pm @@ -65,6 +65,9 @@ use TLSProxy::ServerHello; use TLSProxy::ServerKeyExchange; use TLSProxy::NewSessionTicket; +my $have_IPv6 = 0; +my $IP_factory; + sub new { my $class = shift; @@ -95,6 +98,44 @@ sub new message_list => [], }; + eval { + require IO::Socket::IP; + my $s = IO::Socket::IP->new( + LocalAddr => "::1", + LocalPort => 0, + Listen=>1, + ); + $s or die "\n"; + $s->close(); + }; + if ($@ eq "") { + # IO::Socket::IP supports IPv6 and is in the core modules list + $IP_factory = sub { IO::Socket::IP->new(@_); }; + $have_IPv6 = 1; + } else { + eval { + require IO::Socket::INET6; + my $s = IO::Socket::INET6->new( + LocalAddr => "::1", + LocalPort => 0, + Listen=>1, + ); + $s or die "\n"; + $s->close(); + }; + if ($@ eq "") { + # IO::Socket::INET6 supports IPv6 but isn't on the core modules list + # However, it's a bit older and said to be more widely deployed + # at the time of writing this comment. + $IP_factory = sub { IO::Socket::INET6->new(@_); }; + $have_IPv6 = 1; + } else { + # IO::Socket::INET doesn't support IPv6 but is a fallback in case + # we have no other. + $IP_factory = sub { IO::Socket::INET->new(@_); }; + } + } + return bless $self, $class; } @@ -139,7 +180,7 @@ sub start $pid = fork(); if ($pid == 0) { open(STDOUT, ">", File::Spec->devnull()) - or die "Failed to redirect stdout"; + or die "Failed to redirect stdout: $!"; open(STDERR, ">&STDOUT"); my $execcmd = $self->execute ." s_server -rev -engine ossltest -accept " @@ -168,8 +209,10 @@ sub clientstart } # Create the Proxy socket - my $proxy_sock = new IO::Socket::INET( - LocalHost => $self->proxy_addr, + my $proxaddr = $self->server_addr; + $proxaddr =~ s/[\[\]]//g; # Remove [ and ] + my $proxy_sock = $IP_factory->( + LocalHost => $proxaddr, LocalPort => $self->proxy_port, Proto => "tcp", Listen => SOMAXCONN, @@ -179,14 +222,14 @@ sub clientstart if ($proxy_sock) { print "Proxy started on port ".$self->proxy_port."\n"; } else { - die "Failed creating proxy socket\n"; + die "Failed creating proxy socket (".$proxaddr.",".$self->proxy_port."): $!\n"; } if ($self->execute) { my $pid = fork(); if ($pid == 0) { open(STDOUT, ">", File::Spec->devnull()) - or die "Failed to redirect stdout"; + or die "Failed to redirect stdout: $!"; open(STDERR, ">&STDOUT"); my $execcmd = "echo test | ".$self->execute ." s_client -engine ossltest -connect " @@ -202,8 +245,8 @@ sub clientstart } # Wait for incoming connection from client - my $client_sock = $proxy_sock->accept() - or die "Failed accepting incoming connection\n"; + my $client_sock = $proxy_sock->accept() + or die "Failed accepting incoming connection: $!\n"; print "Connection opened\n"; @@ -213,11 +256,13 @@ sub clientstart #We loop over this a few times because sometimes s_server can take a while #to start up do { - $server_sock = new IO::Socket::INET( - PeerAddr => $self->server_addr, + my $servaddr = $self->server_addr; + $servaddr =~ s/[\[\]]//g; # Remove [ and ] + $server_sock = $IP_factory->( + PeerAddr => $servaddr, PeerPort => $self->server_port, Proto => 'tcp' - ); + ); $retry--; if (!$server_sock) { @@ -225,7 +270,7 @@ sub clientstart #Sleep for a short while select(undef, undef, undef, 0.1); } else { - die "Failed to start up server\n"; + die "Failed to start up server (".$servaddr.",".$self->server_port."): $!\n"; } } } while (!$server_sock); @@ -353,6 +398,11 @@ sub end my $self = shift; return $self->{end}; } +sub supports_IPv6 +{ + my $self = shift; + return $have_IPv6; +} #Read/write accessors sub proxy_addr -- GitLab