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
iperf_sctp_recv(struct iperf_stream * sp)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
iperf_sctp_send(struct iperf_stream * sp)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
iperf_sctp_accept(struct iperf_test * test)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
iperf_sctp_listen(struct iperf_test * test)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
iperf_sctp_connect(struct iperf_test * test)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
iperf_sctp_init(struct iperf_test * test)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
iperf_sctp_bindx(struct iperf_test * test,int s,int is_server)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