early-access version 1503
This commit is contained in:
273
externals/mbedtls/programs/test/udp_proxy.c
vendored
273
externals/mbedtls/programs/test/udp_proxy.c
vendored
@@ -1,8 +1,31 @@
|
||||
/*
|
||||
* UDP proxy: emulate an unreliable UDP connexion for DTLS testing
|
||||
*
|
||||
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
* Copyright The Mbed TLS Contributors
|
||||
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
*
|
||||
* This file is provided under the Apache License 2.0, or the
|
||||
* GNU General Public License v2.0 or later.
|
||||
*
|
||||
* **********
|
||||
* Apache License 2.0:
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* **********
|
||||
*
|
||||
* **********
|
||||
* GNU General Public License v2.0 or later:
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -18,7 +41,7 @@
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* This file is part of mbed TLS (https://tls.mbed.org)
|
||||
* **********
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -42,6 +65,9 @@
|
||||
#define mbedtls_time time
|
||||
#define mbedtls_time_t time_t
|
||||
#define mbedtls_printf printf
|
||||
#define mbedtls_calloc calloc
|
||||
#define mbedtls_free free
|
||||
#define mbedtls_exit exit
|
||||
#define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS
|
||||
#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE
|
||||
#endif /* MBEDTLS_PLATFORM_C */
|
||||
@@ -50,7 +76,7 @@
|
||||
int main( void )
|
||||
{
|
||||
mbedtls_printf( "MBEDTLS_NET_C not defined.\n" );
|
||||
return( 0 );
|
||||
mbedtls_exit( 0 );
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -108,6 +134,21 @@ int main( void )
|
||||
" delay=%%d default: 0 (no delayed packets)\n" \
|
||||
" delay about 1:N packets randomly\n" \
|
||||
" delay_ccs=0/1 default: 0 (don't delay ChangeCipherSpec)\n" \
|
||||
" delay_cli=%%s Handshake message from client that should be\n"\
|
||||
" delayed. Possible values are 'ClientHello',\n" \
|
||||
" 'Certificate', 'CertificateVerify', and\n" \
|
||||
" 'ClientKeyExchange'.\n" \
|
||||
" May be used multiple times, even for the same\n"\
|
||||
" message, in which case the respective message\n"\
|
||||
" gets delayed multiple times.\n" \
|
||||
" delay_srv=%%s Handshake message from server that should be\n"\
|
||||
" delayed. Possible values are 'HelloRequest',\n"\
|
||||
" 'ServerHello', 'ServerHelloDone', 'Certificate'\n"\
|
||||
" 'ServerKeyExchange', 'NewSessionTicket',\n"\
|
||||
" 'HelloVerifyRequest' and ''CertificateRequest'.\n"\
|
||||
" May be used multiple times, even for the same\n"\
|
||||
" message, in which case the respective message\n"\
|
||||
" gets delayed multiple times.\n" \
|
||||
" drop=%%d default: 0 (no dropped packets)\n" \
|
||||
" drop about 1:N packets randomly\n" \
|
||||
" mtu=%%d default: 0 (unlimited)\n" \
|
||||
@@ -115,6 +156,7 @@ int main( void )
|
||||
" bad_ad=0/1 default: 0 (don't add bad ApplicationData)\n" \
|
||||
" protect_hvr=0/1 default: 0 (don't protect HelloVerifyRequest)\n" \
|
||||
" protect_len=%%d default: (don't protect packets of this size)\n" \
|
||||
" inject_clihlo=0/1 default: 0 (don't inject fake ClientHello)\n" \
|
||||
"\n" \
|
||||
" seed=%%d default: (use current time)\n" \
|
||||
USAGE_PACK \
|
||||
@@ -123,6 +165,9 @@ int main( void )
|
||||
/*
|
||||
* global options
|
||||
*/
|
||||
|
||||
#define MAX_DELAYED_HS 10
|
||||
|
||||
static struct options
|
||||
{
|
||||
const char *server_addr; /* address to forward packets to */
|
||||
@@ -133,11 +178,18 @@ static struct options
|
||||
int duplicate; /* duplicate 1 in N packets (none if 0) */
|
||||
int delay; /* delay 1 packet in N (none if 0) */
|
||||
int delay_ccs; /* delay ChangeCipherSpec */
|
||||
char* delay_cli[MAX_DELAYED_HS]; /* handshake types of messages from
|
||||
* client that should be delayed. */
|
||||
uint8_t delay_cli_cnt; /* Number of entries in delay_cli. */
|
||||
char* delay_srv[MAX_DELAYED_HS]; /* handshake types of messages from
|
||||
* server that should be delayed. */
|
||||
uint8_t delay_srv_cnt; /* Number of entries in delay_srv. */
|
||||
int drop; /* drop 1 packet in N (none if 0) */
|
||||
int mtu; /* drop packets larger than this */
|
||||
int bad_ad; /* inject corrupted ApplicationData record */
|
||||
int protect_hvr; /* never drop or delay HelloVerifyRequest */
|
||||
int protect_len; /* never drop/delay packet of the given size*/
|
||||
int inject_clihlo; /* inject fake ClientHello after handshake */
|
||||
unsigned pack; /* merge packets into single datagram for
|
||||
* at most \c merge milliseconds if > 0 */
|
||||
unsigned int seed; /* seed for "random" events */
|
||||
@@ -166,6 +218,11 @@ static void get_options( int argc, char *argv[] )
|
||||
opt.pack = DFL_PACK;
|
||||
/* Other members default to 0 */
|
||||
|
||||
opt.delay_cli_cnt = 0;
|
||||
opt.delay_srv_cnt = 0;
|
||||
memset( opt.delay_cli, 0, sizeof( opt.delay_cli ) );
|
||||
memset( opt.delay_srv, 0, sizeof( opt.delay_srv ) );
|
||||
|
||||
for( i = 1; i < argc; i++ )
|
||||
{
|
||||
p = argv[i];
|
||||
@@ -199,6 +256,43 @@ static void get_options( int argc, char *argv[] )
|
||||
if( opt.delay_ccs < 0 || opt.delay_ccs > 1 )
|
||||
exit_usage( p, q );
|
||||
}
|
||||
else if( strcmp( p, "delay_cli" ) == 0 ||
|
||||
strcmp( p, "delay_srv" ) == 0 )
|
||||
{
|
||||
uint8_t *delay_cnt;
|
||||
char **delay_list;
|
||||
size_t len;
|
||||
char *buf;
|
||||
|
||||
if( strcmp( p, "delay_cli" ) == 0 )
|
||||
{
|
||||
delay_cnt = &opt.delay_cli_cnt;
|
||||
delay_list = opt.delay_cli;
|
||||
}
|
||||
else
|
||||
{
|
||||
delay_cnt = &opt.delay_srv_cnt;
|
||||
delay_list = opt.delay_srv;
|
||||
}
|
||||
|
||||
if( *delay_cnt == MAX_DELAYED_HS )
|
||||
{
|
||||
mbedtls_printf( " too many uses of %s: only %d allowed\n",
|
||||
p, MAX_DELAYED_HS );
|
||||
exit_usage( p, NULL );
|
||||
}
|
||||
|
||||
len = strlen( q );
|
||||
buf = mbedtls_calloc( 1, len + 1 );
|
||||
if( buf == NULL )
|
||||
{
|
||||
mbedtls_printf( " Allocation failure\n" );
|
||||
exit( 1 );
|
||||
}
|
||||
memcpy( buf, q, len + 1 );
|
||||
|
||||
delay_list[ (*delay_cnt)++ ] = buf;
|
||||
}
|
||||
else if( strcmp( p, "drop" ) == 0 )
|
||||
{
|
||||
opt.drop = atoi( q );
|
||||
@@ -238,6 +332,12 @@ static void get_options( int argc, char *argv[] )
|
||||
if( opt.protect_len < 0 )
|
||||
exit_usage( p, q );
|
||||
}
|
||||
else if( strcmp( p, "inject_clihlo" ) == 0 )
|
||||
{
|
||||
opt.inject_clihlo = atoi( q );
|
||||
if( opt.inject_clihlo < 0 || opt.inject_clihlo > 1 )
|
||||
exit_usage( p, q );
|
||||
}
|
||||
else if( strcmp( p, "seed" ) == 0 )
|
||||
{
|
||||
opt.seed = atoi( q );
|
||||
@@ -437,11 +537,41 @@ void print_packet( const packet *p, const char *why )
|
||||
fflush( stdout );
|
||||
}
|
||||
|
||||
/*
|
||||
* In order to test the server's behaviour when receiving a ClientHello after
|
||||
* the connection is established (this could be a hard reset from the client,
|
||||
* but the server must not drop the existing connection before establishing
|
||||
* client reachability, see RFC 6347 Section 4.2.8), we memorize the first
|
||||
* ClientHello we see (which can't have a cookie), then replay it after the
|
||||
* first ApplicationData record - then we're done.
|
||||
*
|
||||
* This is controlled by the inject_clihlo option.
|
||||
*
|
||||
* We want an explicit state and a place to store the packet.
|
||||
*/
|
||||
typedef enum {
|
||||
ICH_INIT, /* haven't seen the first ClientHello yet */
|
||||
ICH_CACHED, /* cached the initial ClientHello */
|
||||
ICH_INJECTED, /* ClientHello already injected, done */
|
||||
} inject_clihlo_state_t;
|
||||
|
||||
static inject_clihlo_state_t inject_clihlo_state;
|
||||
static packet initial_clihlo;
|
||||
|
||||
int send_packet( const packet *p, const char *why )
|
||||
{
|
||||
int ret;
|
||||
mbedtls_net_context *dst = p->dst;
|
||||
|
||||
/* save initial ClientHello? */
|
||||
if( opt.inject_clihlo != 0 &&
|
||||
inject_clihlo_state == ICH_INIT &&
|
||||
strcmp( p->type, "ClientHello" ) == 0 )
|
||||
{
|
||||
memcpy( &initial_clihlo, p, sizeof( packet ) );
|
||||
inject_clihlo_state = ICH_CACHED;
|
||||
}
|
||||
|
||||
/* insert corrupted ApplicationData record? */
|
||||
if( opt.bad_ad &&
|
||||
strcmp( p->type, "ApplicationData" ) == 0 )
|
||||
@@ -487,14 +617,57 @@ int send_packet( const packet *p, const char *why )
|
||||
}
|
||||
}
|
||||
|
||||
/* Inject ClientHello after first ApplicationData */
|
||||
if( opt.inject_clihlo != 0 &&
|
||||
inject_clihlo_state == ICH_CACHED &&
|
||||
strcmp( p->type, "ApplicationData" ) == 0 )
|
||||
{
|
||||
print_packet( &initial_clihlo, "injected" );
|
||||
|
||||
if( ( ret = dispatch_data( dst, initial_clihlo.buf,
|
||||
initial_clihlo.len ) ) <= 0 )
|
||||
{
|
||||
mbedtls_printf( " ! dispatch returned %d\n", ret );
|
||||
return( ret );
|
||||
}
|
||||
|
||||
inject_clihlo_state = ICH_INJECTED;
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static packet prev;
|
||||
#define MAX_DELAYED_MSG 5
|
||||
static size_t prev_len;
|
||||
static packet prev[MAX_DELAYED_MSG];
|
||||
|
||||
void clear_pending( void )
|
||||
{
|
||||
memset( &prev, 0, sizeof( packet ) );
|
||||
memset( &prev, 0, sizeof( prev ) );
|
||||
prev_len = 0;
|
||||
}
|
||||
|
||||
void delay_packet( packet *delay )
|
||||
{
|
||||
if( prev_len == MAX_DELAYED_MSG )
|
||||
return;
|
||||
|
||||
memcpy( &prev[prev_len++], delay, sizeof( packet ) );
|
||||
}
|
||||
|
||||
int send_delayed()
|
||||
{
|
||||
uint8_t offset;
|
||||
int ret;
|
||||
for( offset = 0; offset < prev_len; offset++ )
|
||||
{
|
||||
ret = send_packet( &prev[offset], "delayed" );
|
||||
if( ret != 0 )
|
||||
return( ret );
|
||||
}
|
||||
|
||||
clear_pending();
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -506,32 +679,17 @@ void clear_pending( void )
|
||||
static unsigned char dropped[2048] = { 0 };
|
||||
#define DROP_MAX 2
|
||||
|
||||
/*
|
||||
* OpenSSL groups packets in a datagram the first time it sends them, but not
|
||||
* when it resends them. Count every record as seen the first time.
|
||||
*/
|
||||
/* We only drop packets at the level of entire datagrams, not at the level
|
||||
* of records. In particular, if the peer changes the way it packs multiple
|
||||
* records into a single datagram, we don't necessarily count the number of
|
||||
* times a record has been dropped correctly. However, the only known reason
|
||||
* why a peer would change datagram packing is disabling the latter on
|
||||
* retransmission, in which case we'd drop involved records at most
|
||||
* DROP_MAX + 1 times. */
|
||||
void update_dropped( const packet *p )
|
||||
{
|
||||
size_t id = p->len % sizeof( dropped );
|
||||
const unsigned char *end = p->buf + p->len;
|
||||
const unsigned char *cur = p->buf;
|
||||
size_t len = ( ( cur[11] << 8 ) | cur[12] ) + 13;
|
||||
|
||||
++dropped[id];
|
||||
|
||||
/* Avoid counting single record twice */
|
||||
if( len == p->len )
|
||||
return;
|
||||
|
||||
while( cur < end )
|
||||
{
|
||||
len = ( ( cur[11] << 8 ) | cur[12] ) + 13;
|
||||
|
||||
id = len % sizeof( dropped );
|
||||
++dropped[id];
|
||||
|
||||
cur += len;
|
||||
}
|
||||
}
|
||||
|
||||
int handle_message( const char *way,
|
||||
@@ -542,6 +700,10 @@ int handle_message( const char *way,
|
||||
packet cur;
|
||||
size_t id;
|
||||
|
||||
uint8_t delay_idx;
|
||||
char ** delay_list;
|
||||
uint8_t delay_list_len;
|
||||
|
||||
/* receive packet */
|
||||
if( ( ret = mbedtls_net_recv( src, cur.buf, sizeof( cur.buf ) ) ) <= 0 )
|
||||
{
|
||||
@@ -557,6 +719,37 @@ int handle_message( const char *way,
|
||||
|
||||
id = cur.len % sizeof( dropped );
|
||||
|
||||
if( strcmp( way, "S <- C" ) == 0 )
|
||||
{
|
||||
delay_list = opt.delay_cli;
|
||||
delay_list_len = opt.delay_cli_cnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
delay_list = opt.delay_srv;
|
||||
delay_list_len = opt.delay_srv_cnt;
|
||||
}
|
||||
|
||||
/* Check if message type is in the list of messages
|
||||
* that should be delayed */
|
||||
for( delay_idx = 0; delay_idx < delay_list_len; delay_idx++ )
|
||||
{
|
||||
if( delay_list[ delay_idx ] == NULL )
|
||||
continue;
|
||||
|
||||
if( strcmp( delay_list[ delay_idx ], cur.type ) == 0 )
|
||||
{
|
||||
/* Delay message */
|
||||
delay_packet( &cur );
|
||||
|
||||
/* Remove entry from list */
|
||||
mbedtls_free( delay_list[delay_idx] );
|
||||
delay_list[delay_idx] = NULL;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/* do we want to drop, delay, or forward it? */
|
||||
if( ( opt.mtu != 0 &&
|
||||
cur.len > (unsigned) opt.mtu ) ||
|
||||
@@ -576,12 +769,11 @@ int handle_message( const char *way,
|
||||
strcmp( cur.type, "ApplicationData" ) != 0 &&
|
||||
! ( opt.protect_hvr &&
|
||||
strcmp( cur.type, "HelloVerifyRequest" ) == 0 ) &&
|
||||
prev.dst == NULL &&
|
||||
cur.len != (size_t) opt.protect_len &&
|
||||
dropped[id] < DROP_MAX &&
|
||||
rand() % opt.delay == 0 ) )
|
||||
{
|
||||
memcpy( &prev, &cur, sizeof( packet ) );
|
||||
delay_packet( &cur );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -589,14 +781,10 @@ int handle_message( const char *way,
|
||||
if( ( ret = send_packet( &cur, "forwarded" ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
/* send previously delayed message if any */
|
||||
if( prev.dst != NULL )
|
||||
{
|
||||
ret = send_packet( &prev, "delayed" );
|
||||
memset( &prev, 0, sizeof( packet ) );
|
||||
if( ret != 0 )
|
||||
return( ret );
|
||||
}
|
||||
/* send previously delayed messages if any */
|
||||
ret = send_delayed();
|
||||
if( ret != 0 )
|
||||
return( ret );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
@@ -606,6 +794,7 @@ int main( int argc, char *argv[] )
|
||||
{
|
||||
int ret = 1;
|
||||
int exit_code = MBEDTLS_EXIT_FAILURE;
|
||||
uint8_t delay_idx;
|
||||
|
||||
mbedtls_net_context listen_fd, client_fd, server_fd;
|
||||
|
||||
@@ -800,6 +989,12 @@ exit:
|
||||
}
|
||||
#endif
|
||||
|
||||
for( delay_idx = 0; delay_idx < MAX_DELAYED_HS; delay_idx++ )
|
||||
{
|
||||
mbedtls_free( opt.delay_cli + delay_idx );
|
||||
mbedtls_free( opt.delay_srv + delay_idx );
|
||||
}
|
||||
|
||||
mbedtls_net_free( &client_fd );
|
||||
mbedtls_net_free( &server_fd );
|
||||
mbedtls_net_free( &listen_fd );
|
||||
@@ -809,7 +1004,7 @@ exit:
|
||||
fflush( stdout ); getchar();
|
||||
#endif
|
||||
|
||||
return( exit_code );
|
||||
mbedtls_exit( exit_code );
|
||||
}
|
||||
|
||||
#endif /* MBEDTLS_NET_C */
|
||||
|
Reference in New Issue
Block a user