blob: 5d5a02ae9462c68252518c2e25aafe0e30fbe39e [file] [log] [blame]
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +02001/*
2 * UDP proxy: emulate an unreliable UDP connexion for DTLS testing
3 *
4 * Copyright (C) 2006-2014, Brainspark B.V.
5 *
6 * This file is part of PolarSSL (http://www.polarssl.org)
7 * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
8 *
9 * All rights reserved.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25
26#if !defined(POLARSSL_CONFIG_FILE)
27#include "polarssl/config.h"
28#else
29#include POLARSSL_CONFIG_FILE
30#endif
31
32#if !defined(POLARSSL_NET_C)
33#include <stdio.h>
34int main( void )
35{
36 printf( "POLARSSL_NET_C not defined.\n" );
37 return( 0 );
38}
39#else
40
41#include "polarssl/net.h"
42#include "polarssl/error.h"
Manuel Pégourié-Gonnard2c41bd82014-09-06 08:14:47 +020043#include "polarssl/ssl.h"
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +020044
45#include <stdio.h>
46#include <stdlib.h>
Manuel Pégourié-Gonnard2c41bd82014-09-06 08:14:47 +020047#include <time.h>
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +020048
49/* For select() */
50#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
51 !defined(EFI32)
52#include <winsock2.h>
53#include <windows.h>
54#if defined(_MSC_VER)
55#if defined(_WIN32_WCE)
56#pragma comment( lib, "ws2.lib" )
57#else
58#pragma comment( lib, "ws2_32.lib" )
59#endif
60#endif /* _MSC_VER */
61#else /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */
62#include <sys/time.h>
63#include <sys/types.h>
64#include <unistd.h>
65#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */
66
Manuel Pégourié-Gonnard7cf35182014-09-20 09:43:48 +020067/* For gettimeofday() */
68#if !defined(_WIN32)
69#include <sys/time.h>
70#endif
71
Manuel Pégourié-Gonnardb46780e2014-09-23 12:17:30 +020072#define MAX_MSG_SIZE 16384 + 2048 /* max record/datagram size */
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +020073
74#define DFL_SERVER_ADDR "localhost"
75#define DFL_SERVER_PORT 4433
76#define DFL_LISTEN_ADDR "localhost"
77#define DFL_LISTEN_PORT 5556
78
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +020079#define USAGE \
80 "\n usage: udp_proxy param=<>...\n" \
81 "\n acceptable parameters:\n" \
Manuel Pégourié-Gonnardd0fd1da2014-09-25 17:00:27 +020082 " server_addr=%%s default: localhost\n" \
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +020083 " server_port=%%d default: 4433\n" \
Manuel Pégourié-Gonnardd0fd1da2014-09-25 17:00:27 +020084 " listen_addr=%%s default: localhost\n" \
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +020085 " listen_port=%%d default: 4433\n" \
Manuel Pégourié-Gonnard2c41bd82014-09-06 08:14:47 +020086 "\n" \
87 " duplicate=%%d default: 0 (no duplication)\n" \
Manuel Pégourié-Gonnard992e1362014-09-20 18:06:23 +020088 " duplicate about 1:N packets randomly\n" \
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +020089 " delay=%%d default: 0 (no delayed packets)\n" \
Manuel Pégourié-Gonnard992e1362014-09-20 18:06:23 +020090 " delay about 1:N packets randomly\n" \
Manuel Pégourié-Gonnardd0fd1da2014-09-25 17:00:27 +020091 " delay_ccs=0/1 default: 0 (don't delay ChangeCipherSpec)\n" \
Manuel Pégourié-Gonnard60fdd7e2014-09-06 14:49:52 +020092 " drop=%%d default: 0 (no dropped packets)\n" \
Manuel Pégourié-Gonnard992e1362014-09-20 18:06:23 +020093 " drop about 1:N packets randomly\n" \
Manuel Pégourié-Gonnardeb00bfd2014-09-08 11:11:42 +020094 " mtu=%%d default: 0 (unlimited)\n" \
95 " drop packets larger than N bytes\n" \
Manuel Pégourié-Gonnardd0fd1da2014-09-25 17:00:27 +020096 " bad_ad=0/1 default: 0 (don't add bad ApplicationData)\n" \
97 " protect_hvr=0/1 default: 0 (don't protect HelloVerifyRequest)\n" \
Manuel Pégourié-Gonnard992e1362014-09-20 18:06:23 +020098 "\n" \
99 " seed=%%d default: (use current time)\n" \
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200100 "\n"
101
Manuel Pégourié-Gonnard44d5e632014-09-06 08:07:45 +0200102/*
103 * global options
104 */
105static struct options
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200106{
Manuel Pégourié-Gonnard44d5e632014-09-06 08:07:45 +0200107 const char *server_addr; /* address to forward packets to */
108 int server_port; /* port to forward packets to */
109 const char *listen_addr; /* address for accepting client connections */
110 int listen_port; /* port for accepting client connections */
Manuel Pégourié-Gonnard2c41bd82014-09-06 08:14:47 +0200111
112 int duplicate; /* duplicate 1 in N packets (none if 0) */
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200113 int delay; /* delay 1 packet in N (none if 0) */
Manuel Pégourié-Gonnard81f2fe92014-09-08 10:44:57 +0200114 int delay_ccs; /* delay ChangeCipherSpec */
Manuel Pégourié-Gonnard60fdd7e2014-09-06 14:49:52 +0200115 int drop; /* drop 1 packet in N (none if 0) */
Manuel Pégourié-Gonnardeb00bfd2014-09-08 11:11:42 +0200116 int mtu; /* drop packets larger than this */
Manuel Pégourié-Gonnard6c18a392014-09-08 11:24:58 +0200117 int bad_ad; /* inject corrupted ApplicationData record */
Manuel Pégourié-Gonnardd0fd1da2014-09-25 17:00:27 +0200118 int protect_hvr; /* never drop or delay HelloVerifyRequest */
Manuel Pégourié-Gonnard992e1362014-09-20 18:06:23 +0200119
120 unsigned int seed; /* seed for "random" events */
Manuel Pégourié-Gonnard44d5e632014-09-06 08:07:45 +0200121} opt;
122
123static void exit_usage( const char *name, const char *value )
124{
125 if( value == NULL )
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200126 printf( " unknown option or missing value: %s\n", name );
Manuel Pégourié-Gonnard44d5e632014-09-06 08:07:45 +0200127 else
128 printf( " option %s: illegal value: %s\n", name, value );
129
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200130 printf( USAGE );
131 exit( 1 );
132}
133
134static void get_options( int argc, char *argv[] )
135{
136 int i;
137 char *p, *q;
138
139 opt.server_addr = DFL_SERVER_ADDR;
140 opt.server_port = DFL_SERVER_PORT;
141 opt.listen_addr = DFL_LISTEN_ADDR;
142 opt.listen_port = DFL_LISTEN_PORT;
Manuel Pégourié-Gonnard60fdd7e2014-09-06 14:49:52 +0200143 /* Other members default to 0 */
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200144
145 for( i = 1; i < argc; i++ )
146 {
147 p = argv[i];
148 if( ( q = strchr( p, '=' ) ) == NULL )
Manuel Pégourié-Gonnard44d5e632014-09-06 08:07:45 +0200149 exit_usage( p, NULL );
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200150 *q++ = '\0';
151
152 if( strcmp( p, "server_addr" ) == 0 )
153 opt.server_addr = q;
154 else if( strcmp( p, "server_port" ) == 0 )
155 {
156 opt.server_port = atoi( q );
157 if( opt.server_port < 1 || opt.server_port > 65535 )
Manuel Pégourié-Gonnard44d5e632014-09-06 08:07:45 +0200158 exit_usage( p, q );
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200159 }
160 else if( strcmp( p, "listen_addr" ) == 0 )
161 opt.listen_addr = q;
162 else if( strcmp( p, "listen_port" ) == 0 )
163 {
164 opt.listen_port = atoi( q );
165 if( opt.listen_port < 1 || opt.listen_port > 65535 )
Manuel Pégourié-Gonnard44d5e632014-09-06 08:07:45 +0200166 exit_usage( p, q );
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200167 }
Manuel Pégourié-Gonnard2c41bd82014-09-06 08:14:47 +0200168 else if( strcmp( p, "duplicate" ) == 0 )
169 {
170 opt.duplicate = atoi( q );
Manuel Pégourié-Gonnard992e1362014-09-20 18:06:23 +0200171 if( opt.duplicate < 0 || opt.duplicate > 20 )
Manuel Pégourié-Gonnard2c41bd82014-09-06 08:14:47 +0200172 exit_usage( p, q );
173 }
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200174 else if( strcmp( p, "delay" ) == 0 )
175 {
176 opt.delay = atoi( q );
Manuel Pégourié-Gonnard992e1362014-09-20 18:06:23 +0200177 if( opt.delay < 0 || opt.delay > 20 || opt.delay == 1 )
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200178 exit_usage( p, q );
179 }
Manuel Pégourié-Gonnard81f2fe92014-09-08 10:44:57 +0200180 else if( strcmp( p, "delay_ccs" ) == 0 )
181 {
182 opt.delay_ccs = atoi( q );
183 if( opt.delay_ccs < 0 || opt.delay_ccs > 1 )
184 exit_usage( p, q );
185 }
Manuel Pégourié-Gonnard60fdd7e2014-09-06 14:49:52 +0200186 else if( strcmp( p, "drop" ) == 0 )
187 {
188 opt.drop = atoi( q );
Manuel Pégourié-Gonnard992e1362014-09-20 18:06:23 +0200189 if( opt.drop < 0 || opt.drop > 20 || opt.drop == 1 )
Manuel Pégourié-Gonnard60fdd7e2014-09-06 14:49:52 +0200190 exit_usage( p, q );
191 }
Manuel Pégourié-Gonnardeb00bfd2014-09-08 11:11:42 +0200192 else if( strcmp( p, "mtu" ) == 0 )
193 {
194 opt.mtu = atoi( q );
195 if( opt.mtu < 0 || opt.mtu > MAX_MSG_SIZE )
196 exit_usage( p, q );
197 }
Manuel Pégourié-Gonnard6c18a392014-09-08 11:24:58 +0200198 else if( strcmp( p, "bad_ad" ) == 0 )
199 {
200 opt.bad_ad = atoi( q );
201 if( opt.bad_ad < 0 || opt.bad_ad > 1 )
202 exit_usage( p, q );
203 }
Manuel Pégourié-Gonnardd0fd1da2014-09-25 17:00:27 +0200204 else if( strcmp( p, "protect_hvr" ) == 0 )
205 {
206 opt.protect_hvr = atoi( q );
207 if( opt.protect_hvr < 0 || opt.protect_hvr > 1 )
208 exit_usage( p, q );
209 }
Manuel Pégourié-Gonnard992e1362014-09-20 18:06:23 +0200210 else if( strcmp( p, "seed" ) == 0 )
211 {
212 opt.seed = atoi( q );
213 if( opt.seed == 0 )
214 exit_usage( p, q );
215 }
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200216 else
Manuel Pégourié-Gonnard44d5e632014-09-06 08:07:45 +0200217 exit_usage( p, NULL );
218 }
219}
220
221static const char *msg_type( unsigned char *msg, size_t len )
222{
223 if( len < 1 ) return( "Invalid" );
224 switch( msg[0] )
225 {
226 case SSL_MSG_CHANGE_CIPHER_SPEC: return( "ChangeCipherSpec" );
227 case SSL_MSG_ALERT: return( "Alert" );
228 case SSL_MSG_APPLICATION_DATA: return( "ApplicationData" );
229 case SSL_MSG_HANDSHAKE: break; /* See below */
230 default: return( "Unknown" );
231 }
232
Manuel Pégourié-Gonnard8cc7e032014-09-25 12:59:05 +0200233 if( len < 13 + 12 ) return( "Invalid handshake" );
234
235 /*
236 * Our handshake message are less than 2^16 bytes long, so they should
237 * have 0 as the first byte of length, frag_offset and frag_length.
238 * Otherwise, assume they are encrypted.
239 */
240 if( msg[14] || msg[19] || msg[22] ) return( "Encrypted handshake" );
241
Manuel Pégourié-Gonnard44d5e632014-09-06 08:07:45 +0200242 switch( msg[13] )
243 {
244 case SSL_HS_HELLO_REQUEST: return( "HelloRequest" );
245 case SSL_HS_CLIENT_HELLO: return( "ClientHello" );
246 case SSL_HS_SERVER_HELLO: return( "ServerHello" );
247 case SSL_HS_HELLO_VERIFY_REQUEST: return( "HelloVerifyRequest" );
248 case SSL_HS_NEW_SESSION_TICKET: return( "NewSessionTicket" );
249 case SSL_HS_CERTIFICATE: return( "Certificate" );
250 case SSL_HS_SERVER_KEY_EXCHANGE: return( "ServerKeyExchange" );
251 case SSL_HS_CERTIFICATE_REQUEST: return( "CertificateRequest" );
252 case SSL_HS_SERVER_HELLO_DONE: return( "ServerHelloDone" );
253 case SSL_HS_CERTIFICATE_VERIFY: return( "CertificateVerify" );
254 case SSL_HS_CLIENT_KEY_EXCHANGE: return( "ClientKeyExchange" );
255 case SSL_HS_FINISHED: return( "Finished" );
Manuel Pégourié-Gonnardbc010a02014-09-20 12:40:51 +0200256 default: return( "Unknown handshake" );
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200257 }
258}
259
Manuel Pégourié-Gonnard7cf35182014-09-20 09:43:48 +0200260/* Return elapsed time in milliseconds since the first call */
261static unsigned long ellapsed_time( void )
262{
263#if defined(_WIN32)
264 return( 0 );
265#else
266 static struct timeval ref = { 0, 0 };
267 struct timeval now;
268
269 if( ref.tv_sec == 0 && ref.tv_usec == 0 )
270 {
271 gettimeofday( &ref, NULL );
272 return( 0 );
273 }
274
275 gettimeofday( &now, NULL );
276 return( 1000 * ( now.tv_sec - ref.tv_sec )
277 + ( now.tv_usec - ref.tv_usec ) / 1000 );
278#endif
279}
280
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200281typedef struct
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200282{
Manuel Pégourié-Gonnard6265d302014-09-24 17:42:09 +0200283 int dst;
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200284 const char *way;
Manuel Pégourié-Gonnard2c41bd82014-09-06 08:14:47 +0200285 const char *type;
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200286 unsigned len;
287 unsigned char buf[MAX_MSG_SIZE];
288} packet;
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200289
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200290/* Print packet. Outgoing packets come with a reason (forward, dupl, etc.) */
291void print_packet( const packet *p, const char *why )
292{
293 if( why == NULL )
Manuel Pégourié-Gonnard7cf35182014-09-20 09:43:48 +0200294 printf( " %05lu %s %s (%u bytes)\n",
295 ellapsed_time(), p->way, p->type, p->len );
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200296 else
Manuel Pégourié-Gonnard7cf35182014-09-20 09:43:48 +0200297 printf( " %s %s (%u bytes): %s\n",
298 p->way, p->type, p->len, why );
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200299 fflush( stdout );
300}
301
302int send_packet( const packet *p, const char *why )
303{
304 int ret;
Manuel Pégourié-Gonnard6265d302014-09-24 17:42:09 +0200305 int dst = p->dst;
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200306
Manuel Pégourié-Gonnard6c18a392014-09-08 11:24:58 +0200307 /* insert corrupted ApplicationData record? */
308 if( opt.bad_ad &&
309 strcmp( p->type, "ApplicationData" ) == 0 )
310 {
311 unsigned char buf[MAX_MSG_SIZE];
312 memcpy( buf, p->buf, p->len );
313 ++buf[p->len - 1];
314
315 print_packet( p, "corrupted" );
Manuel Pégourié-Gonnard6265d302014-09-24 17:42:09 +0200316 if( ( ret = net_send( &dst, buf, p->len ) ) <= 0 )
Manuel Pégourié-Gonnard6c18a392014-09-08 11:24:58 +0200317 {
318 printf( " ! net_send returned %d\n", ret );
319 return( ret );
320 }
321 }
322
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200323 print_packet( p, why );
Manuel Pégourié-Gonnard6265d302014-09-24 17:42:09 +0200324 if( ( ret = net_send( &dst, p->buf, p->len ) ) <= 0 )
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200325 {
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200326 printf( " ! net_send returned %d\n", ret );
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200327 return( ret );
328 }
329
Manuel Pégourié-Gonnard2c41bd82014-09-06 08:14:47 +0200330 /* Don't duplicate Application Data, only handshake covered */
Manuel Pégourié-Gonnard2c41bd82014-09-06 08:14:47 +0200331 if( opt.duplicate != 0 &&
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200332 strcmp( p->type, "ApplicationData" ) != 0 &&
Manuel Pégourié-Gonnard992e1362014-09-20 18:06:23 +0200333 rand() % opt.duplicate == 0 )
Manuel Pégourié-Gonnard2c41bd82014-09-06 08:14:47 +0200334 {
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200335 print_packet( p, "duplicated" );
Manuel Pégourié-Gonnard2c41bd82014-09-06 08:14:47 +0200336
Manuel Pégourié-Gonnard6265d302014-09-24 17:42:09 +0200337 if( ( ret = net_send( &dst, p->buf, p->len ) ) <= 0 )
Manuel Pégourié-Gonnard2c41bd82014-09-06 08:14:47 +0200338 {
339 printf( " ! net_send returned %d\n", ret );
340 return( ret );
341 }
342 }
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200343
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200344 return( 0 );
345}
346
Manuel Pégourié-Gonnard6312e0f2014-09-23 12:46:33 +0200347static packet prev;
348
349void clear_pending( void )
350{
351 memset( &prev, 0, sizeof( packet ) );
352}
353
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200354int handle_message( const char *way, int dst, int src )
355{
356 int ret;
357 packet cur;
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200358
Manuel Pégourié-Gonnard63eca932014-09-08 16:39:08 +0200359 /* receive packet */
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200360 if( ( ret = net_recv( &src, cur.buf, sizeof( cur.buf ) ) ) <= 0 )
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200361 {
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200362 printf( " ! net_recv returned %d\n", ret );
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200363 return( ret );
364 }
365
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200366 cur.len = ret;
367 cur.type = msg_type( cur.buf, cur.len );
368 cur.way = way;
Manuel Pégourié-Gonnard6265d302014-09-24 17:42:09 +0200369 cur.dst = dst;
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200370 print_packet( &cur, NULL );
371
Manuel Pégourié-Gonnard60fdd7e2014-09-06 14:49:52 +0200372 /* do we want to drop, delay, or forward it? */
Manuel Pégourié-Gonnardeb00bfd2014-09-08 11:11:42 +0200373 if( ( opt.mtu != 0 &&
374 cur.len > (unsigned) opt.mtu ) ||
375 ( opt.drop != 0 &&
376 strcmp( cur.type, "ApplicationData" ) != 0 &&
Manuel Pégourié-Gonnardd0fd1da2014-09-25 17:00:27 +0200377 ! ( opt.protect_hvr &&
378 strcmp( cur.type, "HelloVerifyRequest" ) == 0 ) &&
Manuel Pégourié-Gonnard992e1362014-09-20 18:06:23 +0200379 rand() % opt.drop == 0 ) )
Manuel Pégourié-Gonnard60fdd7e2014-09-06 14:49:52 +0200380 {
Manuel Pégourié-Gonnard992e1362014-09-20 18:06:23 +0200381 ; /* Nothing to do */
Manuel Pégourié-Gonnard60fdd7e2014-09-06 14:49:52 +0200382 }
Manuel Pégourié-Gonnard81f2fe92014-09-08 10:44:57 +0200383 else if( ( opt.delay_ccs == 1 &&
384 strcmp( cur.type, "ChangeCipherSpec" ) == 0 ) ||
385 ( opt.delay != 0 &&
386 strcmp( cur.type, "ApplicationData" ) != 0 &&
Manuel Pégourié-Gonnardd0fd1da2014-09-25 17:00:27 +0200387 ! ( opt.protect_hvr &&
388 strcmp( cur.type, "HelloVerifyRequest" ) == 0 ) &&
Manuel Pégourié-Gonnard6265d302014-09-24 17:42:09 +0200389 prev.dst == 0 &&
Manuel Pégourié-Gonnard992e1362014-09-20 18:06:23 +0200390 rand() % opt.delay == 0 ) )
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200391 {
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200392 memcpy( &prev, &cur, sizeof( packet ) );
393 }
394 else
395 {
Manuel Pégourié-Gonnard60fdd7e2014-09-06 14:49:52 +0200396 /* forward and possibly duplicate */
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200397 if( ( ret = send_packet( &cur, "forwarded" ) ) != 0 )
398 return( ret );
399
400 /* send previously delayed message if any */
Manuel Pégourié-Gonnard6265d302014-09-24 17:42:09 +0200401 if( prev.dst != 0 )
Manuel Pégourié-Gonnard21398c32014-09-06 14:36:46 +0200402 {
403 ret = send_packet( &prev, "delayed" );
404 memset( &prev, 0, sizeof( packet ) );
405 if( ret != 0 )
406 return( ret );
407 }
408 }
409
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200410 return( 0 );
411}
412
413int main( int argc, char *argv[] )
414{
415 int ret;
416
417 int listen_fd = -1;
418 int client_fd = -1;
419 int server_fd = -1;
420
421 int nb_fds;
422 fd_set read_fds;
423
424 get_options( argc, argv );
Manuel Pégourié-Gonnard992e1362014-09-20 18:06:23 +0200425
426 /*
427 * Decisions to drop/delay/duplicate packets are pseudo-random: dropping
428 * exactly 1 in N packets would lead to problems when a flight has exactly
429 * N packets: the same packet would be dropped on every resend.
430 *
431 * In order to be able to reproduce problems reliably, the seed may be
432 * specified explicitly.
433 */
434 if( opt.seed == 0 )
435 {
436 opt.seed = time( NULL );
437 printf( " . Pseudo-random seed: %u\n", opt.seed );
438 }
439
440 srand( opt.seed );
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200441
442 /*
Manuel Pégourié-Gonnard44d5e632014-09-06 08:07:45 +0200443 * 0. "Connect" to the server
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200444 */
445 printf( " . Connect to server on UDP/%s/%d ...",
446 opt.server_addr, opt.server_port );
447 fflush( stdout );
448
449 if( ( ret = net_connect( &server_fd, opt.server_addr, opt.server_port,
450 NET_PROTO_UDP ) ) != 0 )
451 {
452 printf( " failed\n ! net_connect returned %d\n\n", ret );
453 goto exit;
454 }
455
456 printf( " ok\n" );
457
458 /*
459 * 1. Setup the "listening" UDP socket
460 */
461 printf( " . Bind on UDP/%s/%d ...",
462 opt.listen_addr, opt.listen_port );
463 fflush( stdout );
464
465 if( ( ret = net_bind( &listen_fd, opt.listen_addr, opt.listen_port,
466 NET_PROTO_UDP ) ) != 0 )
467 {
468 printf( " failed\n ! net_bind returned %d\n\n", ret );
469 goto exit;
470 }
471
472 printf( " ok\n" );
473
474 /*
475 * 2. Wait until a client connects
476 */
Manuel Pégourié-Gonnard6312e0f2014-09-23 12:46:33 +0200477accept:
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200478 printf( " . Waiting for a remote connection ..." );
479 fflush( stdout );
480
481 if( ( ret = net_accept( listen_fd, &client_fd, NULL ) ) != 0 )
482 {
483 printf( " failed\n ! net_accept returned %d\n\n", ret );
484 goto exit;
485 }
486
487 printf( " ok\n" );
488 fflush( stdout );
489
Manuel Pégourié-Gonnard6312e0f2014-09-23 12:46:33 +0200490 printf( " . Re-bind on UDP/%s/%d ...",
491 opt.listen_addr, opt.listen_port );
492 fflush( stdout );
493
494 if( ( ret = net_bind( &listen_fd, opt.listen_addr, opt.listen_port,
495 NET_PROTO_UDP ) ) != 0 )
496 {
497 printf( " failed\n ! net_bind returned %d\n\n", ret );
498 goto exit;
499 }
500
501 printf( " ok\n" );
502
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200503 /*
504 * 3. Forward packets forever (kill the process to terminate it)
505 */
Manuel Pégourié-Gonnard6312e0f2014-09-23 12:46:33 +0200506 nb_fds = client_fd;
507 if( nb_fds < server_fd )
508 nb_fds = server_fd;
509 if( nb_fds < listen_fd )
510 nb_fds = listen_fd;
511 ++nb_fds;
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200512
513 while( 1 )
514 {
515 FD_ZERO( &read_fds );
516 FD_SET( server_fd, &read_fds );
517 FD_SET( client_fd, &read_fds );
Manuel Pégourié-Gonnard6312e0f2014-09-23 12:46:33 +0200518 FD_SET( listen_fd, &read_fds );
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200519
520 if( ( ret = select( nb_fds, &read_fds, NULL, NULL, NULL ) ) <= 0 )
521 {
522 perror( "select" );
523 goto exit;
524 }
525
Manuel Pégourié-Gonnard6312e0f2014-09-23 12:46:33 +0200526 if( FD_ISSET( listen_fd, &read_fds ) )
527 {
528 clear_pending();
529 goto accept;
530 }
531
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200532 if( FD_ISSET( client_fd, &read_fds ) )
533 {
Manuel Pégourié-Gonnard7cf35182014-09-20 09:43:48 +0200534 if( ( ret = handle_message( "S <- C",
535 server_fd, client_fd ) ) != 0 )
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200536 goto exit;
537 }
538
539 if( FD_ISSET( server_fd, &read_fds ) )
540 {
Manuel Pégourié-Gonnard7cf35182014-09-20 09:43:48 +0200541 if( ( ret = handle_message( "S -> C",
542 client_fd, server_fd ) ) != 0 )
Manuel Pégourié-Gonnardcb4137b2014-09-04 14:55:28 +0200543 goto exit;
544 }
545 }
546
547exit:
548
549#ifdef POLARSSL_ERROR_C
550 if( ret != 0 )
551 {
552 char error_buf[100];
553 polarssl_strerror( ret, error_buf, 100 );
554 printf( "Last error was: -0x%04X - %s\n\n", - ret, error_buf );
555 fflush( stdout );
556 }
557#endif
558
559 if( client_fd != -1 )
560 net_close( client_fd );
561
562 if( listen_fd != -1 )
563 net_close( listen_fd );
564
565#if defined(_WIN32)
566 printf( " Press Enter to exit this program.\n" );
567 fflush( stdout ); getchar();
568#endif
569
570 return( ret != 0 );
571}
572
573#endif /* POLARSSL_NET_C */