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