xref: /netbsd-src/crypto/external/bsd/openssl/dist/util/perl/TLSProxy/Proxy.pm (revision 97e3c58506797315d86c0608cba9d3f55de0c735)
1*97e3c585Schristos# Copyright 2016-2024 The OpenSSL Project Authors. All Rights Reserved.
253060421Schristos#
3b0d17251Schristos# Licensed under the Apache License 2.0 (the "License").  You may not use
453060421Schristos# this file except in compliance with the License.  You can obtain a copy
553060421Schristos# in the file LICENSE in the source distribution or at
653060421Schristos# https://www.openssl.org/source/license.html
753060421Schristos
853060421Schristosuse strict;
953060421Schristosuse POSIX ":sys_wait_h";
1053060421Schristos
1153060421Schristospackage TLSProxy::Proxy;
1253060421Schristos
1353060421Schristosuse File::Spec;
1453060421Schristosuse IO::Socket;
1553060421Schristosuse IO::Select;
1653060421Schristosuse TLSProxy::Record;
1753060421Schristosuse TLSProxy::Message;
1853060421Schristosuse TLSProxy::ClientHello;
1953060421Schristosuse TLSProxy::ServerHello;
2013d40330Schristosuse TLSProxy::EncryptedExtensions;
2113d40330Schristosuse TLSProxy::Certificate;
224ce06407Schristosuse TLSProxy::CertificateRequest;
2313d40330Schristosuse TLSProxy::CertificateVerify;
2453060421Schristosuse TLSProxy::ServerKeyExchange;
2553060421Schristosuse TLSProxy::NewSessionTicket;
26*97e3c585Schristosuse TLSProxy::NextProto;
2753060421Schristos
2813d40330Schristosmy $have_IPv6;
2953060421Schristosmy $IP_factory;
3053060421Schristos
3113d40330SchristosBEGIN
3253060421Schristos{
3353060421Schristos    # IO::Socket::IP is on the core module list, IO::Socket::INET6 isn't.
3453060421Schristos    # However, IO::Socket::INET6 is older and is said to be more widely
3553060421Schristos    # deployed for the moment, and may have less bugs, so we try the latter
3613d40330Schristos    # first, then fall back on the core modules.  Worst case scenario, we
3753060421Schristos    # fall back to IO::Socket::INET, only supports IPv4.
3853060421Schristos    eval {
3953060421Schristos        require IO::Socket::INET6;
4053060421Schristos        my $s = IO::Socket::INET6->new(
4153060421Schristos            LocalAddr => "::1",
4253060421Schristos            LocalPort => 0,
4353060421Schristos            Listen=>1,
4453060421Schristos            );
4553060421Schristos        $s or die "\n";
4653060421Schristos        $s->close();
4753060421Schristos    };
4853060421Schristos    if ($@ eq "") {
49b88c74d5Schristos        $IP_factory = sub { IO::Socket::INET6->new(Domain => AF_INET6, @_); };
5053060421Schristos        $have_IPv6 = 1;
5153060421Schristos    } else {
5253060421Schristos        eval {
5353060421Schristos            require IO::Socket::IP;
5453060421Schristos            my $s = IO::Socket::IP->new(
5553060421Schristos                LocalAddr => "::1",
5653060421Schristos                LocalPort => 0,
5753060421Schristos                Listen=>1,
5853060421Schristos                );
5953060421Schristos            $s or die "\n";
6053060421Schristos            $s->close();
6153060421Schristos        };
6253060421Schristos        if ($@ eq "") {
6353060421Schristos            $IP_factory = sub { IO::Socket::IP->new(@_); };
6453060421Schristos            $have_IPv6 = 1;
6553060421Schristos        } else {
6653060421Schristos            $IP_factory = sub { IO::Socket::INET->new(@_); };
6713d40330Schristos            $have_IPv6 = 0;
6853060421Schristos        }
6953060421Schristos    }
7013d40330Schristos}
7113d40330Schristos
7213d40330Schristosmy $is_tls13 = 0;
7313d40330Schristosmy $ciphersuite = undef;
7413d40330Schristos
7513d40330Schristossub new
7613d40330Schristos{
7713d40330Schristos    my $class = shift;
7813d40330Schristos    my ($filter,
7913d40330Schristos        $execute,
8013d40330Schristos        $cert,
8113d40330Schristos        $debug) = @_;
8213d40330Schristos
8313d40330Schristos    my $self = {
8413d40330Schristos        #Public read/write
8513d40330Schristos        proxy_addr => $have_IPv6 ? "[::1]" : "127.0.0.1",
8613d40330Schristos        filter => $filter,
8713d40330Schristos        serverflags => "",
8813d40330Schristos        clientflags => "",
8913d40330Schristos        serverconnects => 1,
9013d40330Schristos        reneg => 0,
9113d40330Schristos        sessionfile => undef,
9213d40330Schristos
9313d40330Schristos        #Public read
9413d40330Schristos        proxy_port => 0,
9513d40330Schristos        server_port => 0,
9613d40330Schristos        serverpid => 0,
9713d40330Schristos        clientpid => 0,
9813d40330Schristos        execute => $execute,
9913d40330Schristos        cert => $cert,
10013d40330Schristos        debug => $debug,
10113d40330Schristos        cipherc => "",
10213d40330Schristos        ciphersuitesc => "",
10313d40330Schristos        ciphers => "AES128-SHA",
10413d40330Schristos        ciphersuitess => "TLS_AES_128_GCM_SHA256",
10513d40330Schristos        flight => -1,
10613d40330Schristos        direction => -1,
10713d40330Schristos        partial => ["", ""],
10813d40330Schristos        record_list => [],
10913d40330Schristos        message_list => [],
11013d40330Schristos    };
11153060421Schristos
11253060421Schristos    # Create the Proxy socket
11353060421Schristos    my $proxaddr = $self->{proxy_addr};
11453060421Schristos    $proxaddr =~ s/[\[\]]//g; # Remove [ and ]
11553060421Schristos    my @proxyargs = (
11653060421Schristos        LocalHost   => $proxaddr,
11713d40330Schristos        LocalPort   => 0,
11853060421Schristos        Proto       => "tcp",
11953060421Schristos        Listen      => SOMAXCONN,
12053060421Schristos       );
12153060421Schristos
12213d40330Schristos    if (my $sock = $IP_factory->(@proxyargs)) {
12313d40330Schristos        $self->{proxy_sock} = $sock;
12413d40330Schristos        $self->{proxy_port} = $sock->sockport();
12513d40330Schristos        $self->{proxy_addr} = $sock->sockhost();
12613d40330Schristos        $self->{proxy_addr} =~ s/(.*:.*)/[$1]/;
12713d40330Schristos        print "Proxy started on port ",
12813d40330Schristos              "$self->{proxy_addr}:$self->{proxy_port}\n";
12913d40330Schristos        # use same address for s_server
13013d40330Schristos        $self->{server_addr} = $self->{proxy_addr};
13153060421Schristos    } else {
13213d40330Schristos        warn "Failed creating proxy socket (".$proxaddr.",0): $!\n";
13353060421Schristos    }
13453060421Schristos
13553060421Schristos    return bless $self, $class;
13653060421Schristos}
13753060421Schristos
13853060421Schristossub DESTROY
13953060421Schristos{
14053060421Schristos    my $self = shift;
14153060421Schristos
14253060421Schristos    $self->{proxy_sock}->close() if $self->{proxy_sock};
14353060421Schristos}
14453060421Schristos
14553060421Schristossub clearClient
14653060421Schristos{
14753060421Schristos    my $self = shift;
14853060421Schristos
14953060421Schristos    $self->{cipherc} = "";
15013d40330Schristos    $self->{ciphersuitec} = "";
15153060421Schristos    $self->{flight} = -1;
15253060421Schristos    $self->{direction} = -1;
15353060421Schristos    $self->{partial} = ["", ""];
15453060421Schristos    $self->{record_list} = [];
15553060421Schristos    $self->{message_list} = [];
15653060421Schristos    $self->{clientflags} = "";
15713d40330Schristos    $self->{sessionfile} = undef;
15853060421Schristos    $self->{clientpid} = 0;
15913d40330Schristos    $is_tls13 = 0;
16013d40330Schristos    $ciphersuite = undef;
16153060421Schristos
16253060421Schristos    TLSProxy::Message->clear();
16353060421Schristos    TLSProxy::Record->clear();
16453060421Schristos}
16553060421Schristos
16653060421Schristossub clear
16753060421Schristos{
16853060421Schristos    my $self = shift;
16953060421Schristos
17053060421Schristos    $self->clearClient;
17153060421Schristos    $self->{ciphers} = "AES128-SHA";
17213d40330Schristos    $self->{ciphersuitess} = "TLS_AES_128_GCM_SHA256";
17353060421Schristos    $self->{serverflags} = "";
17453060421Schristos    $self->{serverconnects} = 1;
17553060421Schristos    $self->{serverpid} = 0;
17653060421Schristos    $self->{reneg} = 0;
17753060421Schristos}
17853060421Schristos
17953060421Schristossub restart
18053060421Schristos{
18153060421Schristos    my $self = shift;
18253060421Schristos
18353060421Schristos    $self->clear;
18453060421Schristos    $self->start;
18553060421Schristos}
18653060421Schristos
18753060421Schristossub clientrestart
18853060421Schristos{
18953060421Schristos    my $self = shift;
19053060421Schristos
19153060421Schristos    $self->clear;
19253060421Schristos    $self->clientstart;
19353060421Schristos}
19453060421Schristos
19513d40330Schristossub connect_to_server
19613d40330Schristos{
19713d40330Schristos    my $self = shift;
19813d40330Schristos    my $servaddr = $self->{server_addr};
19913d40330Schristos
20013d40330Schristos    $servaddr =~ s/[\[\]]//g; # Remove [ and ]
20113d40330Schristos
20213d40330Schristos    my $sock = $IP_factory->(PeerAddr => $servaddr,
20313d40330Schristos                             PeerPort => $self->{server_port},
20413d40330Schristos                             Proto => 'tcp');
20513d40330Schristos    if (!defined($sock)) {
20613d40330Schristos        my $err = $!;
20713d40330Schristos        kill(3, $self->{real_serverpid});
20813d40330Schristos        die "unable to connect: $err\n";
20913d40330Schristos    }
21013d40330Schristos
21113d40330Schristos    $self->{server_sock} = $sock;
21213d40330Schristos}
21313d40330Schristos
21453060421Schristossub start
21553060421Schristos{
21653060421Schristos    my ($self) = shift;
21753060421Schristos    my $pid;
21853060421Schristos
21953060421Schristos    if ($self->{proxy_sock} == 0) {
22053060421Schristos        return 0;
22153060421Schristos    }
22253060421Schristos
22353060421Schristos    my $execcmd = $self->execute
22413d40330Schristos        ." s_server -max_protocol TLSv1.3 -no_comp -rev -engine ossltest"
22513d40330Schristos        #In TLSv1.3 we issue two session tickets. The default session id
22613d40330Schristos        #callback gets confused because the ossltest engine causes the same
22713d40330Schristos        #session id to be created twice due to the changed random number
22813d40330Schristos        #generation. Using "-ext_cache" replaces the default callback with a
22913d40330Schristos        #different one that doesn't get confused.
23013d40330Schristos        ." -ext_cache"
23113d40330Schristos        ." -accept $self->{server_addr}:0"
23213d40330Schristos        ." -cert ".$self->cert." -cert2 ".$self->cert
23313d40330Schristos        ." -naccept ".$self->serverconnects;
23453060421Schristos    if ($self->ciphers ne "") {
23553060421Schristos        $execcmd .= " -cipher ".$self->ciphers;
23653060421Schristos    }
23713d40330Schristos    if ($self->ciphersuitess ne "") {
23813d40330Schristos        $execcmd .= " -ciphersuites ".$self->ciphersuitess;
23913d40330Schristos    }
24053060421Schristos    if ($self->serverflags ne "") {
24153060421Schristos        $execcmd .= " ".$self->serverflags;
24253060421Schristos    }
24353060421Schristos    if ($self->debug) {
24453060421Schristos        print STDERR "Server command: $execcmd\n";
24553060421Schristos    }
24613d40330Schristos
24713d40330Schristos    open(my $savedin, "<&STDIN");
24813d40330Schristos
24913d40330Schristos    # Temporarily replace STDIN so that sink process can inherit it...
25013d40330Schristos    $pid = open(STDIN, "$execcmd 2>&1 |") or die "Failed to $execcmd: $!\n";
25113d40330Schristos    $self->{real_serverpid} = $pid;
25213d40330Schristos
25313d40330Schristos    # Process the output from s_server until we find the ACCEPT line, which
25413d40330Schristos    # tells us what the accepting address and port are.
25513d40330Schristos    while (<>) {
25613d40330Schristos        print;
25713d40330Schristos        s/\R$//;                # Better chomp
25813d40330Schristos        next unless (/^ACCEPT\s.*:(\d+)$/);
25913d40330Schristos        $self->{server_port} = $1;
26013d40330Schristos        last;
26153060421Schristos    }
26213d40330Schristos
26313d40330Schristos    if ($self->{server_port} == 0) {
26413d40330Schristos        # This actually means that s_server exited, because otherwise
26513d40330Schristos        # we would still searching for ACCEPT...
26613d40330Schristos        waitpid($pid, 0);
26713d40330Schristos        die "no ACCEPT detected in '$execcmd' output: $?\n";
26813d40330Schristos    }
26913d40330Schristos
27013d40330Schristos    # Just make sure everything else is simply printed [as separate lines].
27113d40330Schristos    # The sub process simply inherits our STD* and will keep consuming
27213d40330Schristos    # server's output and printing it as long as there is anything there,
27313d40330Schristos    # out of our way.
27413d40330Schristos    my $error;
27513d40330Schristos    $pid = undef;
27613d40330Schristos    if (eval { require Win32::Process; 1; }) {
27713d40330Schristos        if (Win32::Process::Create(my $h, $^X, "perl -ne print", 0, 0, ".")) {
27813d40330Schristos            $pid = $h->GetProcessID();
27913d40330Schristos            $self->{proc_handle} = $h;  # hold handle till next round [or exit]
28013d40330Schristos        } else {
28113d40330Schristos            $error = Win32::FormatMessage(Win32::GetLastError());
28213d40330Schristos        }
28313d40330Schristos    } else {
28413d40330Schristos        if (defined($pid = fork)) {
28513d40330Schristos            $pid or exec("$^X -ne print") or exit($!);
28613d40330Schristos        } else {
28713d40330Schristos            $error = $!;
28813d40330Schristos        }
28913d40330Schristos    }
29013d40330Schristos
29113d40330Schristos    # Change back to original stdin
29213d40330Schristos    open(STDIN, "<&", $savedin);
29313d40330Schristos    close($savedin);
29413d40330Schristos
29513d40330Schristos    if (!defined($pid)) {
29613d40330Schristos        kill(3, $self->{real_serverpid});
29713d40330Schristos        die "Failed to capture s_server's output: $error\n";
29813d40330Schristos    }
29913d40330Schristos
30013d40330Schristos    $self->{serverpid} = $pid;
30113d40330Schristos
30213d40330Schristos    print STDERR "Server responds on ",
30313d40330Schristos                 "$self->{server_addr}:$self->{server_port}\n";
30413d40330Schristos
30513d40330Schristos    # Connect right away...
30613d40330Schristos    $self->connect_to_server();
30753060421Schristos
30853060421Schristos    return $self->clientstart;
30953060421Schristos}
31053060421Schristos
31153060421Schristossub clientstart
31253060421Schristos{
31353060421Schristos    my ($self) = shift;
31453060421Schristos
31553060421Schristos    if ($self->execute) {
31613d40330Schristos        my $pid;
31713d40330Schristos        my $execcmd = $self->execute
31813d40330Schristos             ." s_client -max_protocol TLSv1.3 -engine ossltest"
31913d40330Schristos             ." -connect $self->{proxy_addr}:$self->{proxy_port}";
32053060421Schristos        if ($self->cipherc ne "") {
32153060421Schristos            $execcmd .= " -cipher ".$self->cipherc;
32253060421Schristos        }
32313d40330Schristos        if ($self->ciphersuitesc ne "") {
32413d40330Schristos            $execcmd .= " -ciphersuites ".$self->ciphersuitesc;
32513d40330Schristos        }
32653060421Schristos        if ($self->clientflags ne "") {
32753060421Schristos            $execcmd .= " ".$self->clientflags;
32853060421Schristos        }
32913d40330Schristos        if ($self->clientflags !~ m/-(no)?servername/) {
33013d40330Schristos            $execcmd .= " -servername localhost";
33113d40330Schristos        }
33213d40330Schristos        if (defined $self->sessionfile) {
33313d40330Schristos            $execcmd .= " -ign_eof";
33413d40330Schristos        }
33553060421Schristos        if ($self->debug) {
33653060421Schristos            print STDERR "Client command: $execcmd\n";
33753060421Schristos        }
33813d40330Schristos
33913d40330Schristos        open(my $savedout, ">&STDOUT");
34013d40330Schristos        # If we open pipe with new descriptor, attempt to close it,
34113d40330Schristos        # explicitly or implicitly, would incur waitpid and effectively
34213d40330Schristos        # dead-lock...
34313d40330Schristos        if (!($pid = open(STDOUT, "| $execcmd"))) {
34413d40330Schristos            my $err = $!;
34513d40330Schristos            kill(3, $self->{real_serverpid});
34613d40330Schristos            die "Failed to $execcmd: $err\n";
34753060421Schristos        }
34813d40330Schristos        $self->{clientpid} = $pid;
34913d40330Schristos
35013d40330Schristos        # queue [magic] input
35113d40330Schristos        print $self->reneg ? "R" : "test";
35213d40330Schristos
35313d40330Schristos        # this closes client's stdin without waiting for its pid
35413d40330Schristos        open(STDOUT, ">&", $savedout);
35513d40330Schristos        close($savedout);
35653060421Schristos    }
35753060421Schristos
35853060421Schristos    # Wait for incoming connection from client
35913d40330Schristos    my $fdset = IO::Select->new($self->{proxy_sock});
36013d40330Schristos    if (!$fdset->can_read(60)) {
36113d40330Schristos        kill(3, $self->{real_serverpid});
36213d40330Schristos        die "s_client didn't try to connect\n";
36313d40330Schristos    }
36413d40330Schristos
36553060421Schristos    my $client_sock;
36653060421Schristos    if(!($client_sock = $self->{proxy_sock}->accept())) {
36753060421Schristos        warn "Failed accepting incoming connection: $!\n";
36853060421Schristos        return 0;
36953060421Schristos    }
37053060421Schristos
37153060421Schristos    print "Connection opened\n";
37253060421Schristos
37313d40330Schristos    my $server_sock = $self->{server_sock};
37453060421Schristos    my $indata;
37553060421Schristos
37653060421Schristos    #Wait for either the server socket or the client socket to become readable
37713d40330Schristos    $fdset = IO::Select->new($server_sock, $client_sock);
37853060421Schristos    my @ready;
37913d40330Schristos    my $ctr = 0;
38053060421Schristos    local $SIG{PIPE} = "IGNORE";
38113d40330Schristos    $self->{saw_session_ticket} = undef;
38213d40330Schristos    while($fdset->count && $ctr < 10) {
38313d40330Schristos        if (defined($self->{sessionfile})) {
38413d40330Schristos            # s_client got -ign_eof and won't be exiting voluntarily, so we
38513d40330Schristos            # look for data *and* session ticket...
38613d40330Schristos            last if TLSProxy::Message->success()
38713d40330Schristos                    && $self->{saw_session_ticket};
38813d40330Schristos        }
38913d40330Schristos        if (!(@ready = $fdset->can_read(1))) {
39013d40330Schristos            $ctr++;
39113d40330Schristos            next;
39213d40330Schristos        }
39353060421Schristos        foreach my $hand (@ready) {
39453060421Schristos            if ($hand == $server_sock) {
39513d40330Schristos                if ($server_sock->sysread($indata, 16384)) {
39613d40330Schristos                    if ($indata = $self->process_packet(1, $indata)) {
39713d40330Schristos                        $client_sock->syswrite($indata) or goto END;
39813d40330Schristos                    }
39913d40330Schristos                    $ctr = 0;
40053060421Schristos                } else {
40113d40330Schristos                    $fdset->remove($server_sock);
40213d40330Schristos                    $client_sock->shutdown(SHUT_WR);
40313d40330Schristos                }
40413d40330Schristos            } elsif ($hand == $client_sock) {
40513d40330Schristos                if ($client_sock->sysread($indata, 16384)) {
40613d40330Schristos                    if ($indata = $self->process_packet(0, $indata)) {
40713d40330Schristos                        $server_sock->syswrite($indata) or goto END;
40813d40330Schristos                    }
40913d40330Schristos                    $ctr = 0;
41013d40330Schristos                } else {
41113d40330Schristos                    $fdset->remove($client_sock);
41213d40330Schristos                    $server_sock->shutdown(SHUT_WR);
41313d40330Schristos                }
41413d40330Schristos            } else {
41513d40330Schristos                kill(3, $self->{real_serverpid});
41613d40330Schristos                die "Unexpected handle";
41753060421Schristos            }
41853060421Schristos        }
41953060421Schristos    }
42053060421Schristos
42113d40330Schristos    if ($ctr >= 10) {
42213d40330Schristos        kill(3, $self->{real_serverpid});
42313d40330Schristos        die "No progress made";
42413d40330Schristos    }
42513d40330Schristos
42653060421Schristos    END:
42753060421Schristos    print "Connection closed\n";
42853060421Schristos    if($server_sock) {
42953060421Schristos        $server_sock->close();
43013d40330Schristos        $self->{server_sock} = undef;
43153060421Schristos    }
43253060421Schristos    if($client_sock) {
43353060421Schristos        #Closing this also kills the child process
43453060421Schristos        $client_sock->close();
43553060421Schristos    }
43613d40330Schristos
43713d40330Schristos    my $pid;
43813d40330Schristos    if (--$self->{serverconnects} == 0) {
43913d40330Schristos        $pid = $self->{serverpid};
44013d40330Schristos        print "Waiting for 'perl -ne print' process to close: $pid...\n";
44113d40330Schristos        $pid = waitpid($pid, 0);
44213d40330Schristos        if ($pid > 0) {
44313d40330Schristos            die "exit code $? from 'perl -ne print' process\n" if $? != 0;
44413d40330Schristos        } elsif ($pid == 0) {
44513d40330Schristos            kill(3, $self->{real_serverpid});
44613d40330Schristos            die "lost control over $self->{serverpid}?";
44753060421Schristos        }
44813d40330Schristos        $pid = $self->{real_serverpid};
44913d40330Schristos        print "Waiting for s_server process to close: $pid...\n";
45013d40330Schristos        # it's done already, just collect the exit code [and reap]...
45113d40330Schristos        waitpid($pid, 0);
45213d40330Schristos        die "exit code $? from s_server process\n" if $? != 0;
45353060421Schristos    } else {
45413d40330Schristos        # It's a bit counter-intuitive spot to make next connection to
45513d40330Schristos        # the s_server. Rationale is that established connection works
4567d004720Schristos        # as synchronization point, in sense that this way we know that
45713d40330Schristos        # s_server is actually done with current session...
45813d40330Schristos        $self->connect_to_server();
45953060421Schristos    }
46013d40330Schristos    $pid = $self->{clientpid};
46113d40330Schristos    print "Waiting for s_client process to close: $pid...\n";
46213d40330Schristos    waitpid($pid, 0);
46353060421Schristos
46453060421Schristos    return 1;
46553060421Schristos}
46653060421Schristos
46753060421Schristossub process_packet
46853060421Schristos{
46953060421Schristos    my ($self, $server, $packet) = @_;
47053060421Schristos    my $len_real;
47153060421Schristos    my $decrypt_len;
47253060421Schristos    my $data;
47353060421Schristos    my $recnum;
47453060421Schristos
47553060421Schristos    if ($server) {
47653060421Schristos        print "Received server packet\n";
47753060421Schristos    } else {
47853060421Schristos        print "Received client packet\n";
47953060421Schristos    }
48053060421Schristos
48153060421Schristos    if ($self->{direction} != $server) {
48253060421Schristos        $self->{flight} = $self->{flight} + 1;
48353060421Schristos        $self->{direction} = $server;
48453060421Schristos    }
48553060421Schristos
48653060421Schristos    print "Packet length = ".length($packet)."\n";
48753060421Schristos    print "Processing flight ".$self->flight."\n";
48853060421Schristos
48953060421Schristos    #Return contains the list of record found in the packet followed by the
49053060421Schristos    #list of messages in those records and any partial message
49113d40330Schristos    my @ret = TLSProxy::Record->get_records($server, $self->flight,
49213d40330Schristos                                            $self->{partial}[$server].$packet);
49353060421Schristos    $self->{partial}[$server] = $ret[2];
49413d40330Schristos    push @{$self->{record_list}}, @{$ret[0]};
49553060421Schristos    push @{$self->{message_list}}, @{$ret[1]};
49653060421Schristos
49753060421Schristos    print "\n";
49853060421Schristos
49953060421Schristos    if (scalar(@{$ret[0]}) == 0 or length($ret[2]) != 0) {
50053060421Schristos        return "";
50153060421Schristos    }
50253060421Schristos
50353060421Schristos    #Finished parsing. Call user provided filter here
50453060421Schristos    if (defined $self->filter) {
50553060421Schristos        $self->filter->($self);
50653060421Schristos    }
50753060421Schristos
50813d40330Schristos    #Take a note on NewSessionTicket
50913d40330Schristos    foreach my $message (reverse @{$self->{message_list}}) {
51013d40330Schristos        if ($message->{mt} == TLSProxy::Message::MT_NEW_SESSION_TICKET) {
51113d40330Schristos            $self->{saw_session_ticket} = 1;
51213d40330Schristos            last;
51313d40330Schristos        }
51413d40330Schristos    }
51513d40330Schristos
51653060421Schristos    #Reconstruct the packet
51753060421Schristos    $packet = "";
51853060421Schristos    foreach my $record (@{$self->record_list}) {
51913d40330Schristos        $packet .= $record->reconstruct_record($server);
52053060421Schristos    }
52153060421Schristos
52253060421Schristos    print "Forwarded packet length = ".length($packet)."\n\n";
52353060421Schristos
52453060421Schristos    return $packet;
52553060421Schristos}
52653060421Schristos
52753060421Schristos#Read accessors
52853060421Schristossub execute
52953060421Schristos{
53053060421Schristos    my $self = shift;
53153060421Schristos    return $self->{execute};
53253060421Schristos}
53353060421Schristossub cert
53453060421Schristos{
53553060421Schristos    my $self = shift;
53653060421Schristos    return $self->{cert};
53753060421Schristos}
53853060421Schristossub debug
53953060421Schristos{
54053060421Schristos    my $self = shift;
54153060421Schristos    return $self->{debug};
54253060421Schristos}
54353060421Schristossub flight
54453060421Schristos{
54553060421Schristos    my $self = shift;
54653060421Schristos    return $self->{flight};
54753060421Schristos}
54853060421Schristossub record_list
54953060421Schristos{
55053060421Schristos    my $self = shift;
55153060421Schristos    return $self->{record_list};
55253060421Schristos}
55353060421Schristossub success
55453060421Schristos{
55553060421Schristos    my $self = shift;
55653060421Schristos    return $self->{success};
55753060421Schristos}
55853060421Schristossub end
55953060421Schristos{
56053060421Schristos    my $self = shift;
56153060421Schristos    return $self->{end};
56253060421Schristos}
56353060421Schristossub supports_IPv6
56453060421Schristos{
56553060421Schristos    my $self = shift;
56653060421Schristos    return $have_IPv6;
56753060421Schristos}
56853060421Schristossub proxy_addr
56953060421Schristos{
57053060421Schristos    my $self = shift;
57153060421Schristos    return $self->{proxy_addr};
57253060421Schristos}
57353060421Schristossub proxy_port
57453060421Schristos{
57553060421Schristos    my $self = shift;
57653060421Schristos    return $self->{proxy_port};
57753060421Schristos}
57853060421Schristossub server_addr
57953060421Schristos{
58053060421Schristos    my $self = shift;
58153060421Schristos    return $self->{server_addr};
58253060421Schristos}
58353060421Schristossub server_port
58453060421Schristos{
58553060421Schristos    my $self = shift;
58653060421Schristos    return $self->{server_port};
58753060421Schristos}
58813d40330Schristossub serverpid
58913d40330Schristos{
59013d40330Schristos    my $self = shift;
59113d40330Schristos    return $self->{serverpid};
59213d40330Schristos}
59313d40330Schristossub clientpid
59413d40330Schristos{
59513d40330Schristos    my $self = shift;
59613d40330Schristos    return $self->{clientpid};
59713d40330Schristos}
59813d40330Schristos
59913d40330Schristos#Read/write accessors
60053060421Schristossub filter
60153060421Schristos{
60253060421Schristos    my $self = shift;
60353060421Schristos    if (@_) {
60453060421Schristos        $self->{filter} = shift;
60553060421Schristos    }
60653060421Schristos    return $self->{filter};
60753060421Schristos}
60853060421Schristossub cipherc
60953060421Schristos{
61053060421Schristos    my $self = shift;
61153060421Schristos    if (@_) {
61253060421Schristos        $self->{cipherc} = shift;
61353060421Schristos    }
61453060421Schristos    return $self->{cipherc};
61553060421Schristos}
61613d40330Schristossub ciphersuitesc
61713d40330Schristos{
61813d40330Schristos    my $self = shift;
61913d40330Schristos    if (@_) {
62013d40330Schristos        $self->{ciphersuitesc} = shift;
62113d40330Schristos    }
62213d40330Schristos    return $self->{ciphersuitesc};
62313d40330Schristos}
62453060421Schristossub ciphers
62553060421Schristos{
62653060421Schristos    my $self = shift;
62753060421Schristos    if (@_) {
62853060421Schristos        $self->{ciphers} = shift;
62953060421Schristos    }
63053060421Schristos    return $self->{ciphers};
63153060421Schristos}
63213d40330Schristossub ciphersuitess
63313d40330Schristos{
63413d40330Schristos    my $self = shift;
63513d40330Schristos    if (@_) {
63613d40330Schristos        $self->{ciphersuitess} = shift;
63713d40330Schristos    }
63813d40330Schristos    return $self->{ciphersuitess};
63913d40330Schristos}
64053060421Schristossub serverflags
64153060421Schristos{
64253060421Schristos    my $self = shift;
64353060421Schristos    if (@_) {
64453060421Schristos        $self->{serverflags} = shift;
64553060421Schristos    }
64653060421Schristos    return $self->{serverflags};
64753060421Schristos}
64853060421Schristossub clientflags
64953060421Schristos{
65053060421Schristos    my $self = shift;
65153060421Schristos    if (@_) {
65253060421Schristos        $self->{clientflags} = shift;
65353060421Schristos    }
65453060421Schristos    return $self->{clientflags};
65553060421Schristos}
65653060421Schristossub serverconnects
65753060421Schristos{
65853060421Schristos    my $self = shift;
65953060421Schristos    if (@_) {
66053060421Schristos        $self->{serverconnects} = shift;
66153060421Schristos    }
66253060421Schristos    return $self->{serverconnects};
66353060421Schristos}
66453060421Schristos# This is a bit ugly because the caller is responsible for keeping the records
66553060421Schristos# in sync with the updated message list; simply updating the message list isn't
66653060421Schristos# sufficient to get the proxy to forward the new message.
66753060421Schristos# But it does the trick for the one test (test_sslsessiontick) that needs it.
66853060421Schristossub message_list
66953060421Schristos{
67053060421Schristos    my $self = shift;
67153060421Schristos    if (@_) {
67253060421Schristos        $self->{message_list} = shift;
67353060421Schristos    }
67453060421Schristos    return $self->{message_list};
67553060421Schristos}
67653060421Schristos
67753060421Schristossub fill_known_data
67853060421Schristos{
67953060421Schristos    my $length = shift;
68053060421Schristos    my $ret = "";
68153060421Schristos    for (my $i = 0; $i < $length; $i++) {
68253060421Schristos        $ret .= chr($i);
68353060421Schristos    }
68453060421Schristos    return $ret;
68553060421Schristos}
68653060421Schristos
68713d40330Schristossub is_tls13
68813d40330Schristos{
68913d40330Schristos    my $class = shift;
69013d40330Schristos    if (@_) {
69113d40330Schristos        $is_tls13 = shift;
69213d40330Schristos    }
69313d40330Schristos    return $is_tls13;
69413d40330Schristos}
69513d40330Schristos
69653060421Schristossub reneg
69753060421Schristos{
69853060421Schristos    my $self = shift;
69953060421Schristos    if (@_) {
70053060421Schristos        $self->{reneg} = shift;
70153060421Schristos    }
70253060421Schristos    return $self->{reneg};
70353060421Schristos}
70453060421Schristos
70513d40330Schristos#Setting a sessionfile means that the client will not close until the given
70613d40330Schristos#file exists. This is useful in TLSv1.3 where otherwise s_client will close
70713d40330Schristos#immediately at the end of the handshake, but before the session has been
70813d40330Schristos#received from the server. A side effect of this is that s_client never sends
70913d40330Schristos#a close_notify, so instead we consider success to be when it sends application
71013d40330Schristos#data over the connection.
71113d40330Schristossub sessionfile
71213d40330Schristos{
71313d40330Schristos    my $self = shift;
71413d40330Schristos    if (@_) {
71513d40330Schristos        $self->{sessionfile} = shift;
71613d40330Schristos        TLSProxy::Message->successondata(1);
71713d40330Schristos    }
71813d40330Schristos    return $self->{sessionfile};
71913d40330Schristos}
72013d40330Schristos
72113d40330Schristossub ciphersuite
72213d40330Schristos{
72313d40330Schristos    my $class = shift;
72413d40330Schristos    if (@_) {
72513d40330Schristos        $ciphersuite = shift;
72613d40330Schristos    }
72713d40330Schristos    return $ciphersuite;
72813d40330Schristos}
72913d40330Schristos
73053060421Schristos1;
731