1 | # Copyright 2016-2018 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 | use strict;
|
---|
9 | use POSIX ":sys_wait_h";
|
---|
10 |
|
---|
11 | package TLSProxy::Proxy;
|
---|
12 |
|
---|
13 | use File::Spec;
|
---|
14 | use IO::Socket;
|
---|
15 | use IO::Select;
|
---|
16 | use TLSProxy::Record;
|
---|
17 | use TLSProxy::Message;
|
---|
18 | use TLSProxy::ClientHello;
|
---|
19 | use TLSProxy::ServerHello;
|
---|
20 | use TLSProxy::EncryptedExtensions;
|
---|
21 | use TLSProxy::Certificate;
|
---|
22 | use TLSProxy::CertificateRequest;
|
---|
23 | use TLSProxy::CertificateVerify;
|
---|
24 | use TLSProxy::ServerKeyExchange;
|
---|
25 | use TLSProxy::NewSessionTicket;
|
---|
26 |
|
---|
27 | my $have_IPv6;
|
---|
28 | my $IP_factory;
|
---|
29 |
|
---|
30 | BEGIN
|
---|
31 | {
|
---|
32 | # IO::Socket::IP is on the core module list, IO::Socket::INET6 isn't.
|
---|
33 | # However, IO::Socket::INET6 is older and is said to be more widely
|
---|
34 | # deployed for the moment, and may have less bugs, so we try the latter
|
---|
35 | # first, then fall back on the core modules. Worst case scenario, we
|
---|
36 | # fall back to IO::Socket::INET, only supports IPv4.
|
---|
37 | eval {
|
---|
38 | require IO::Socket::INET6;
|
---|
39 | my $s = IO::Socket::INET6->new(
|
---|
40 | LocalAddr => "::1",
|
---|
41 | LocalPort => 0,
|
---|
42 | Listen=>1,
|
---|
43 | );
|
---|
44 | $s or die "\n";
|
---|
45 | $s->close();
|
---|
46 | };
|
---|
47 | if ($@ eq "") {
|
---|
48 | $IP_factory = sub { IO::Socket::INET6->new(Domain => AF_INET6, @_); };
|
---|
49 | $have_IPv6 = 1;
|
---|
50 | } else {
|
---|
51 | eval {
|
---|
52 | require IO::Socket::IP;
|
---|
53 | my $s = IO::Socket::IP->new(
|
---|
54 | LocalAddr => "::1",
|
---|
55 | LocalPort => 0,
|
---|
56 | Listen=>1,
|
---|
57 | );
|
---|
58 | $s or die "\n";
|
---|
59 | $s->close();
|
---|
60 | };
|
---|
61 | if ($@ eq "") {
|
---|
62 | $IP_factory = sub { IO::Socket::IP->new(@_); };
|
---|
63 | $have_IPv6 = 1;
|
---|
64 | } else {
|
---|
65 | $IP_factory = sub { IO::Socket::INET->new(@_); };
|
---|
66 | $have_IPv6 = 0;
|
---|
67 | }
|
---|
68 | }
|
---|
69 | }
|
---|
70 |
|
---|
71 | my $is_tls13 = 0;
|
---|
72 | my $ciphersuite = undef;
|
---|
73 |
|
---|
74 | sub new
|
---|
75 | {
|
---|
76 | my $class = shift;
|
---|
77 | my ($filter,
|
---|
78 | $execute,
|
---|
79 | $cert,
|
---|
80 | $debug) = @_;
|
---|
81 |
|
---|
82 | my $self = {
|
---|
83 | #Public read/write
|
---|
84 | proxy_addr => $have_IPv6 ? "[::1]" : "127.0.0.1",
|
---|
85 | filter => $filter,
|
---|
86 | serverflags => "",
|
---|
87 | clientflags => "",
|
---|
88 | serverconnects => 1,
|
---|
89 | reneg => 0,
|
---|
90 | sessionfile => undef,
|
---|
91 |
|
---|
92 | #Public read
|
---|
93 | proxy_port => 0,
|
---|
94 | server_port => 0,
|
---|
95 | serverpid => 0,
|
---|
96 | clientpid => 0,
|
---|
97 | execute => $execute,
|
---|
98 | cert => $cert,
|
---|
99 | debug => $debug,
|
---|
100 | cipherc => "",
|
---|
101 | ciphersuitesc => "",
|
---|
102 | ciphers => "AES128-SHA",
|
---|
103 | ciphersuitess => "TLS_AES_128_GCM_SHA256",
|
---|
104 | flight => -1,
|
---|
105 | direction => -1,
|
---|
106 | partial => ["", ""],
|
---|
107 | record_list => [],
|
---|
108 | message_list => [],
|
---|
109 | };
|
---|
110 |
|
---|
111 | # Create the Proxy socket
|
---|
112 | my $proxaddr = $self->{proxy_addr};
|
---|
113 | $proxaddr =~ s/[\[\]]//g; # Remove [ and ]
|
---|
114 | my @proxyargs = (
|
---|
115 | LocalHost => $proxaddr,
|
---|
116 | LocalPort => 0,
|
---|
117 | Proto => "tcp",
|
---|
118 | Listen => SOMAXCONN,
|
---|
119 | );
|
---|
120 |
|
---|
121 | if (my $sock = $IP_factory->(@proxyargs)) {
|
---|
122 | $self->{proxy_sock} = $sock;
|
---|
123 | $self->{proxy_port} = $sock->sockport();
|
---|
124 | $self->{proxy_addr} = $sock->sockhost();
|
---|
125 | $self->{proxy_addr} =~ s/(.*:.*)/[$1]/;
|
---|
126 | print "Proxy started on port ",
|
---|
127 | "$self->{proxy_addr}:$self->{proxy_port}\n";
|
---|
128 | # use same address for s_server
|
---|
129 | $self->{server_addr} = $self->{proxy_addr};
|
---|
130 | } else {
|
---|
131 | warn "Failed creating proxy socket (".$proxaddr.",0): $!\n";
|
---|
132 | }
|
---|
133 |
|
---|
134 | return bless $self, $class;
|
---|
135 | }
|
---|
136 |
|
---|
137 | sub DESTROY
|
---|
138 | {
|
---|
139 | my $self = shift;
|
---|
140 |
|
---|
141 | $self->{proxy_sock}->close() if $self->{proxy_sock};
|
---|
142 | }
|
---|
143 |
|
---|
144 | sub clearClient
|
---|
145 | {
|
---|
146 | my $self = shift;
|
---|
147 |
|
---|
148 | $self->{cipherc} = "";
|
---|
149 | $self->{ciphersuitec} = "";
|
---|
150 | $self->{flight} = -1;
|
---|
151 | $self->{direction} = -1;
|
---|
152 | $self->{partial} = ["", ""];
|
---|
153 | $self->{record_list} = [];
|
---|
154 | $self->{message_list} = [];
|
---|
155 | $self->{clientflags} = "";
|
---|
156 | $self->{sessionfile} = undef;
|
---|
157 | $self->{clientpid} = 0;
|
---|
158 | $is_tls13 = 0;
|
---|
159 | $ciphersuite = undef;
|
---|
160 |
|
---|
161 | TLSProxy::Message->clear();
|
---|
162 | TLSProxy::Record->clear();
|
---|
163 | }
|
---|
164 |
|
---|
165 | sub clear
|
---|
166 | {
|
---|
167 | my $self = shift;
|
---|
168 |
|
---|
169 | $self->clearClient;
|
---|
170 | $self->{ciphers} = "AES128-SHA";
|
---|
171 | $self->{ciphersuitess} = "TLS_AES_128_GCM_SHA256";
|
---|
172 | $self->{serverflags} = "";
|
---|
173 | $self->{serverconnects} = 1;
|
---|
174 | $self->{serverpid} = 0;
|
---|
175 | $self->{reneg} = 0;
|
---|
176 | }
|
---|
177 |
|
---|
178 | sub restart
|
---|
179 | {
|
---|
180 | my $self = shift;
|
---|
181 |
|
---|
182 | $self->clear;
|
---|
183 | $self->start;
|
---|
184 | }
|
---|
185 |
|
---|
186 | sub clientrestart
|
---|
187 | {
|
---|
188 | my $self = shift;
|
---|
189 |
|
---|
190 | $self->clear;
|
---|
191 | $self->clientstart;
|
---|
192 | }
|
---|
193 |
|
---|
194 | sub connect_to_server
|
---|
195 | {
|
---|
196 | my $self = shift;
|
---|
197 | my $servaddr = $self->{server_addr};
|
---|
198 |
|
---|
199 | $servaddr =~ s/[\[\]]//g; # Remove [ and ]
|
---|
200 |
|
---|
201 | my $sock = $IP_factory->(PeerAddr => $servaddr,
|
---|
202 | PeerPort => $self->{server_port},
|
---|
203 | Proto => 'tcp');
|
---|
204 | if (!defined($sock)) {
|
---|
205 | my $err = $!;
|
---|
206 | kill(3, $self->{real_serverpid});
|
---|
207 | die "unable to connect: $err\n";
|
---|
208 | }
|
---|
209 |
|
---|
210 | $self->{server_sock} = $sock;
|
---|
211 | }
|
---|
212 |
|
---|
213 | sub start
|
---|
214 | {
|
---|
215 | my ($self) = shift;
|
---|
216 | my $pid;
|
---|
217 |
|
---|
218 | if ($self->{proxy_sock} == 0) {
|
---|
219 | return 0;
|
---|
220 | }
|
---|
221 |
|
---|
222 | my $execcmd = $self->execute
|
---|
223 | ." s_server -max_protocol TLSv1.3 -no_comp -rev -engine ossltest"
|
---|
224 | #In TLSv1.3 we issue two session tickets. The default session id
|
---|
225 | #callback gets confused because the ossltest engine causes the same
|
---|
226 | #session id to be created twice due to the changed random number
|
---|
227 | #generation. Using "-ext_cache" replaces the default callback with a
|
---|
228 | #different one that doesn't get confused.
|
---|
229 | ." -ext_cache"
|
---|
230 | ." -accept $self->{server_addr}:0"
|
---|
231 | ." -cert ".$self->cert." -cert2 ".$self->cert
|
---|
232 | ." -naccept ".$self->serverconnects;
|
---|
233 | if ($self->ciphers ne "") {
|
---|
234 | $execcmd .= " -cipher ".$self->ciphers;
|
---|
235 | }
|
---|
236 | if ($self->ciphersuitess ne "") {
|
---|
237 | $execcmd .= " -ciphersuites ".$self->ciphersuitess;
|
---|
238 | }
|
---|
239 | if ($self->serverflags ne "") {
|
---|
240 | $execcmd .= " ".$self->serverflags;
|
---|
241 | }
|
---|
242 | if ($self->debug) {
|
---|
243 | print STDERR "Server command: $execcmd\n";
|
---|
244 | }
|
---|
245 |
|
---|
246 | open(my $savedin, "<&STDIN");
|
---|
247 |
|
---|
248 | # Temporarily replace STDIN so that sink process can inherit it...
|
---|
249 | $pid = open(STDIN, "$execcmd 2>&1 |") or die "Failed to $execcmd: $!\n";
|
---|
250 | $self->{real_serverpid} = $pid;
|
---|
251 |
|
---|
252 | # Process the output from s_server until we find the ACCEPT line, which
|
---|
253 | # tells us what the accepting address and port are.
|
---|
254 | while (<>) {
|
---|
255 | print;
|
---|
256 | s/\R$//; # Better chomp
|
---|
257 | next unless (/^ACCEPT\s.*:(\d+)$/);
|
---|
258 | $self->{server_port} = $1;
|
---|
259 | last;
|
---|
260 | }
|
---|
261 |
|
---|
262 | if ($self->{server_port} == 0) {
|
---|
263 | # This actually means that s_server exited, because otherwise
|
---|
264 | # we would still searching for ACCEPT...
|
---|
265 | waitpid($pid, 0);
|
---|
266 | die "no ACCEPT detected in '$execcmd' output: $?\n";
|
---|
267 | }
|
---|
268 |
|
---|
269 | # Just make sure everything else is simply printed [as separate lines].
|
---|
270 | # The sub process simply inherits our STD* and will keep consuming
|
---|
271 | # server's output and printing it as long as there is anything there,
|
---|
272 | # out of our way.
|
---|
273 | my $error;
|
---|
274 | $pid = undef;
|
---|
275 | if (eval { require Win32::Process; 1; }) {
|
---|
276 | if (Win32::Process::Create(my $h, $^X, "perl -ne print", 0, 0, ".")) {
|
---|
277 | $pid = $h->GetProcessID();
|
---|
278 | $self->{proc_handle} = $h; # hold handle till next round [or exit]
|
---|
279 | } else {
|
---|
280 | $error = Win32::FormatMessage(Win32::GetLastError());
|
---|
281 | }
|
---|
282 | } else {
|
---|
283 | if (defined($pid = fork)) {
|
---|
284 | $pid or exec("$^X -ne print") or exit($!);
|
---|
285 | } else {
|
---|
286 | $error = $!;
|
---|
287 | }
|
---|
288 | }
|
---|
289 |
|
---|
290 | # Change back to original stdin
|
---|
291 | open(STDIN, "<&", $savedin);
|
---|
292 | close($savedin);
|
---|
293 |
|
---|
294 | if (!defined($pid)) {
|
---|
295 | kill(3, $self->{real_serverpid});
|
---|
296 | die "Failed to capture s_server's output: $error\n";
|
---|
297 | }
|
---|
298 |
|
---|
299 | $self->{serverpid} = $pid;
|
---|
300 |
|
---|
301 | print STDERR "Server responds on ",
|
---|
302 | "$self->{server_addr}:$self->{server_port}\n";
|
---|
303 |
|
---|
304 | # Connect right away...
|
---|
305 | $self->connect_to_server();
|
---|
306 |
|
---|
307 | return $self->clientstart;
|
---|
308 | }
|
---|
309 |
|
---|
310 | sub clientstart
|
---|
311 | {
|
---|
312 | my ($self) = shift;
|
---|
313 |
|
---|
314 | if ($self->execute) {
|
---|
315 | my $pid;
|
---|
316 | my $execcmd = $self->execute
|
---|
317 | ." s_client -max_protocol TLSv1.3 -engine ossltest"
|
---|
318 | ." -connect $self->{proxy_addr}:$self->{proxy_port}";
|
---|
319 | if ($self->cipherc ne "") {
|
---|
320 | $execcmd .= " -cipher ".$self->cipherc;
|
---|
321 | }
|
---|
322 | if ($self->ciphersuitesc ne "") {
|
---|
323 | $execcmd .= " -ciphersuites ".$self->ciphersuitesc;
|
---|
324 | }
|
---|
325 | if ($self->clientflags ne "") {
|
---|
326 | $execcmd .= " ".$self->clientflags;
|
---|
327 | }
|
---|
328 | if ($self->clientflags !~ m/-(no)?servername/) {
|
---|
329 | $execcmd .= " -servername localhost";
|
---|
330 | }
|
---|
331 | if (defined $self->sessionfile) {
|
---|
332 | $execcmd .= " -ign_eof";
|
---|
333 | }
|
---|
334 | if ($self->debug) {
|
---|
335 | print STDERR "Client command: $execcmd\n";
|
---|
336 | }
|
---|
337 |
|
---|
338 | open(my $savedout, ">&STDOUT");
|
---|
339 | # If we open pipe with new descriptor, attempt to close it,
|
---|
340 | # explicitly or implicitly, would incur waitpid and effectively
|
---|
341 | # dead-lock...
|
---|
342 | if (!($pid = open(STDOUT, "| $execcmd"))) {
|
---|
343 | my $err = $!;
|
---|
344 | kill(3, $self->{real_serverpid});
|
---|
345 | die "Failed to $execcmd: $err\n";
|
---|
346 | }
|
---|
347 | $self->{clientpid} = $pid;
|
---|
348 |
|
---|
349 | # queue [magic] input
|
---|
350 | print $self->reneg ? "R" : "test";
|
---|
351 |
|
---|
352 | # this closes client's stdin without waiting for its pid
|
---|
353 | open(STDOUT, ">&", $savedout);
|
---|
354 | close($savedout);
|
---|
355 | }
|
---|
356 |
|
---|
357 | # Wait for incoming connection from client
|
---|
358 | my $fdset = IO::Select->new($self->{proxy_sock});
|
---|
359 | if (!$fdset->can_read(60)) {
|
---|
360 | kill(3, $self->{real_serverpid});
|
---|
361 | die "s_client didn't try to connect\n";
|
---|
362 | }
|
---|
363 |
|
---|
364 | my $client_sock;
|
---|
365 | if(!($client_sock = $self->{proxy_sock}->accept())) {
|
---|
366 | warn "Failed accepting incoming connection: $!\n";
|
---|
367 | return 0;
|
---|
368 | }
|
---|
369 |
|
---|
370 | print "Connection opened\n";
|
---|
371 |
|
---|
372 | my $server_sock = $self->{server_sock};
|
---|
373 | my $indata;
|
---|
374 |
|
---|
375 | #Wait for either the server socket or the client socket to become readable
|
---|
376 | $fdset = IO::Select->new($server_sock, $client_sock);
|
---|
377 | my @ready;
|
---|
378 | my $ctr = 0;
|
---|
379 | local $SIG{PIPE} = "IGNORE";
|
---|
380 | $self->{saw_session_ticket} = undef;
|
---|
381 | while($fdset->count && $ctr < 10) {
|
---|
382 | if (defined($self->{sessionfile})) {
|
---|
383 | # s_client got -ign_eof and won't be exiting voluntarily, so we
|
---|
384 | # look for data *and* session ticket...
|
---|
385 | last if TLSProxy::Message->success()
|
---|
386 | && $self->{saw_session_ticket};
|
---|
387 | }
|
---|
388 | if (!(@ready = $fdset->can_read(1))) {
|
---|
389 | $ctr++;
|
---|
390 | next;
|
---|
391 | }
|
---|
392 | foreach my $hand (@ready) {
|
---|
393 | if ($hand == $server_sock) {
|
---|
394 | if ($server_sock->sysread($indata, 16384)) {
|
---|
395 | if ($indata = $self->process_packet(1, $indata)) {
|
---|
396 | $client_sock->syswrite($indata) or goto END;
|
---|
397 | }
|
---|
398 | $ctr = 0;
|
---|
399 | } else {
|
---|
400 | $fdset->remove($server_sock);
|
---|
401 | $client_sock->shutdown(SHUT_WR);
|
---|
402 | }
|
---|
403 | } elsif ($hand == $client_sock) {
|
---|
404 | if ($client_sock->sysread($indata, 16384)) {
|
---|
405 | if ($indata = $self->process_packet(0, $indata)) {
|
---|
406 | $server_sock->syswrite($indata) or goto END;
|
---|
407 | }
|
---|
408 | $ctr = 0;
|
---|
409 | } else {
|
---|
410 | $fdset->remove($client_sock);
|
---|
411 | $server_sock->shutdown(SHUT_WR);
|
---|
412 | }
|
---|
413 | } else {
|
---|
414 | kill(3, $self->{real_serverpid});
|
---|
415 | die "Unexpected handle";
|
---|
416 | }
|
---|
417 | }
|
---|
418 | }
|
---|
419 |
|
---|
420 | if ($ctr >= 10) {
|
---|
421 | kill(3, $self->{real_serverpid});
|
---|
422 | die "No progress made";
|
---|
423 | }
|
---|
424 |
|
---|
425 | END:
|
---|
426 | print "Connection closed\n";
|
---|
427 | if($server_sock) {
|
---|
428 | $server_sock->close();
|
---|
429 | $self->{server_sock} = undef;
|
---|
430 | }
|
---|
431 | if($client_sock) {
|
---|
432 | #Closing this also kills the child process
|
---|
433 | $client_sock->close();
|
---|
434 | }
|
---|
435 |
|
---|
436 | my $pid;
|
---|
437 | if (--$self->{serverconnects} == 0) {
|
---|
438 | $pid = $self->{serverpid};
|
---|
439 | print "Waiting for 'perl -ne print' process to close: $pid...\n";
|
---|
440 | $pid = waitpid($pid, 0);
|
---|
441 | if ($pid > 0) {
|
---|
442 | die "exit code $? from 'perl -ne print' process\n" if $? != 0;
|
---|
443 | } elsif ($pid == 0) {
|
---|
444 | kill(3, $self->{real_serverpid});
|
---|
445 | die "lost control over $self->{serverpid}?";
|
---|
446 | }
|
---|
447 | $pid = $self->{real_serverpid};
|
---|
448 | print "Waiting for s_server process to close: $pid...\n";
|
---|
449 | # it's done already, just collect the exit code [and reap]...
|
---|
450 | waitpid($pid, 0);
|
---|
451 | die "exit code $? from s_server process\n" if $? != 0;
|
---|
452 | } else {
|
---|
453 | # It's a bit counter-intuitive spot to make next connection to
|
---|
454 | # the s_server. Rationale is that established connection works
|
---|
455 | # as synchronization point, in sense that this way we know that
|
---|
456 | # s_server is actually done with current session...
|
---|
457 | $self->connect_to_server();
|
---|
458 | }
|
---|
459 | $pid = $self->{clientpid};
|
---|
460 | print "Waiting for s_client process to close: $pid...\n";
|
---|
461 | waitpid($pid, 0);
|
---|
462 |
|
---|
463 | return 1;
|
---|
464 | }
|
---|
465 |
|
---|
466 | sub process_packet
|
---|
467 | {
|
---|
468 | my ($self, $server, $packet) = @_;
|
---|
469 | my $len_real;
|
---|
470 | my $decrypt_len;
|
---|
471 | my $data;
|
---|
472 | my $recnum;
|
---|
473 |
|
---|
474 | if ($server) {
|
---|
475 | print "Received server packet\n";
|
---|
476 | } else {
|
---|
477 | print "Received client packet\n";
|
---|
478 | }
|
---|
479 |
|
---|
480 | if ($self->{direction} != $server) {
|
---|
481 | $self->{flight} = $self->{flight} + 1;
|
---|
482 | $self->{direction} = $server;
|
---|
483 | }
|
---|
484 |
|
---|
485 | print "Packet length = ".length($packet)."\n";
|
---|
486 | print "Processing flight ".$self->flight."\n";
|
---|
487 |
|
---|
488 | #Return contains the list of record found in the packet followed by the
|
---|
489 | #list of messages in those records and any partial message
|
---|
490 | my @ret = TLSProxy::Record->get_records($server, $self->flight,
|
---|
491 | $self->{partial}[$server].$packet);
|
---|
492 | $self->{partial}[$server] = $ret[2];
|
---|
493 | push @{$self->{record_list}}, @{$ret[0]};
|
---|
494 | push @{$self->{message_list}}, @{$ret[1]};
|
---|
495 |
|
---|
496 | print "\n";
|
---|
497 |
|
---|
498 | if (scalar(@{$ret[0]}) == 0 or length($ret[2]) != 0) {
|
---|
499 | return "";
|
---|
500 | }
|
---|
501 |
|
---|
502 | #Finished parsing. Call user provided filter here
|
---|
503 | if (defined $self->filter) {
|
---|
504 | $self->filter->($self);
|
---|
505 | }
|
---|
506 |
|
---|
507 | #Take a note on NewSessionTicket
|
---|
508 | foreach my $message (reverse @{$self->{message_list}}) {
|
---|
509 | if ($message->{mt} == TLSProxy::Message::MT_NEW_SESSION_TICKET) {
|
---|
510 | $self->{saw_session_ticket} = 1;
|
---|
511 | last;
|
---|
512 | }
|
---|
513 | }
|
---|
514 |
|
---|
515 | #Reconstruct the packet
|
---|
516 | $packet = "";
|
---|
517 | foreach my $record (@{$self->record_list}) {
|
---|
518 | $packet .= $record->reconstruct_record($server);
|
---|
519 | }
|
---|
520 |
|
---|
521 | print "Forwarded packet length = ".length($packet)."\n\n";
|
---|
522 |
|
---|
523 | return $packet;
|
---|
524 | }
|
---|
525 |
|
---|
526 | #Read accessors
|
---|
527 | sub execute
|
---|
528 | {
|
---|
529 | my $self = shift;
|
---|
530 | return $self->{execute};
|
---|
531 | }
|
---|
532 | sub cert
|
---|
533 | {
|
---|
534 | my $self = shift;
|
---|
535 | return $self->{cert};
|
---|
536 | }
|
---|
537 | sub debug
|
---|
538 | {
|
---|
539 | my $self = shift;
|
---|
540 | return $self->{debug};
|
---|
541 | }
|
---|
542 | sub flight
|
---|
543 | {
|
---|
544 | my $self = shift;
|
---|
545 | return $self->{flight};
|
---|
546 | }
|
---|
547 | sub record_list
|
---|
548 | {
|
---|
549 | my $self = shift;
|
---|
550 | return $self->{record_list};
|
---|
551 | }
|
---|
552 | sub success
|
---|
553 | {
|
---|
554 | my $self = shift;
|
---|
555 | return $self->{success};
|
---|
556 | }
|
---|
557 | sub end
|
---|
558 | {
|
---|
559 | my $self = shift;
|
---|
560 | return $self->{end};
|
---|
561 | }
|
---|
562 | sub supports_IPv6
|
---|
563 | {
|
---|
564 | my $self = shift;
|
---|
565 | return $have_IPv6;
|
---|
566 | }
|
---|
567 | sub proxy_addr
|
---|
568 | {
|
---|
569 | my $self = shift;
|
---|
570 | return $self->{proxy_addr};
|
---|
571 | }
|
---|
572 | sub proxy_port
|
---|
573 | {
|
---|
574 | my $self = shift;
|
---|
575 | return $self->{proxy_port};
|
---|
576 | }
|
---|
577 | sub server_addr
|
---|
578 | {
|
---|
579 | my $self = shift;
|
---|
580 | return $self->{server_addr};
|
---|
581 | }
|
---|
582 | sub server_port
|
---|
583 | {
|
---|
584 | my $self = shift;
|
---|
585 | return $self->{server_port};
|
---|
586 | }
|
---|
587 | sub serverpid
|
---|
588 | {
|
---|
589 | my $self = shift;
|
---|
590 | return $self->{serverpid};
|
---|
591 | }
|
---|
592 | sub clientpid
|
---|
593 | {
|
---|
594 | my $self = shift;
|
---|
595 | return $self->{clientpid};
|
---|
596 | }
|
---|
597 |
|
---|
598 | #Read/write accessors
|
---|
599 | sub filter
|
---|
600 | {
|
---|
601 | my $self = shift;
|
---|
602 | if (@_) {
|
---|
603 | $self->{filter} = shift;
|
---|
604 | }
|
---|
605 | return $self->{filter};
|
---|
606 | }
|
---|
607 | sub cipherc
|
---|
608 | {
|
---|
609 | my $self = shift;
|
---|
610 | if (@_) {
|
---|
611 | $self->{cipherc} = shift;
|
---|
612 | }
|
---|
613 | return $self->{cipherc};
|
---|
614 | }
|
---|
615 | sub ciphersuitesc
|
---|
616 | {
|
---|
617 | my $self = shift;
|
---|
618 | if (@_) {
|
---|
619 | $self->{ciphersuitesc} = shift;
|
---|
620 | }
|
---|
621 | return $self->{ciphersuitesc};
|
---|
622 | }
|
---|
623 | sub ciphers
|
---|
624 | {
|
---|
625 | my $self = shift;
|
---|
626 | if (@_) {
|
---|
627 | $self->{ciphers} = shift;
|
---|
628 | }
|
---|
629 | return $self->{ciphers};
|
---|
630 | }
|
---|
631 | sub ciphersuitess
|
---|
632 | {
|
---|
633 | my $self = shift;
|
---|
634 | if (@_) {
|
---|
635 | $self->{ciphersuitess} = shift;
|
---|
636 | }
|
---|
637 | return $self->{ciphersuitess};
|
---|
638 | }
|
---|
639 | sub serverflags
|
---|
640 | {
|
---|
641 | my $self = shift;
|
---|
642 | if (@_) {
|
---|
643 | $self->{serverflags} = shift;
|
---|
644 | }
|
---|
645 | return $self->{serverflags};
|
---|
646 | }
|
---|
647 | sub clientflags
|
---|
648 | {
|
---|
649 | my $self = shift;
|
---|
650 | if (@_) {
|
---|
651 | $self->{clientflags} = shift;
|
---|
652 | }
|
---|
653 | return $self->{clientflags};
|
---|
654 | }
|
---|
655 | sub serverconnects
|
---|
656 | {
|
---|
657 | my $self = shift;
|
---|
658 | if (@_) {
|
---|
659 | $self->{serverconnects} = shift;
|
---|
660 | }
|
---|
661 | return $self->{serverconnects};
|
---|
662 | }
|
---|
663 | # This is a bit ugly because the caller is responsible for keeping the records
|
---|
664 | # in sync with the updated message list; simply updating the message list isn't
|
---|
665 | # sufficient to get the proxy to forward the new message.
|
---|
666 | # But it does the trick for the one test (test_sslsessiontick) that needs it.
|
---|
667 | sub message_list
|
---|
668 | {
|
---|
669 | my $self = shift;
|
---|
670 | if (@_) {
|
---|
671 | $self->{message_list} = shift;
|
---|
672 | }
|
---|
673 | return $self->{message_list};
|
---|
674 | }
|
---|
675 |
|
---|
676 | sub fill_known_data
|
---|
677 | {
|
---|
678 | my $length = shift;
|
---|
679 | my $ret = "";
|
---|
680 | for (my $i = 0; $i < $length; $i++) {
|
---|
681 | $ret .= chr($i);
|
---|
682 | }
|
---|
683 | return $ret;
|
---|
684 | }
|
---|
685 |
|
---|
686 | sub is_tls13
|
---|
687 | {
|
---|
688 | my $class = shift;
|
---|
689 | if (@_) {
|
---|
690 | $is_tls13 = shift;
|
---|
691 | }
|
---|
692 | return $is_tls13;
|
---|
693 | }
|
---|
694 |
|
---|
695 | sub reneg
|
---|
696 | {
|
---|
697 | my $self = shift;
|
---|
698 | if (@_) {
|
---|
699 | $self->{reneg} = shift;
|
---|
700 | }
|
---|
701 | return $self->{reneg};
|
---|
702 | }
|
---|
703 |
|
---|
704 | #Setting a sessionfile means that the client will not close until the given
|
---|
705 | #file exists. This is useful in TLSv1.3 where otherwise s_client will close
|
---|
706 | #immediately at the end of the handshake, but before the session has been
|
---|
707 | #received from the server. A side effect of this is that s_client never sends
|
---|
708 | #a close_notify, so instead we consider success to be when it sends application
|
---|
709 | #data over the connection.
|
---|
710 | sub sessionfile
|
---|
711 | {
|
---|
712 | my $self = shift;
|
---|
713 | if (@_) {
|
---|
714 | $self->{sessionfile} = shift;
|
---|
715 | TLSProxy::Message->successondata(1);
|
---|
716 | }
|
---|
717 | return $self->{sessionfile};
|
---|
718 | }
|
---|
719 |
|
---|
720 | sub ciphersuite
|
---|
721 | {
|
---|
722 | my $class = shift;
|
---|
723 | if (@_) {
|
---|
724 | $ciphersuite = shift;
|
---|
725 | }
|
---|
726 | return $ciphersuite;
|
---|
727 | }
|
---|
728 |
|
---|
729 | 1;
|
---|