1 /* 2 * iperf, Copyright (c) 2014-2019, The Regents of the University of 3 * California, through Lawrence Berkeley National Laboratory (subject 4 * to receipt of any required approvals from the U.S. Dept. of 5 * Energy). All rights reserved. 6 * 7 * If you have questions about your rights to use or distribute this 8 * software, please contact Berkeley Lab's Technology Transfer 9 * Department at TTD@lbl.gov. 10 * 11 * NOTICE. This software is owned by the U.S. Department of Energy. 12 * As such, the U.S. Government has been granted for itself and others 13 * acting on its behalf a paid-up, nonexclusive, irrevocable, 14 * worldwide license in the Software to reproduce, prepare derivative 15 * works, and perform publicly and display publicly. Beginning five 16 * (5) years after the date permission to assert copyright is obtained 17 * from the U.S. Department of Energy, and subject to any subsequent 18 * five (5) year renewals, the U.S. Government is granted for itself 19 * and others acting on its behalf a paid-up, nonexclusive, 20 * irrevocable, worldwide license in the Software to reproduce, 21 * prepare derivative works, distribute copies to the public, perform 22 * publicly and display publicly, and to permit others to do so. 23 * 24 * This code is distributed under a BSD style license, see the LICENSE 25 * file for complete information. 26 */ 27 #include "iperf_config.h" 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <errno.h> 33 #include <unistd.h> 34 #include <sys/socket.h> 35 #include <sys/types.h> 36 #include <netinet/in.h> 37 #include <netdb.h> 38 #include <sys/time.h> 39 #include <sys/select.h> 40 #include <limits.h> 41 42 #ifdef HAVE_NETINET_SCTP_H 43 #include <netinet/sctp.h> 44 #endif /* HAVE_NETINET_SCTP_H */ 45 46 #include "iperf.h" 47 #include "iperf_api.h" 48 #include "iperf_sctp.h" 49 #include "net.h" 50 51 52 53 /* iperf_sctp_recv 54 * 55 * receives the data for SCTP 56 */ 57 int 58 iperf_sctp_recv(struct iperf_stream *sp) 59 { 60 #if defined(HAVE_SCTP) 61 int r; 62 63 r = Nread(sp->socket, sp->buffer, sp->settings->blksize, Psctp); 64 if (r < 0) 65 return r; 66 67 /* Only count bytes received while we're in the correct state. */ 68 if (sp->test->state == TEST_RUNNING) { 69 sp->result->bytes_received += r; 70 sp->result->bytes_received_this_interval += r; 71 } 72 else { 73 if (sp->test->debug) 74 printf("Late receive, state = %d\n", sp->test->state); 75 } 76 77 return r; 78 #else 79 i_errno = IENOSCTP; 80 return -1; 81 #endif /* HAVE_SCTP */ 82 } 83 84 85 /* iperf_sctp_send 86 * 87 * sends the data for SCTP 88 */ 89 int 90 iperf_sctp_send(struct iperf_stream *sp) 91 { 92 #if defined(HAVE_SCTP) 93 int r; 94 95 r = Nwrite(sp->socket, sp->buffer, sp->settings->blksize, Psctp); 96 if (r < 0) 97 return r; 98 99 sp->result->bytes_sent += r; 100 sp->result->bytes_sent_this_interval += r; 101 102 return r; 103 #else 104 i_errno = IENOSCTP; 105 return -1; 106 #endif /* HAVE_SCTP */ 107 } 108 109 110 111 /* iperf_sctp_accept 112 * 113 * accept a new SCTP stream connection 114 */ 115 int 116 iperf_sctp_accept(struct iperf_test * test) 117 { 118 #if defined(HAVE_SCTP) 119 int s; 120 signed char rbuf = ACCESS_DENIED; 121 char cookie[COOKIE_SIZE]; 122 socklen_t len; 123 struct sockaddr_storage addr; 124 125 len = sizeof(addr); 126 s = accept(test->listener, (struct sockaddr *) &addr, &len); 127 if (s < 0) { 128 i_errno = IESTREAMCONNECT; 129 return -1; 130 } 131 132 if (Nread(s, cookie, COOKIE_SIZE, Psctp) < 0) { 133 i_errno = IERECVCOOKIE; 134 return -1; 135 } 136 137 if (strcmp(test->cookie, cookie) != 0) { 138 if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Psctp) < 0) { 139 i_errno = IESENDMESSAGE; 140 return -1; 141 } 142 close(s); 143 } 144 145 return s; 146 #else 147 i_errno = IENOSCTP; 148 return -1; 149 #endif /* HAVE_SCTP */ 150 } 151 152 153 /* iperf_sctp_listen 154 * 155 * start up a listener for SCTP stream connections 156 */ 157 int 158 iperf_sctp_listen(struct iperf_test *test) 159 { 160 #if defined(HAVE_SCTP) 161 struct addrinfo hints, *res; 162 char portstr[6]; 163 int s, opt, saved_errno; 164 165 close(test->listener); 166 167 snprintf(portstr, 6, "%d", test->server_port); 168 memset(&hints, 0, sizeof(hints)); 169 /* 170 * If binding to the wildcard address with no explicit address 171 * family specified, then force us to get an AF_INET6 socket. 172 * More details in the comments in netanounce(). 173 */ 174 if (test->settings->domain == AF_UNSPEC && !test->bind_address) { 175 hints.ai_family = AF_INET6; 176 } else { 177 hints.ai_family = test->settings->domain; 178 } 179 hints.ai_socktype = SOCK_STREAM; 180 hints.ai_flags = AI_PASSIVE; 181 if ((gerror = getaddrinfo(test->bind_address, portstr, &hints, &res)) != 0) { 182 i_errno = IESTREAMLISTEN; 183 return -1; 184 } 185 186 if ((s = socket(res->ai_family, SOCK_STREAM, IPPROTO_SCTP)) < 0) { 187 freeaddrinfo(res); 188 i_errno = IESTREAMLISTEN; 189 return -1; 190 } 191 192 #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__) 193 if (res->ai_family == AF_INET6 && (test->settings->domain == AF_UNSPEC || 194 test->settings->domain == AF_INET6)) { 195 if (test->settings->domain == AF_UNSPEC) 196 opt = 0; 197 else 198 opt = 1; 199 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, 200 (char *) &opt, sizeof(opt)) < 0) { 201 saved_errno = errno; 202 close(s); 203 freeaddrinfo(res); 204 errno = saved_errno; 205 i_errno = IEPROTOCOL; 206 return -1; 207 } 208 } 209 #endif /* IPV6_V6ONLY */ 210 211 opt = 1; 212 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { 213 saved_errno = errno; 214 close(s); 215 freeaddrinfo(res); 216 errno = saved_errno; 217 i_errno = IEREUSEADDR; 218 return -1; 219 } 220 221 /* servers must call sctp_bindx() _instead_ of bind() */ 222 if (!TAILQ_EMPTY(&test->xbind_addrs)) { 223 freeaddrinfo(res); 224 if (iperf_sctp_bindx(test, s, IPERF_SCTP_SERVER)) 225 return -1; 226 } else 227 if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) { 228 saved_errno = errno; 229 close(s); 230 freeaddrinfo(res); 231 errno = saved_errno; 232 i_errno = IESTREAMLISTEN; 233 return -1; 234 } 235 236 freeaddrinfo(res); 237 238 if (listen(s, INT_MAX) < 0) { 239 i_errno = IESTREAMLISTEN; 240 return -1; 241 } 242 243 test->listener = s; 244 245 return s; 246 #else 247 i_errno = IENOSCTP; 248 return -1; 249 #endif /* HAVE_SCTP */ 250 } 251 252 253 /* iperf_sctp_connect 254 * 255 * connect to a SCTP stream listener 256 */ 257 int 258 iperf_sctp_connect(struct iperf_test *test) 259 { 260 #if defined(HAVE_SCTP) 261 int s, opt, saved_errno; 262 char portstr[6]; 263 struct addrinfo hints, *local_res, *server_res; 264 265 if (test->bind_address) { 266 memset(&hints, 0, sizeof(hints)); 267 hints.ai_family = test->settings->domain; 268 hints.ai_socktype = SOCK_STREAM; 269 if ((gerror = getaddrinfo(test->bind_address, NULL, &hints, &local_res)) != 0) { 270 i_errno = IESTREAMCONNECT; 271 return -1; 272 } 273 } 274 275 memset(&hints, 0, sizeof(hints)); 276 hints.ai_family = test->settings->domain; 277 hints.ai_socktype = SOCK_STREAM; 278 snprintf(portstr, sizeof(portstr), "%d", test->server_port); 279 if ((gerror = getaddrinfo(test->server_hostname, portstr, &hints, &server_res)) != 0) { 280 if (test->bind_address) 281 freeaddrinfo(local_res); 282 i_errno = IESTREAMCONNECT; 283 return -1; 284 } 285 286 s = socket(server_res->ai_family, SOCK_STREAM, IPPROTO_SCTP); 287 if (s < 0) { 288 if (test->bind_address) 289 freeaddrinfo(local_res); 290 freeaddrinfo(server_res); 291 i_errno = IESTREAMCONNECT; 292 return -1; 293 } 294 295 /* 296 * Various ways to bind the local end of the connection. 297 * 1. --bind (with or without --cport). 298 */ 299 if (test->bind_address) { 300 struct sockaddr_in *lcladdr; 301 lcladdr = (struct sockaddr_in *)local_res->ai_addr; 302 lcladdr->sin_port = htons(test->bind_port); 303 304 if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) { 305 saved_errno = errno; 306 close(s); 307 freeaddrinfo(local_res); 308 freeaddrinfo(server_res); 309 errno = saved_errno; 310 i_errno = IESTREAMCONNECT; 311 return -1; 312 } 313 freeaddrinfo(local_res); 314 } 315 /* --cport, no --bind */ 316 else if (test->bind_port) { 317 size_t addrlen; 318 struct sockaddr_storage lcl; 319 320 /* IPv4 */ 321 if (server_res->ai_family == AF_INET) { 322 struct sockaddr_in *lcladdr = (struct sockaddr_in *) &lcl; 323 lcladdr->sin_family = AF_INET; 324 lcladdr->sin_port = htons(test->bind_port); 325 lcladdr->sin_addr.s_addr = INADDR_ANY; 326 addrlen = sizeof(struct sockaddr_in); 327 } 328 /* IPv6 */ 329 else if (server_res->ai_family == AF_INET6) { 330 struct sockaddr_in6 *lcladdr = (struct sockaddr_in6 *) &lcl; 331 lcladdr->sin6_family = AF_INET6; 332 lcladdr->sin6_port = htons(test->bind_port); 333 lcladdr->sin6_addr = in6addr_any; 334 addrlen = sizeof(struct sockaddr_in6); 335 } 336 /* Unknown protocol */ 337 else { 338 saved_errno = errno; 339 close(s); 340 freeaddrinfo(server_res); 341 errno = saved_errno; 342 i_errno = IEPROTOCOL; 343 return -1; 344 } 345 346 if (bind(s, (struct sockaddr *) &lcl, addrlen) < 0) { 347 saved_errno = errno; 348 close(s); 349 freeaddrinfo(server_res); 350 errno = saved_errno; 351 i_errno = IESTREAMCONNECT; 352 return -1; 353 } 354 } 355 356 if (test->no_delay != 0) { 357 opt = 1; 358 if (setsockopt(s, IPPROTO_SCTP, SCTP_NODELAY, &opt, sizeof(opt)) < 0) { 359 saved_errno = errno; 360 close(s); 361 freeaddrinfo(server_res); 362 errno = saved_errno; 363 i_errno = IESETNODELAY; 364 return -1; 365 } 366 } 367 368 if ((test->settings->mss >= 512 && test->settings->mss <= 131072)) { 369 370 /* 371 * Some platforms use a struct sctp_assoc_value as the 372 * argument to SCTP_MAXSEG. Other (older API implementations) 373 * take an int. FreeBSD 10 and CentOS 6 support SCTP_MAXSEG, 374 * but OpenSolaris 11 doesn't. 375 */ 376 #ifdef HAVE_STRUCT_SCTP_ASSOC_VALUE 377 struct sctp_assoc_value av; 378 379 /* 380 * Some platforms support SCTP_FUTURE_ASSOC, others need to 381 * (equivalently) do 0 here. FreeBSD 10 is an example of the 382 * former, CentOS 6 Linux is an example of the latter. 383 */ 384 #ifdef SCTP_FUTURE_ASSOC 385 av.assoc_id = SCTP_FUTURE_ASSOC; 386 #else 387 av.assoc_id = 0; 388 #endif 389 av.assoc_value = test->settings->mss; 390 391 if (setsockopt(s, IPPROTO_SCTP, SCTP_MAXSEG, &av, sizeof(av)) < 0) { 392 saved_errno = errno; 393 close(s); 394 freeaddrinfo(server_res); 395 errno = saved_errno; 396 i_errno = IESETMSS; 397 return -1; 398 } 399 #else 400 opt = test->settings->mss; 401 402 /* 403 * Solaris might not support this option. If it doesn't work, 404 * ignore the error (at least for now). 405 */ 406 if (setsockopt(s, IPPROTO_SCTP, SCTP_MAXSEG, &opt, sizeof(opt)) < 0 && 407 errno != ENOPROTOOPT) { 408 saved_errno = errno; 409 close(s); 410 freeaddrinfo(server_res); 411 errno = saved_errno; 412 i_errno = IESETMSS; 413 return -1; 414 } 415 #endif /* HAVE_STRUCT_SCTP_ASSOC_VALUE */ 416 } 417 418 if (test->settings->num_ostreams > 0) { 419 struct sctp_initmsg initmsg; 420 421 memset(&initmsg, 0, sizeof(struct sctp_initmsg)); 422 initmsg.sinit_num_ostreams = test->settings->num_ostreams; 423 424 if (setsockopt(s, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(struct sctp_initmsg)) < 0) { 425 saved_errno = errno; 426 close(s); 427 freeaddrinfo(server_res); 428 errno = saved_errno; 429 i_errno = IESETSCTPNSTREAM; 430 return -1; 431 } 432 } 433 434 /* clients must call bind() followed by sctp_bindx() before connect() */ 435 if (!TAILQ_EMPTY(&test->xbind_addrs)) { 436 if (iperf_sctp_bindx(test, s, IPERF_SCTP_CLIENT)) 437 return -1; 438 } 439 440 /* TODO support sctp_connectx() to avoid heartbeating. */ 441 if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) { 442 saved_errno = errno; 443 close(s); 444 freeaddrinfo(server_res); 445 errno = saved_errno; 446 i_errno = IESTREAMCONNECT; 447 return -1; 448 } 449 freeaddrinfo(server_res); 450 451 /* Send cookie for verification */ 452 if (Nwrite(s, test->cookie, COOKIE_SIZE, Psctp) < 0) { 453 saved_errno = errno; 454 close(s); 455 errno = saved_errno; 456 i_errno = IESENDCOOKIE; 457 return -1; 458 } 459 460 /* 461 * We want to allow fragmentation. But there's at least one 462 * implementation (Solaris) that doesn't support this option, 463 * even though it defines SCTP_DISABLE_FRAGMENTS. So we have to 464 * try setting the option and ignore the error, if it doesn't 465 * work. 466 */ 467 opt = 0; 468 if (setsockopt(s, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &opt, sizeof(opt)) < 0 && 469 errno != ENOPROTOOPT) { 470 saved_errno = errno; 471 close(s); 472 freeaddrinfo(server_res); 473 errno = saved_errno; 474 i_errno = IESETSCTPDISABLEFRAG; 475 return -1; 476 } 477 478 return s; 479 #else 480 i_errno = IENOSCTP; 481 return -1; 482 #endif /* HAVE_SCTP */ 483 } 484 485 486 487 int 488 iperf_sctp_init(struct iperf_test *test) 489 { 490 #if defined(HAVE_SCTP) 491 return 0; 492 #else 493 i_errno = IENOSCTP; 494 return -1; 495 #endif /* HAVE_SCTP */ 496 } 497 498 499 500 /* iperf_sctp_bindx 501 * 502 * handle binding to multiple endpoints (-X parameters) 503 */ 504 int 505 iperf_sctp_bindx(struct iperf_test *test, int s, int is_server) 506 { 507 #if defined(HAVE_SCTP) 508 struct addrinfo hints; 509 char portstr[6]; 510 char *servname; 511 struct addrinfo *ai, *ai0; 512 struct sockaddr *xaddrs; 513 struct xbind_entry *xbe, *xbe0; 514 char *bp; 515 size_t xaddrlen; 516 int nxaddrs; 517 int retval; 518 int domain; 519 int saved_errno; 520 521 domain = test->settings->domain; 522 xbe0 = NULL; 523 retval = 0; 524 525 if (TAILQ_EMPTY(&test->xbind_addrs)) 526 return retval; /* nothing to do */ 527 528 memset(&hints, 0, sizeof(hints)); 529 hints.ai_family = (domain == AF_UNSPEC ? AF_INET6 : domain); 530 hints.ai_socktype = SOCK_STREAM; 531 servname = NULL; 532 if (is_server) { 533 hints.ai_flags |= AI_PASSIVE; 534 snprintf(portstr, 6, "%d", test->server_port); 535 servname = portstr; 536 } 537 538 /* client: must pop first -X address and call bind(). 539 * sctp_bindx() must see the ephemeral port chosen by bind(). 540 * we deliberately ignore the -B argument in this case. 541 */ 542 if (!is_server) { 543 struct sockaddr *sa; 544 struct sockaddr_in *sin; 545 struct sockaddr_in6 *sin6; 546 int eport; 547 548 xbe0 = TAILQ_FIRST(&test->xbind_addrs); 549 TAILQ_REMOVE(&test->xbind_addrs, xbe0, link); 550 551 if ((gerror = getaddrinfo(xbe0->name, servname, &hints, &xbe0->ai)) != 0) { 552 i_errno = IESETSCTPBINDX; 553 retval = -1; 554 goto out; 555 } 556 557 ai = xbe0->ai; 558 if (domain != AF_UNSPEC && domain != ai->ai_family) { 559 i_errno = IESETSCTPBINDX; 560 retval = -1; 561 goto out; 562 } 563 if (bind(s, (struct sockaddr *)ai->ai_addr, ai->ai_addrlen) < 0) { 564 i_errno = IESETSCTPBINDX; 565 retval = -1; 566 goto out; 567 } 568 569 /* if only one -X argument, nothing more to do */ 570 if (TAILQ_EMPTY(&test->xbind_addrs)) 571 goto out; 572 573 sa = (struct sockaddr *)ai->ai_addr; 574 if (sa->sa_family == AF_INET) { 575 sin = (struct sockaddr_in *)ai->ai_addr; 576 eport = sin->sin_port; 577 } else if (sa->sa_family == AF_INET6) { 578 sin6 = (struct sockaddr_in6 *)ai->ai_addr; 579 eport = sin6->sin6_port; 580 } else { 581 i_errno = IESETSCTPBINDX; 582 retval = -1; 583 goto out; 584 } 585 snprintf(portstr, 6, "%d", ntohs(eport)); 586 servname = portstr; 587 } 588 589 /* pass 1: resolve and compute lengths. */ 590 nxaddrs = 0; 591 xaddrlen = 0; 592 TAILQ_FOREACH(xbe, &test->xbind_addrs, link) { 593 if (xbe->ai != NULL) 594 freeaddrinfo(xbe->ai); 595 if ((gerror = getaddrinfo(xbe->name, servname, &hints, &xbe->ai)) != 0) { 596 i_errno = IESETSCTPBINDX; 597 retval = -1; 598 goto out; 599 } 600 ai0 = xbe->ai; 601 for (ai = ai0; ai; ai = ai->ai_next) { 602 if (domain != AF_UNSPEC && domain != ai->ai_family) 603 continue; 604 xaddrlen += ai->ai_addrlen; 605 ++nxaddrs; 606 } 607 } 608 609 /* pass 2: copy into flat buffer. */ 610 xaddrs = (struct sockaddr *)malloc(xaddrlen); 611 if (!xaddrs) { 612 i_errno = IESETSCTPBINDX; 613 retval = -1; 614 goto out; 615 } 616 bp = (char *)xaddrs; 617 TAILQ_FOREACH(xbe, &test->xbind_addrs, link) { 618 ai0 = xbe->ai; 619 for (ai = ai0; ai; ai = ai->ai_next) { 620 if (domain != AF_UNSPEC && domain != ai->ai_family) 621 continue; 622 memcpy(bp, ai->ai_addr, ai->ai_addrlen); 623 bp += ai->ai_addrlen; 624 } 625 } 626 627 if (sctp_bindx(s, xaddrs, nxaddrs, SCTP_BINDX_ADD_ADDR) == -1) { 628 saved_errno = errno; 629 close(s); 630 free(xaddrs); 631 errno = saved_errno; 632 i_errno = IESETSCTPBINDX; 633 retval = -1; 634 goto out; 635 } 636 637 free(xaddrs); 638 retval = 0; 639 640 out: 641 /* client: put head node back. */ 642 if (!is_server && xbe0) 643 TAILQ_INSERT_HEAD(&test->xbind_addrs, xbe0, link); 644 645 TAILQ_FOREACH(xbe, &test->xbind_addrs, link) { 646 if (xbe->ai) { 647 freeaddrinfo(xbe->ai); 648 xbe->ai = NULL; 649 } 650 } 651 652 return retval; 653 #else 654 i_errno = IENOSCTP; 655 return -1; 656 #endif /* HAVE_SCTP */ 657 } 658