Net-QUIC

 view release on metacpan or  search on metacpan

t/07-server-front-door.t  view on Meta::CPAN

use strict;
use warnings;

use FindBin ();
use Socket qw(inet_aton pack_sockaddr_in);
use Test2::V0;
use Time::HiRes qw(sleep);

use Net::QUIC::Endpoint;

my $server_local = pack_sockaddr_in(4437, inet_aton('127.0.0.1'));
my $client_local = pack_sockaddr_in(40005, inet_aton('127.0.0.1'));
my $wrong_client_local = pack_sockaddr_in(40006, inet_aton('127.0.0.1'));
my $alpn = 'net-quic-front-door-test';
my $cert_file = "$FindBin::Bin/data/server-cert.pem";
my $key_file = "$FindBin::Bin/data/server-key.pem";

sub make_client {
    return Net::QUIC::Endpoint->client(
        local       => $client_local,
        peer        => $server_local,
        alpn        => $alpn,
        server_name => 'localhost',
        ca_file     => $cert_file,
    );
}

my $vn_server = Net::QUIC::Endpoint->server(
    alpn             => $alpn,
    certificate_file => $cert_file,
    private_key_file => $key_file,
);

my $vn_client = make_client();
my $initial = $vn_client->next_datagram;
ok(defined($initial), 'client produces Initial for version negotiation test');

my $unsupported = $initial->data;
substr($unsupported, 1, 4, pack('N', 0x1a2a3a4a));

$vn_server->receive_datagram(
    $unsupported,
    $server_local,
    $client_local,
);

ok(
    !defined($vn_server->next_connection),
    'unsupported version does not allocate a Connection',
);

my $vn = $vn_server->next_datagram;
ok(defined($vn), 'unsupported version produces a stateless response');
is(
    $vn->local,
    $server_local,
    'Version Negotiation preserves the concrete local destination address',
);
is(
    unpack('N', substr($vn->data, 1, 4)),
    0,
    'stateless response is a Version Negotiation packet',
);
my $vn_data = $vn->data;
my $offset = 5;
my $dcid_len = unpack('C', substr($vn_data, $offset, 1));
$offset += 1 + $dcid_len;
my $scid_len = unpack('C', substr($vn_data, $offset, 1));
$offset += 1 + $scid_len;
my @versions = unpack('N*', substr($vn_data, $offset));

ok(
    scalar(grep { $_ == 1 } @versions),
    'Version Negotiation advertises QUIC v1',
);
ok(
    !defined($vn_server->next_datagram),
    'Version Negotiation response is drained from stateless queue',
);

my $server = Net::QUIC::Endpoint->server(
    alpn             => $alpn,
    certificate_file => $cert_file,
    private_key_file => $key_file,
    validate_address => 1,
);
my $client = make_client();

$initial = $client->next_datagram;
ok(defined($initial), 'client produces Initial for Retry test');

$server->receive_datagram(
    $initial->data,
    $server_local,
    $client_local,
);

ok(
    !defined($server->next_connection),
    'first Initial does not allocate a Connection when address validation is enabled',
);

my $retry = $server->next_datagram;
ok(defined($retry), 'server answers first Initial with Retry');
is(
    $retry->local,
    $server_local,
    'Retry preserves the concrete local destination address',
);

$client->receive_datagram(
    $retry->data,
    $client_local,
    $server_local,
);

my $retried_initial = $client->next_datagram;
ok(defined($retried_initial), 'client answers Retry with another Initial');

$server->receive_datagram(
    $retried_initial->data,
    $server_local,
    $wrong_client_local,
);

ok(
    !defined($server->next_connection),
    'Retry token cannot be replayed from a different peer address',
);

my $invalid_token_response = $server->next_datagram;
ok(
    defined($invalid_token_response),
    'invalid address-bound Retry token gets a stateless rejection',
);
is(
    $invalid_token_response->peer,
    $wrong_client_local,
    'stateless rejection is addressed to the peer that used the bad token',
);
is(
    $invalid_token_response->local,
    $server_local,
    'stateless rejection preserves the concrete local destination address',



( run in 1.053 second using v1.01-cache-2.11-cpan-036bef1c656 )