• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  UDP proxy: emulate an unreliable UDP connexion for DTLS testing
3  *
4  *  Copyright The Mbed TLS Contributors
5  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6  *
7  *  This file is provided under the Apache License 2.0, or the
8  *  GNU General Public License v2.0 or later.
9  *
10  *  **********
11  *  Apache License 2.0:
12  *
13  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
14  *  not use this file except in compliance with the License.
15  *  You may obtain a copy of the License at
16  *
17  *  http://www.apache.org/licenses/LICENSE-2.0
18  *
19  *  Unless required by applicable law or agreed to in writing, software
20  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
21  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22  *  See the License for the specific language governing permissions and
23  *  limitations under the License.
24  *
25  *  **********
26  *
27  *  **********
28  *  GNU General Public License v2.0 or later:
29  *
30  *  This program is free software; you can redistribute it and/or modify
31  *  it under the terms of the GNU General Public License as published by
32  *  the Free Software Foundation; either version 2 of the License, or
33  *  (at your option) any later version.
34  *
35  *  This program is distributed in the hope that it will be useful,
36  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
37  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38  *  GNU General Public License for more details.
39  *
40  *  You should have received a copy of the GNU General Public License along
41  *  with this program; if not, write to the Free Software Foundation, Inc.,
42  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
43  *
44  *  **********
45  */
46 
47 /*
48  * Warning: this is an internal utility program we use for tests.
49  * It does break some abstractions from the NET layer, and is thus NOT an
50  * example of good general usage.
51  */
52 
53 #if !defined(MBEDTLS_CONFIG_FILE)
54 #include "mbedtls/config.h"
55 #else
56 #include MBEDTLS_CONFIG_FILE
57 #endif
58 
59 #if defined(MBEDTLS_PLATFORM_C)
60 #include "mbedtls/platform.h"
61 #else
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <time.h>
65 #define mbedtls_time            time
66 #define mbedtls_time_t          time_t
67 #define mbedtls_printf          printf
68 #define mbedtls_calloc          calloc
69 #define mbedtls_free            free
70 #define mbedtls_exit            exit
71 #define MBEDTLS_EXIT_SUCCESS    EXIT_SUCCESS
72 #define MBEDTLS_EXIT_FAILURE    EXIT_FAILURE
73 #endif /* MBEDTLS_PLATFORM_C */
74 
75 #if !defined(MBEDTLS_NET_C)
main(void)76 int main( void )
77 {
78     mbedtls_printf( "MBEDTLS_NET_C not defined.\n" );
79     mbedtls_exit( 0 );
80 }
81 #else
82 
83 #include "mbedtls/net_sockets.h"
84 #include "mbedtls/error.h"
85 #include "mbedtls/ssl.h"
86 #include "mbedtls/timing.h"
87 
88 #include <string.h>
89 
90 /* For select() */
91 #if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
92     !defined(EFI32)
93 #include <winsock2.h>
94 #include <windows.h>
95 #if defined(_MSC_VER)
96 #if defined(_WIN32_WCE)
97 #pragma comment( lib, "ws2.lib" )
98 #else
99 #pragma comment( lib, "ws2_32.lib" )
100 #endif
101 #endif /* _MSC_VER */
102 #else /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */
103 #include <sys/time.h>
104 #include <sys/types.h>
105 #include <unistd.h>
106 #endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */
107 
108 #define MAX_MSG_SIZE            16384 + 2048 /* max record/datagram size */
109 
110 #define DFL_SERVER_ADDR         "localhost"
111 #define DFL_SERVER_PORT         "4433"
112 #define DFL_LISTEN_ADDR         "localhost"
113 #define DFL_LISTEN_PORT         "5556"
114 #define DFL_PACK                0
115 
116 #if defined(MBEDTLS_TIMING_C)
117 #define USAGE_PACK                                                          \
118     "    pack=%%d             default: 0     (don't pack)\n"                \
119     "                         options: t > 0 (pack for t milliseconds)\n"
120 #else
121 #define USAGE_PACK
122 #endif
123 
124 #define USAGE                                                               \
125     "\n usage: udp_proxy param=<>...\n"                                     \
126     "\n acceptable parameters:\n"                                           \
127     "    server_addr=%%s      default: localhost\n"                         \
128     "    server_port=%%d      default: 4433\n"                              \
129     "    listen_addr=%%s      default: localhost\n"                         \
130     "    listen_port=%%d      default: 4433\n"                              \
131     "\n"                                                                    \
132     "    duplicate=%%d        default: 0 (no duplication)\n"                \
133     "                        duplicate about 1:N packets randomly\n"        \
134     "    delay=%%d            default: 0 (no delayed packets)\n"            \
135     "                        delay about 1:N packets randomly\n"            \
136     "    delay_ccs=0/1       default: 0 (don't delay ChangeCipherSpec)\n"   \
137     "    delay_cli=%%s        Handshake message from client that should be\n"\
138     "                        delayed. Possible values are 'ClientHello',\n" \
139     "                        'Certificate', 'CertificateVerify', and\n"     \
140     "                        'ClientKeyExchange'.\n"                        \
141     "                        May be used multiple times, even for the same\n"\
142     "                        message, in which case the respective message\n"\
143     "                        gets delayed multiple times.\n"                 \
144     "    delay_srv=%%s        Handshake message from server that should be\n"\
145     "                        delayed. Possible values are 'HelloRequest',\n"\
146     "                        'ServerHello', 'ServerHelloDone', 'Certificate'\n"\
147     "                        'ServerKeyExchange', 'NewSessionTicket',\n"\
148     "                        'HelloVerifyRequest' and ''CertificateRequest'.\n"\
149     "                        May be used multiple times, even for the same\n"\
150     "                        message, in which case the respective message\n"\
151     "                        gets delayed multiple times.\n"                 \
152     "    drop=%%d             default: 0 (no dropped packets)\n"            \
153     "                        drop about 1:N packets randomly\n"             \
154     "    mtu=%%d              default: 0 (unlimited)\n"                     \
155     "                        drop packets larger than N bytes\n"            \
156     "    bad_ad=0/1          default: 0 (don't add bad ApplicationData)\n"  \
157     "    protect_hvr=0/1     default: 0 (don't protect HelloVerifyRequest)\n" \
158     "    protect_len=%%d      default: (don't protect packets of this size)\n" \
159     "    inject_clihlo=0/1   default: 0 (don't inject fake ClientHello)\n"  \
160     "\n"                                                                    \
161     "    seed=%%d             default: (use current time)\n"                \
162     USAGE_PACK                                                              \
163     "\n"
164 
165 /*
166  * global options
167  */
168 
169 #define MAX_DELAYED_HS 10
170 
171 static struct options
172 {
173     const char *server_addr;    /* address to forward packets to            */
174     const char *server_port;    /* port to forward packets to               */
175     const char *listen_addr;    /* address for accepting client connections */
176     const char *listen_port;    /* port for accepting client connections    */
177 
178     int duplicate;              /* duplicate 1 in N packets (none if 0)     */
179     int delay;                  /* delay 1 packet in N (none if 0)          */
180     int delay_ccs;              /* delay ChangeCipherSpec                   */
181     char* delay_cli[MAX_DELAYED_HS];  /* handshake types of messages from
182                                        * client that should be delayed.     */
183     uint8_t delay_cli_cnt;      /* Number of entries in delay_cli.          */
184     char* delay_srv[MAX_DELAYED_HS];  /* handshake types of messages from
185                                        * server that should be delayed.     */
186     uint8_t delay_srv_cnt;      /* Number of entries in delay_srv.          */
187     int drop;                   /* drop 1 packet in N (none if 0)           */
188     int mtu;                    /* drop packets larger than this            */
189     int bad_ad;                 /* inject corrupted ApplicationData record  */
190     int protect_hvr;            /* never drop or delay HelloVerifyRequest   */
191     int protect_len;            /* never drop/delay packet of the given size*/
192     int inject_clihlo;          /* inject fake ClientHello after handshake  */
193     unsigned pack;              /* merge packets into single datagram for
194                                  * at most \c merge milliseconds if > 0     */
195     unsigned int seed;          /* seed for "random" events                 */
196 } opt;
197 
exit_usage(const char * name,const char * value)198 static void exit_usage( const char *name, const char *value )
199 {
200     if( value == NULL )
201         mbedtls_printf( " unknown option or missing value: %s\n", name );
202     else
203         mbedtls_printf( " option %s: illegal value: %s\n", name, value );
204 
205     mbedtls_printf( USAGE );
206     exit( 1 );
207 }
208 
get_options(int argc,char * argv[])209 static void get_options( int argc, char *argv[] )
210 {
211     int i;
212     char *p, *q;
213 
214     opt.server_addr    = DFL_SERVER_ADDR;
215     opt.server_port    = DFL_SERVER_PORT;
216     opt.listen_addr    = DFL_LISTEN_ADDR;
217     opt.listen_port    = DFL_LISTEN_PORT;
218     opt.pack           = DFL_PACK;
219     /* Other members default to 0 */
220 
221     opt.delay_cli_cnt = 0;
222     opt.delay_srv_cnt = 0;
223     memset( opt.delay_cli, 0, sizeof( opt.delay_cli ) );
224     memset( opt.delay_srv, 0, sizeof( opt.delay_srv ) );
225 
226     for( i = 1; i < argc; i++ )
227     {
228         p = argv[i];
229         if( ( q = strchr( p, '=' ) ) == NULL )
230             exit_usage( p, NULL );
231         *q++ = '\0';
232 
233         if( strcmp( p, "server_addr" ) == 0 )
234             opt.server_addr = q;
235         else if( strcmp( p, "server_port" ) == 0 )
236             opt.server_port = q;
237         else if( strcmp( p, "listen_addr" ) == 0 )
238             opt.listen_addr = q;
239         else if( strcmp( p, "listen_port" ) == 0 )
240             opt.listen_port = q;
241         else if( strcmp( p, "duplicate" ) == 0 )
242         {
243             opt.duplicate = atoi( q );
244             if( opt.duplicate < 0 || opt.duplicate > 20 )
245                 exit_usage( p, q );
246         }
247         else if( strcmp( p, "delay" ) == 0 )
248         {
249             opt.delay = atoi( q );
250             if( opt.delay < 0 || opt.delay > 20 || opt.delay == 1 )
251                 exit_usage( p, q );
252         }
253         else if( strcmp( p, "delay_ccs" ) == 0 )
254         {
255             opt.delay_ccs = atoi( q );
256             if( opt.delay_ccs < 0 || opt.delay_ccs > 1 )
257                 exit_usage( p, q );
258         }
259         else if( strcmp( p, "delay_cli" ) == 0 ||
260                  strcmp( p, "delay_srv" ) == 0 )
261         {
262             uint8_t *delay_cnt;
263             char **delay_list;
264             size_t len;
265             char *buf;
266 
267             if( strcmp( p, "delay_cli" ) == 0 )
268             {
269                 delay_cnt  = &opt.delay_cli_cnt;
270                 delay_list = opt.delay_cli;
271             }
272             else
273             {
274                 delay_cnt  = &opt.delay_srv_cnt;
275                 delay_list = opt.delay_srv;
276             }
277 
278             if( *delay_cnt == MAX_DELAYED_HS )
279             {
280                 mbedtls_printf( " too many uses of %s: only %d allowed\n",
281                                 p, MAX_DELAYED_HS );
282                 exit_usage( p, NULL );
283             }
284 
285             len = strlen( q );
286             buf = mbedtls_calloc( 1, len + 1 );
287             if( buf == NULL )
288             {
289                 mbedtls_printf( " Allocation failure\n" );
290                 exit( 1 );
291             }
292             memcpy( buf, q, len + 1 );
293 
294             delay_list[ (*delay_cnt)++ ] = buf;
295         }
296         else if( strcmp( p, "drop" ) == 0 )
297         {
298             opt.drop = atoi( q );
299             if( opt.drop < 0 || opt.drop > 20 || opt.drop == 1 )
300                 exit_usage( p, q );
301         }
302         else if( strcmp( p, "pack" ) == 0 )
303         {
304 #if defined(MBEDTLS_TIMING_C)
305             opt.pack = (unsigned) atoi( q );
306 #else
307             mbedtls_printf( " option pack only defined if MBEDTLS_TIMING_C is enabled\n" );
308             exit( 1 );
309 #endif
310         }
311         else if( strcmp( p, "mtu" ) == 0 )
312         {
313             opt.mtu = atoi( q );
314             if( opt.mtu < 0 || opt.mtu > MAX_MSG_SIZE )
315                 exit_usage( p, q );
316         }
317         else if( strcmp( p, "bad_ad" ) == 0 )
318         {
319             opt.bad_ad = atoi( q );
320             if( opt.bad_ad < 0 || opt.bad_ad > 1 )
321                 exit_usage( p, q );
322         }
323         else if( strcmp( p, "protect_hvr" ) == 0 )
324         {
325             opt.protect_hvr = atoi( q );
326             if( opt.protect_hvr < 0 || opt.protect_hvr > 1 )
327                 exit_usage( p, q );
328         }
329         else if( strcmp( p, "protect_len" ) == 0 )
330         {
331             opt.protect_len = atoi( q );
332             if( opt.protect_len < 0 )
333                 exit_usage( p, q );
334         }
335         else if( strcmp( p, "inject_clihlo" ) == 0 )
336         {
337             opt.inject_clihlo = atoi( q );
338             if( opt.inject_clihlo < 0 || opt.inject_clihlo > 1 )
339                 exit_usage( p, q );
340         }
341         else if( strcmp( p, "seed" ) == 0 )
342         {
343             opt.seed = atoi( q );
344             if( opt.seed == 0 )
345                 exit_usage( p, q );
346         }
347         else
348             exit_usage( p, NULL );
349     }
350 }
351 
msg_type(unsigned char * msg,size_t len)352 static const char *msg_type( unsigned char *msg, size_t len )
353 {
354     if( len < 1 )                           return( "Invalid" );
355     switch( msg[0] )
356     {
357         case MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC:    return( "ChangeCipherSpec" );
358         case MBEDTLS_SSL_MSG_ALERT:                 return( "Alert" );
359         case MBEDTLS_SSL_MSG_APPLICATION_DATA:      return( "ApplicationData" );
360         case MBEDTLS_SSL_MSG_HANDSHAKE:             break; /* See below */
361         default:                            return( "Unknown" );
362     }
363 
364     if( len < 13 + 12 )                     return( "Invalid handshake" );
365 
366     /*
367      * Our handshake message are less than 2^16 bytes long, so they should
368      * have 0 as the first byte of length, frag_offset and frag_length.
369      * Otherwise, assume they are encrypted.
370      */
371     if( msg[14] || msg[19] || msg[22] )     return( "Encrypted handshake" );
372 
373     switch( msg[13] )
374     {
375         case MBEDTLS_SSL_HS_HELLO_REQUEST:          return( "HelloRequest" );
376         case MBEDTLS_SSL_HS_CLIENT_HELLO:           return( "ClientHello" );
377         case MBEDTLS_SSL_HS_SERVER_HELLO:           return( "ServerHello" );
378         case MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST:   return( "HelloVerifyRequest" );
379         case MBEDTLS_SSL_HS_NEW_SESSION_TICKET:     return( "NewSessionTicket" );
380         case MBEDTLS_SSL_HS_CERTIFICATE:            return( "Certificate" );
381         case MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE:    return( "ServerKeyExchange" );
382         case MBEDTLS_SSL_HS_CERTIFICATE_REQUEST:    return( "CertificateRequest" );
383         case MBEDTLS_SSL_HS_SERVER_HELLO_DONE:      return( "ServerHelloDone" );
384         case MBEDTLS_SSL_HS_CERTIFICATE_VERIFY:     return( "CertificateVerify" );
385         case MBEDTLS_SSL_HS_CLIENT_KEY_EXCHANGE:    return( "ClientKeyExchange" );
386         case MBEDTLS_SSL_HS_FINISHED:               return( "Finished" );
387         default:                            return( "Unknown handshake" );
388     }
389 }
390 
391 #if defined(MBEDTLS_TIMING_C)
392 /* Return elapsed time in milliseconds since the first call */
ellapsed_time(void)393 static unsigned ellapsed_time( void )
394 {
395     static int initialized = 0;
396     static struct mbedtls_timing_hr_time hires;
397 
398     if( initialized == 0 )
399     {
400         (void) mbedtls_timing_get_timer( &hires, 1 );
401         initialized = 1;
402         return( 0 );
403     }
404 
405     return( mbedtls_timing_get_timer( &hires, 0 ) );
406 }
407 
408 typedef struct
409 {
410     mbedtls_net_context *ctx;
411 
412     const char *description;
413 
414     unsigned packet_lifetime;
415     unsigned num_datagrams;
416 
417     unsigned char data[MAX_MSG_SIZE];
418     size_t len;
419 
420 } ctx_buffer;
421 
422 static ctx_buffer outbuf[2];
423 
ctx_buffer_flush(ctx_buffer * buf)424 static int ctx_buffer_flush( ctx_buffer *buf )
425 {
426     int ret;
427 
428     mbedtls_printf( "  %05u flush    %s: %u bytes, %u datagrams, last %u ms\n",
429                     ellapsed_time(), buf->description,
430                     (unsigned) buf->len, buf->num_datagrams,
431                     ellapsed_time() - buf->packet_lifetime );
432 
433     ret = mbedtls_net_send( buf->ctx, buf->data, buf->len );
434 
435     buf->len           = 0;
436     buf->num_datagrams = 0;
437 
438     return( ret );
439 }
440 
ctx_buffer_time_remaining(ctx_buffer * buf)441 static unsigned ctx_buffer_time_remaining( ctx_buffer *buf )
442 {
443     unsigned const cur_time = ellapsed_time();
444 
445     if( buf->num_datagrams == 0 )
446         return( (unsigned) -1 );
447 
448     if( cur_time - buf->packet_lifetime >= opt.pack )
449         return( 0 );
450 
451     return( opt.pack - ( cur_time - buf->packet_lifetime ) );
452 }
453 
ctx_buffer_append(ctx_buffer * buf,const unsigned char * data,size_t len)454 static int ctx_buffer_append( ctx_buffer *buf,
455                               const unsigned char * data,
456                               size_t len )
457 {
458     int ret;
459 
460     if( len > (size_t) INT_MAX )
461         return( -1 );
462 
463     if( len > sizeof( buf->data ) )
464     {
465         mbedtls_printf( "  ! buffer size %u too large (max %u)\n",
466                         (unsigned) len, (unsigned) sizeof( buf->data ) );
467         return( -1 );
468     }
469 
470     if( sizeof( buf->data ) - buf->len < len )
471     {
472         if( ( ret = ctx_buffer_flush( buf ) ) <= 0 )
473             return( ret );
474     }
475 
476     memcpy( buf->data + buf->len, data, len );
477 
478     buf->len += len;
479     if( ++buf->num_datagrams == 1 )
480         buf->packet_lifetime = ellapsed_time();
481 
482     return( (int) len );
483 }
484 #endif /* MBEDTLS_TIMING_C */
485 
dispatch_data(mbedtls_net_context * ctx,const unsigned char * data,size_t len)486 static int dispatch_data( mbedtls_net_context *ctx,
487                           const unsigned char * data,
488                           size_t len )
489 {
490 #if defined(MBEDTLS_TIMING_C)
491     ctx_buffer *buf = NULL;
492     if( opt.pack > 0 )
493     {
494         if( outbuf[0].ctx == ctx )
495             buf = &outbuf[0];
496         else if( outbuf[1].ctx == ctx )
497             buf = &outbuf[1];
498 
499         if( buf == NULL )
500             return( -1 );
501 
502         return( ctx_buffer_append( buf, data, len ) );
503     }
504 #endif /* MBEDTLS_TIMING_C */
505 
506     return( mbedtls_net_send( ctx, data, len ) );
507 }
508 
509 typedef struct
510 {
511     mbedtls_net_context *dst;
512     const char *way;
513     const char *type;
514     unsigned len;
515     unsigned char buf[MAX_MSG_SIZE];
516 } packet;
517 
518 /* Print packet. Outgoing packets come with a reason (forward, dupl, etc.) */
print_packet(const packet * p,const char * why)519 void print_packet( const packet *p, const char *why )
520 {
521 #if defined(MBEDTLS_TIMING_C)
522     if( why == NULL )
523         mbedtls_printf( "  %05u dispatch %s %s (%u bytes)\n",
524                 ellapsed_time(), p->way, p->type, p->len );
525     else
526         mbedtls_printf( "  %05u dispatch %s %s (%u bytes): %s\n",
527                 ellapsed_time(), p->way, p->type, p->len, why );
528 #else
529     if( why == NULL )
530         mbedtls_printf( "        dispatch %s %s (%u bytes)\n",
531                 p->way, p->type, p->len );
532     else
533         mbedtls_printf( "        dispatch %s %s (%u bytes): %s\n",
534                 p->way, p->type, p->len, why );
535 #endif
536 
537     fflush( stdout );
538 }
539 
540 /*
541  * In order to test the server's behaviour when receiving a ClientHello after
542  * the connection is established (this could be a hard reset from the client,
543  * but the server must not drop the existing connection before establishing
544  * client reachability, see RFC 6347 Section 4.2.8), we memorize the first
545  * ClientHello we see (which can't have a cookie), then replay it after the
546  * first ApplicationData record - then we're done.
547  *
548  * This is controlled by the inject_clihlo option.
549  *
550  * We want an explicit state and a place to store the packet.
551  */
552 typedef enum {
553     ICH_INIT,       /* haven't seen the first ClientHello yet */
554     ICH_CACHED,     /* cached the initial ClientHello */
555     ICH_INJECTED,   /* ClientHello already injected, done */
556 } inject_clihlo_state_t;
557 
558 static inject_clihlo_state_t inject_clihlo_state;
559 static packet initial_clihlo;
560 
send_packet(const packet * p,const char * why)561 int send_packet( const packet *p, const char *why )
562 {
563     int ret;
564     mbedtls_net_context *dst = p->dst;
565 
566     /* save initial ClientHello? */
567     if( opt.inject_clihlo != 0 &&
568         inject_clihlo_state == ICH_INIT &&
569         strcmp( p->type, "ClientHello" ) == 0 )
570     {
571         memcpy( &initial_clihlo, p, sizeof( packet ) );
572         inject_clihlo_state = ICH_CACHED;
573     }
574 
575     /* insert corrupted ApplicationData record? */
576     if( opt.bad_ad &&
577         strcmp( p->type, "ApplicationData" ) == 0 )
578     {
579         unsigned char buf[MAX_MSG_SIZE];
580         memcpy( buf, p->buf, p->len );
581 
582         if( p->len <= 13 )
583         {
584             mbedtls_printf( "  ! can't corrupt empty AD record" );
585         }
586         else
587         {
588             ++buf[13];
589             print_packet( p, "corrupted" );
590         }
591 
592         if( ( ret = dispatch_data( dst, buf, p->len ) ) <= 0 )
593         {
594             mbedtls_printf( "  ! dispatch returned %d\n", ret );
595             return( ret );
596         }
597     }
598 
599     print_packet( p, why );
600     if( ( ret = dispatch_data( dst, p->buf, p->len ) ) <= 0 )
601     {
602         mbedtls_printf( "  ! dispatch returned %d\n", ret );
603         return( ret );
604     }
605 
606     /* Don't duplicate Application Data, only handshake covered */
607     if( opt.duplicate != 0 &&
608         strcmp( p->type, "ApplicationData" ) != 0 &&
609         rand() % opt.duplicate == 0 )
610     {
611         print_packet( p, "duplicated" );
612 
613         if( ( ret = dispatch_data( dst, p->buf, p->len ) ) <= 0 )
614         {
615             mbedtls_printf( "  ! dispatch returned %d\n", ret );
616             return( ret );
617         }
618     }
619 
620     /* Inject ClientHello after first ApplicationData */
621     if( opt.inject_clihlo != 0 &&
622         inject_clihlo_state == ICH_CACHED &&
623         strcmp( p->type, "ApplicationData" ) == 0 )
624     {
625         print_packet( &initial_clihlo, "injected" );
626 
627         if( ( ret = dispatch_data( dst, initial_clihlo.buf,
628                                         initial_clihlo.len ) ) <= 0 )
629         {
630             mbedtls_printf( "  ! dispatch returned %d\n", ret );
631             return( ret );
632         }
633 
634         inject_clihlo_state = ICH_INJECTED;
635     }
636 
637     return( 0 );
638 }
639 
640 #define MAX_DELAYED_MSG 5
641 static size_t prev_len;
642 static packet prev[MAX_DELAYED_MSG];
643 
clear_pending(void)644 void clear_pending( void )
645 {
646     memset( &prev, 0, sizeof( prev ) );
647     prev_len = 0;
648 }
649 
delay_packet(packet * delay)650 void delay_packet( packet *delay )
651 {
652     if( prev_len == MAX_DELAYED_MSG )
653         return;
654 
655     memcpy( &prev[prev_len++], delay, sizeof( packet ) );
656 }
657 
send_delayed()658 int send_delayed()
659 {
660     uint8_t offset;
661     int ret;
662     for( offset = 0; offset < prev_len; offset++ )
663     {
664         ret = send_packet( &prev[offset], "delayed" );
665         if( ret != 0 )
666             return( ret );
667     }
668 
669     clear_pending();
670     return( 0 );
671 }
672 
673 /*
674  * Avoid dropping or delaying a packet that was already dropped twice: this
675  * only results in uninteresting timeouts. We can't rely on type to identify
676  * packets, since during renegotiation they're all encrypted.  So, rely on
677  * size mod 2048 (which is usually just size).
678  */
679 static unsigned char dropped[2048] = { 0 };
680 #define DROP_MAX 2
681 
682 /* We only drop packets at the level of entire datagrams, not at the level
683  * of records. In particular, if the peer changes the way it packs multiple
684  * records into a single datagram, we don't necessarily count the number of
685  * times a record has been dropped correctly. However, the only known reason
686  * why a peer would change datagram packing is disabling the latter on
687  * retransmission, in which case we'd drop involved records at most
688  * DROP_MAX + 1 times. */
update_dropped(const packet * p)689 void update_dropped( const packet *p )
690 {
691     size_t id = p->len % sizeof( dropped );
692     ++dropped[id];
693 }
694 
handle_message(const char * way,mbedtls_net_context * dst,mbedtls_net_context * src)695 int handle_message( const char *way,
696                     mbedtls_net_context *dst,
697                     mbedtls_net_context *src )
698 {
699     int ret;
700     packet cur;
701     size_t id;
702 
703     uint8_t delay_idx;
704     char ** delay_list;
705     uint8_t delay_list_len;
706 
707     /* receive packet */
708     if( ( ret = mbedtls_net_recv( src, cur.buf, sizeof( cur.buf ) ) ) <= 0 )
709     {
710         mbedtls_printf( "  ! mbedtls_net_recv returned %d\n", ret );
711         return( ret );
712     }
713 
714     cur.len  = ret;
715     cur.type = msg_type( cur.buf, cur.len );
716     cur.way  = way;
717     cur.dst  = dst;
718     print_packet( &cur, NULL );
719 
720     id = cur.len % sizeof( dropped );
721 
722     if( strcmp( way, "S <- C" ) == 0 )
723     {
724         delay_list     = opt.delay_cli;
725         delay_list_len = opt.delay_cli_cnt;
726     }
727     else
728     {
729         delay_list     = opt.delay_srv;
730         delay_list_len = opt.delay_srv_cnt;
731     }
732 
733     /* Check if message type is in the list of messages
734      * that should be delayed */
735     for( delay_idx = 0; delay_idx < delay_list_len; delay_idx++ )
736     {
737         if( delay_list[ delay_idx ] == NULL )
738             continue;
739 
740         if( strcmp( delay_list[ delay_idx ], cur.type ) == 0 )
741         {
742             /* Delay message */
743             delay_packet( &cur );
744 
745             /* Remove entry from list */
746             mbedtls_free( delay_list[delay_idx] );
747             delay_list[delay_idx] = NULL;
748 
749             return( 0 );
750         }
751     }
752 
753     /* do we want to drop, delay, or forward it? */
754     if( ( opt.mtu != 0 &&
755           cur.len > (unsigned) opt.mtu ) ||
756         ( opt.drop != 0 &&
757           strcmp( cur.type, "ApplicationData" ) != 0 &&
758           ! ( opt.protect_hvr &&
759               strcmp( cur.type, "HelloVerifyRequest" ) == 0 ) &&
760           cur.len != (size_t) opt.protect_len &&
761           dropped[id] < DROP_MAX &&
762           rand() % opt.drop == 0 ) )
763     {
764         update_dropped( &cur );
765     }
766     else if( ( opt.delay_ccs == 1 &&
767                strcmp( cur.type, "ChangeCipherSpec" ) == 0 ) ||
768              ( opt.delay != 0 &&
769                strcmp( cur.type, "ApplicationData" ) != 0 &&
770                ! ( opt.protect_hvr &&
771                    strcmp( cur.type, "HelloVerifyRequest" ) == 0 ) &&
772                cur.len != (size_t) opt.protect_len &&
773                dropped[id] < DROP_MAX &&
774                rand() % opt.delay == 0 ) )
775     {
776         delay_packet( &cur );
777     }
778     else
779     {
780         /* forward and possibly duplicate */
781         if( ( ret = send_packet( &cur, "forwarded" ) ) != 0 )
782             return( ret );
783 
784         /* send previously delayed messages if any */
785         ret = send_delayed();
786         if( ret != 0 )
787             return( ret );
788     }
789 
790     return( 0 );
791 }
792 
main(int argc,char * argv[])793 int main( int argc, char *argv[] )
794 {
795     int ret = 1;
796     int exit_code = MBEDTLS_EXIT_FAILURE;
797     uint8_t delay_idx;
798 
799     mbedtls_net_context listen_fd, client_fd, server_fd;
800 
801 #if defined( MBEDTLS_TIMING_C )
802     struct timeval tm;
803 #endif
804 
805     struct timeval *tm_ptr = NULL;
806 
807     int nb_fds;
808     fd_set read_fds;
809 
810     mbedtls_net_init( &listen_fd );
811     mbedtls_net_init( &client_fd );
812     mbedtls_net_init( &server_fd );
813 
814     get_options( argc, argv );
815 
816     /*
817      * Decisions to drop/delay/duplicate packets are pseudo-random: dropping
818      * exactly 1 in N packets would lead to problems when a flight has exactly
819      * N packets: the same packet would be dropped on every resend.
820      *
821      * In order to be able to reproduce problems reliably, the seed may be
822      * specified explicitly.
823      */
824     if( opt.seed == 0 )
825     {
826         opt.seed = (unsigned int) time( NULL );
827         mbedtls_printf( "  . Pseudo-random seed: %u\n", opt.seed );
828     }
829 
830     srand( opt.seed );
831 
832     /*
833      * 0. "Connect" to the server
834      */
835     mbedtls_printf( "  . Connect to server on UDP/%s/%s ...",
836             opt.server_addr, opt.server_port );
837     fflush( stdout );
838 
839     if( ( ret = mbedtls_net_connect( &server_fd, opt.server_addr, opt.server_port,
840                              MBEDTLS_NET_PROTO_UDP ) ) != 0 )
841     {
842         mbedtls_printf( " failed\n  ! mbedtls_net_connect returned %d\n\n", ret );
843         goto exit;
844     }
845 
846     mbedtls_printf( " ok\n" );
847 
848     /*
849      * 1. Setup the "listening" UDP socket
850      */
851     mbedtls_printf( "  . Bind on UDP/%s/%s ...",
852             opt.listen_addr, opt.listen_port );
853     fflush( stdout );
854 
855     if( ( ret = mbedtls_net_bind( &listen_fd, opt.listen_addr, opt.listen_port,
856                           MBEDTLS_NET_PROTO_UDP ) ) != 0 )
857     {
858         mbedtls_printf( " failed\n  ! mbedtls_net_bind returned %d\n\n", ret );
859         goto exit;
860     }
861 
862     mbedtls_printf( " ok\n" );
863 
864     /*
865      * 2. Wait until a client connects
866      */
867 accept:
868     mbedtls_net_free( &client_fd );
869 
870     mbedtls_printf( "  . Waiting for a remote connection ..." );
871     fflush( stdout );
872 
873     if( ( ret = mbedtls_net_accept( &listen_fd, &client_fd,
874                                     NULL, 0, NULL ) ) != 0 )
875     {
876         mbedtls_printf( " failed\n  ! mbedtls_net_accept returned %d\n\n", ret );
877         goto exit;
878     }
879 
880     mbedtls_printf( " ok\n" );
881 
882     /*
883      * 3. Forward packets forever (kill the process to terminate it)
884      */
885     clear_pending();
886     memset( dropped, 0, sizeof( dropped ) );
887 
888     nb_fds = client_fd.fd;
889     if( nb_fds < server_fd.fd )
890         nb_fds = server_fd.fd;
891     if( nb_fds < listen_fd.fd )
892         nb_fds = listen_fd.fd;
893     ++nb_fds;
894 
895 #if defined(MBEDTLS_TIMING_C)
896     if( opt.pack > 0 )
897     {
898         outbuf[0].ctx = &server_fd;
899         outbuf[0].description = "S <- C";
900         outbuf[0].num_datagrams = 0;
901         outbuf[0].len = 0;
902 
903         outbuf[1].ctx = &client_fd;
904         outbuf[1].description = "S -> C";
905         outbuf[1].num_datagrams = 0;
906         outbuf[1].len = 0;
907     }
908 #endif /* MBEDTLS_TIMING_C */
909 
910     while( 1 )
911     {
912 #if defined(MBEDTLS_TIMING_C)
913         if( opt.pack > 0 )
914         {
915             unsigned max_wait_server, max_wait_client, max_wait;
916             max_wait_server = ctx_buffer_time_remaining( &outbuf[0] );
917             max_wait_client = ctx_buffer_time_remaining( &outbuf[1] );
918 
919             max_wait = (unsigned) -1;
920 
921             if( max_wait_server == 0 )
922                 ctx_buffer_flush( &outbuf[0] );
923             else
924                 max_wait = max_wait_server;
925 
926             if( max_wait_client == 0 )
927                 ctx_buffer_flush( &outbuf[1] );
928             else
929             {
930                 if( max_wait_client < max_wait )
931                     max_wait = max_wait_client;
932             }
933 
934             if( max_wait != (unsigned) -1 )
935             {
936                 tm.tv_sec  = max_wait / 1000;
937                 tm.tv_usec = ( max_wait % 1000 ) * 1000;
938 
939                 tm_ptr = &tm;
940             }
941             else
942             {
943                 tm_ptr = NULL;
944             }
945         }
946 #endif /* MBEDTLS_TIMING_C */
947 
948         FD_ZERO( &read_fds );
949         FD_SET( server_fd.fd, &read_fds );
950         FD_SET( client_fd.fd, &read_fds );
951         FD_SET( listen_fd.fd, &read_fds );
952 
953         if( ( ret = select( nb_fds, &read_fds, NULL, NULL, tm_ptr ) ) < 0 )
954         {
955             perror( "select" );
956             goto exit;
957         }
958 
959         if( FD_ISSET( listen_fd.fd, &read_fds ) )
960             goto accept;
961 
962         if( FD_ISSET( client_fd.fd, &read_fds ) )
963         {
964             if( ( ret = handle_message( "S <- C",
965                                         &server_fd, &client_fd ) ) != 0 )
966                 goto accept;
967         }
968 
969         if( FD_ISSET( server_fd.fd, &read_fds ) )
970         {
971             if( ( ret = handle_message( "S -> C",
972                                         &client_fd, &server_fd ) ) != 0 )
973                 goto accept;
974         }
975 
976     }
977 
978     exit_code = MBEDTLS_EXIT_SUCCESS;
979 
980 exit:
981 
982 #ifdef MBEDTLS_ERROR_C
983     if( exit_code != MBEDTLS_EXIT_SUCCESS )
984     {
985         char error_buf[100];
986         mbedtls_strerror( ret, error_buf, 100 );
987         mbedtls_printf( "Last error was: -0x%04X - %s\n\n", - ret, error_buf );
988         fflush( stdout );
989     }
990 #endif
991 
992     for( delay_idx = 0; delay_idx < MAX_DELAYED_HS; delay_idx++ )
993     {
994         mbedtls_free( opt.delay_cli + delay_idx );
995         mbedtls_free( opt.delay_srv + delay_idx );
996     }
997 
998     mbedtls_net_free( &client_fd );
999     mbedtls_net_free( &server_fd );
1000     mbedtls_net_free( &listen_fd );
1001 
1002 #if defined(_WIN32)
1003     mbedtls_printf( "  Press Enter to exit this program.\n" );
1004     fflush( stdout ); getchar();
1005 #endif
1006 
1007     mbedtls_exit( exit_code );
1008 }
1009 
1010 #endif /* MBEDTLS_NET_C */
1011