xref: /freebsd/crypto/openssl/util/perl/OpenSSL/Test/Utils.pm (revision a7148ab39c03abd4d1a84997c70bf96f15dd2a09)
1 # Copyright 2016-2024 The OpenSSL Project Authors. All Rights Reserved.
2 #
3 # Licensed under the Apache License 2.0 (the "License").  You may not use
4 # this file except in compliance with the License.  You can obtain a copy
5 # in the file LICENSE in the source distribution or at
6 # https://www.openssl.org/source/license.html
7 
8 package OpenSSL::Test::Utils;
9 
10 use strict;
11 use warnings;
12 
13 use Exporter;
14 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
15 $VERSION = "0.1";
16 @ISA = qw(Exporter);
17 @EXPORT = qw(alldisabled anydisabled disabled config available_protocols
18              have_IPv4 have_IPv6);
19 
20 =head1 NAME
21 
22 OpenSSL::Test::Utils - test utility functions
23 
24 =head1 SYNOPSIS
25 
26   use OpenSSL::Test::Utils;
27 
28   my @tls = available_protocols("tls");
29   my @dtls = available_protocols("dtls");
30   alldisabled("dh", "dsa");
31   anydisabled("dh", "dsa");
32 
33   config("fips");
34 
35   have_IPv4();
36   have_IPv6();
37 
38 =head1 DESCRIPTION
39 
40 This module provides utility functions for the testing framework.
41 
42 =cut
43 
44 use OpenSSL::Test qw/:DEFAULT bldtop_file/;
45 
46 =over 4
47 
48 =item B<available_protocols STRING>
49 
50 Returns a list of strings for all the available SSL/TLS versions if
51 STRING is "tls", or for all the available DTLS versions if STRING is
52 "dtls".  Otherwise, it returns the empty list.  The strings in the
53 returned list can be used with B<alldisabled> and B<anydisabled>.
54 
55 =item B<alldisabled ARRAY>
56 
57 =item B<anydisabled ARRAY>
58 
59 In an array context returns an array with each element set to 1 if the
60 corresponding feature is disabled and 0 otherwise.
61 
62 In a scalar context, alldisabled returns 1 if all of the features in
63 ARRAY are disabled, while anydisabled returns 1 if any of them are
64 disabled.
65 
66 =item B<config STRING>
67 
68 Returns an item from the %config hash in \$TOP/configdata.pm.
69 
70 =item B<have_IPv4>
71 
72 =item B<have_IPv6>
73 
74 Return true if IPv4 / IPv6 is possible to use on the current system.
75 Additionally, B<have_IPv6> also checks how OpenSSL was configured,
76 i.e. if IPv6 was explicitly disabled with -DOPENSSL_USE_IPv6=0.
77 
78 =back
79 
80 =cut
81 
82 our %available_protocols;
83 our %disabled;
84 our %config;
85 our %target;
86 my $configdata_loaded = 0;
87 
88 sub load_configdata {
89     # We eval it so it doesn't run at compile time of this file.
90     # The latter would have bldtop_file() complain that setup() hasn't
91     # been run yet.
92     my $configdata = bldtop_file("configdata.pm");
93     eval { require $configdata;
94 	   %available_protocols = %configdata::available_protocols;
95 	   %disabled = %configdata::disabled;
96 	   %config = %configdata::config;
97 	   %target = %configdata::target;
98     };
99     $configdata_loaded = 1;
100 }
101 
102 # args
103 #  list of 1s and 0s, coming from check_disabled()
104 sub anyof {
105     my $x = 0;
106     foreach (@_) { $x += $_ }
107     return $x > 0;
108 }
109 
110 # args
111 #  list of 1s and 0s, coming from check_disabled()
112 sub allof {
113     my $x = 1;
114     foreach (@_) { $x *= $_ }
115     return $x > 0;
116 }
117 
118 # args
119 #  list of strings, all of them should be names of features
120 #  that can be disabled.
121 # returns a list of 1s (if the corresponding feature is disabled)
122 #  and 0s (if it isn't)
123 sub check_disabled {
124     return map { exists $disabled{lc $_} ? 1 : 0 } @_;
125 }
126 
127 # Exported functions #################################################
128 
129 # args:
130 #  list of features to check
131 sub anydisabled {
132     load_configdata() unless $configdata_loaded;
133     my @ret = check_disabled(@_);
134     return @ret if wantarray;
135     return anyof(@ret);
136 }
137 
138 # args:
139 #  list of features to check
140 sub alldisabled {
141     load_configdata() unless $configdata_loaded;
142     my @ret = check_disabled(@_);
143     return @ret if wantarray;
144     return allof(@ret);
145 }
146 
147 # !!! Kept for backward compatibility
148 # args:
149 #  single string
150 sub disabled {
151     anydisabled(@_);
152 }
153 
154 sub available_protocols {
155     load_configdata() unless $configdata_loaded;
156     my $protocol_class = shift;
157     if (exists $available_protocols{lc $protocol_class}) {
158 	return @{$available_protocols{lc $protocol_class}}
159     }
160     return ();
161 }
162 
163 sub config {
164     load_configdata() unless $configdata_loaded;
165     return $config{$_[0]};
166 }
167 
168 # IPv4 / IPv6 checker
169 my $have_IPv4 = -1;
170 my $have_IPv6 = -1;
171 my $IP_factory;
172 sub check_IP {
173     my $listenaddress = shift;
174 
175     eval {
176         require IO::Socket::IP;
177         my $s = IO::Socket::IP->new(
178             LocalAddr => $listenaddress,
179             LocalPort => 0,
180             Listen=>1,
181             );
182         $s or die "\n";
183         $s->close();
184     };
185     if ($@ eq "") {
186         return 1;
187     }
188 
189     eval {
190         require IO::Socket::INET6;
191         my $s = IO::Socket::INET6->new(
192             LocalAddr => $listenaddress,
193             LocalPort => 0,
194             Listen=>1,
195             );
196         $s or die "\n";
197         $s->close();
198     };
199     if ($@ eq "") {
200         return 1;
201     }
202 
203     eval {
204         require IO::Socket::INET;
205         my $s = IO::Socket::INET->new(
206             LocalAddr => $listenaddress,
207             LocalPort => 0,
208             Listen=>1,
209             );
210         $s or die "\n";
211         $s->close();
212     };
213     if ($@ eq "") {
214         return 1;
215     }
216 
217     return 0;
218 }
219 
220 sub have_IPv4 {
221     if ($have_IPv4 < 0) {
222         $have_IPv4 = check_IP("127.0.0.1");
223     }
224     return $have_IPv4;
225 }
226 
227 sub have_IPv6 {
228     if ($have_IPv6 < 0) {
229         load_configdata() unless $configdata_loaded;
230         # If OpenSSL is configured with IPv6 explicitly disabled, no IPv6
231         # related tests should be performed.  In other words, pretend IPv6
232         # isn't present.
233         $have_IPv6 = 0
234             if grep { $_ eq 'OPENSSL_USE_IPV6=0' } @{$config{CPPDEFINES}};
235         # Similarly, if a config target has explicitly disabled IPv6, no
236         # IPv6 related tests should be performed.
237         $have_IPv6 = 0
238             if grep { $_ eq 'OPENSSL_USE_IPV6=0' } @{$target{defines}};
239     }
240     if ($have_IPv6 < 0) {
241         $have_IPv6 = check_IP("::1");
242     }
243     return $have_IPv6;
244 }
245 
246 =head1 SEE ALSO
247 
248 L<OpenSSL::Test>
249 
250 =head1 AUTHORS
251 
252 Stephen Henson E<lt>steve@openssl.orgE<gt> and
253 Richard Levitte E<lt>levitte@openssl.orgE<gt>
254 
255 =cut
256 
257 1;
258