• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_H)
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_H */
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_H)
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_H */
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_H)
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         close(s);
135         return -1;
136     }
137 
138     if (strncmp(test->cookie, cookie, COOKIE_SIZE) != 0) {
139         if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Psctp) < 0) {
140             i_errno = IESENDMESSAGE;
141             close(s);
142             return -1;
143         }
144         close(s);
145     }
146 
147     return s;
148 #else
149     i_errno = IENOSCTP;
150     return -1;
151 #endif /* HAVE_SCTP_H */
152 }
153 
154 
155 /* iperf_sctp_listen
156  *
157  * start up a listener for SCTP stream connections
158  */
159 int
iperf_sctp_listen(struct iperf_test * test)160 iperf_sctp_listen(struct iperf_test *test)
161 {
162 #if defined(HAVE_SCTP_H)
163     struct addrinfo hints, *res;
164     char portstr[6];
165     int s, opt, saved_errno;
166 
167     close(test->listener);
168 
169     snprintf(portstr, 6, "%d", test->server_port);
170     memset(&hints, 0, sizeof(hints));
171     /*
172      * If binding to the wildcard address with no explicit address
173      * family specified, then force us to get an AF_INET6 socket.
174      * More details in the comments in netanounce().
175      */
176     if (test->settings->domain == AF_UNSPEC && !test->bind_address) {
177         hints.ai_family = AF_INET6;
178     } else {
179         hints.ai_family = test->settings->domain;
180     }
181     hints.ai_socktype = SOCK_STREAM;
182     hints.ai_flags = AI_PASSIVE;
183     if ((gerror = getaddrinfo(test->bind_address, portstr, &hints, &res)) != 0) {
184         i_errno = IESTREAMLISTEN;
185         return -1;
186     }
187 
188     if ((s = socket(res->ai_family, SOCK_STREAM, IPPROTO_SCTP)) < 0) {
189         freeaddrinfo(res);
190         i_errno = IESTREAMLISTEN;
191         return -1;
192     }
193 
194     if ((opt = test->settings->socket_bufsize)) {
195         int saved_errno;
196         if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
197             saved_errno = errno;
198             close(s);
199             freeaddrinfo(res);
200             errno = saved_errno;
201             i_errno = IESETBUF;
202             return -1;
203         }
204         if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
205             saved_errno = errno;
206             close(s);
207             freeaddrinfo(res);
208             errno = saved_errno;
209             i_errno = IESETBUF;
210             return -1;
211         }
212     }
213 
214 #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
215     if (res->ai_family == AF_INET6 && (test->settings->domain == AF_UNSPEC ||
216         test->settings->domain == AF_INET6)) {
217         if (test->settings->domain == AF_UNSPEC)
218             opt = 0;
219         else
220             opt = 1;
221         if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
222 		       (char *) &opt, sizeof(opt)) < 0) {
223 	    saved_errno = errno;
224 	    close(s);
225 	    freeaddrinfo(res);
226 	    errno = saved_errno;
227 	    i_errno = IEPROTOCOL;
228 	    return -1;
229 	}
230     }
231 #endif /* IPV6_V6ONLY */
232 
233     opt = 1;
234     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
235         saved_errno = errno;
236         close(s);
237         freeaddrinfo(res);
238         errno = saved_errno;
239         i_errno = IEREUSEADDR;
240         return -1;
241     }
242 
243     /* servers must call sctp_bindx() _instead_ of bind() */
244     if (!TAILQ_EMPTY(&test->xbind_addrs)) {
245         if (iperf_sctp_bindx(test, s, IPERF_SCTP_SERVER)) {
246             close(s);
247             freeaddrinfo(res);
248             return -1;
249         }
250     } else
251     if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
252         saved_errno = errno;
253         close(s);
254         freeaddrinfo(res);
255         errno = saved_errno;
256         i_errno = IESTREAMLISTEN;
257         return -1;
258     }
259 
260     freeaddrinfo(res);
261 
262     if (listen(s, INT_MAX) < 0) {
263         i_errno = IESTREAMLISTEN;
264         return -1;
265     }
266 
267     test->listener = s;
268 
269     return s;
270 #else
271     i_errno = IENOSCTP;
272     return -1;
273 #endif /* HAVE_SCTP_H */
274 }
275 
276 
277 /* iperf_sctp_connect
278  *
279  * connect to a SCTP stream listener
280  */
281 int
iperf_sctp_connect(struct iperf_test * test)282 iperf_sctp_connect(struct iperf_test *test)
283 {
284 #if defined(HAVE_SCTP_H)
285     int s, opt, saved_errno;
286     char portstr[6];
287     struct addrinfo hints, *local_res, *server_res;
288 
289     if (test->bind_address) {
290         memset(&hints, 0, sizeof(hints));
291         hints.ai_family = test->settings->domain;
292         hints.ai_socktype = SOCK_STREAM;
293         if ((gerror = getaddrinfo(test->bind_address, NULL, &hints, &local_res)) != 0) {
294             i_errno = IESTREAMCONNECT;
295             return -1;
296         }
297     }
298 
299     memset(&hints, 0, sizeof(hints));
300     hints.ai_family = test->settings->domain;
301     hints.ai_socktype = SOCK_STREAM;
302     snprintf(portstr, sizeof(portstr), "%d", test->server_port);
303     if ((gerror = getaddrinfo(test->server_hostname, portstr, &hints, &server_res)) != 0) {
304 	if (test->bind_address)
305 	    freeaddrinfo(local_res);
306         i_errno = IESTREAMCONNECT;
307         return -1;
308     }
309 
310     s = socket(server_res->ai_family, SOCK_STREAM, IPPROTO_SCTP);
311     if (s < 0) {
312 	if (test->bind_address)
313 	    freeaddrinfo(local_res);
314 	freeaddrinfo(server_res);
315         i_errno = IESTREAMCONNECT;
316         return -1;
317     }
318 
319     if ((opt = test->settings->socket_bufsize)) {
320         int saved_errno;
321         if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
322             saved_errno = errno;
323             close(s);
324             freeaddrinfo(server_res);
325             errno = saved_errno;
326             i_errno = IESETBUF;
327             return -1;
328         }
329         if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
330             saved_errno = errno;
331             close(s);
332             freeaddrinfo(server_res);
333             errno = saved_errno;
334             i_errno = IESETBUF;
335             return -1;
336         }
337     }
338 
339     /*
340      * Various ways to bind the local end of the connection.
341      * 1.  --bind (with or without --cport).
342      */
343     if (test->bind_address) {
344         struct sockaddr_in *lcladdr;
345         lcladdr = (struct sockaddr_in *)local_res->ai_addr;
346         lcladdr->sin_port = htons(test->bind_port);
347 
348         if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) {
349 	    saved_errno = errno;
350 	    close(s);
351 	    freeaddrinfo(local_res);
352 	    freeaddrinfo(server_res);
353 	    errno = saved_errno;
354             i_errno = IESTREAMCONNECT;
355             return -1;
356         }
357         freeaddrinfo(local_res);
358     }
359     /* --cport, no --bind */
360     else if (test->bind_port) {
361 	size_t addrlen;
362 	struct sockaddr_storage lcl;
363 
364 	/* IPv4 */
365 	if (server_res->ai_family == AF_INET) {
366 	    struct sockaddr_in *lcladdr = (struct sockaddr_in *) &lcl;
367 	    lcladdr->sin_family = AF_INET;
368 	    lcladdr->sin_port = htons(test->bind_port);
369 	    lcladdr->sin_addr.s_addr = INADDR_ANY;
370 	    addrlen = sizeof(struct sockaddr_in);
371 	}
372 	/* IPv6 */
373 	else if (server_res->ai_family == AF_INET6) {
374 	    struct sockaddr_in6 *lcladdr = (struct sockaddr_in6 *) &lcl;
375 	    lcladdr->sin6_family = AF_INET6;
376 	    lcladdr->sin6_port = htons(test->bind_port);
377 	    lcladdr->sin6_addr = in6addr_any;
378 	    addrlen = sizeof(struct sockaddr_in6);
379 	}
380 	/* Unknown protocol */
381 	else {
382 	    saved_errno = errno;
383 	    close(s);
384 	    freeaddrinfo(server_res);
385 	    errno = saved_errno;
386             i_errno = IEPROTOCOL;
387             return -1;
388 	}
389 
390         if (bind(s, (struct sockaddr *) &lcl, addrlen) < 0) {
391 	    saved_errno = errno;
392 	    close(s);
393 	    freeaddrinfo(server_res);
394 	    errno = saved_errno;
395             i_errno = IESTREAMCONNECT;
396             return -1;
397         }
398     }
399 
400     if (test->no_delay != 0) {
401          opt = 1;
402          if (setsockopt(s, IPPROTO_SCTP, SCTP_NODELAY, &opt, sizeof(opt)) < 0) {
403              saved_errno = errno;
404              close(s);
405              freeaddrinfo(server_res);
406              errno = saved_errno;
407              i_errno = IESETNODELAY;
408              return -1;
409          }
410     }
411 
412     if ((test->settings->mss >= 512 && test->settings->mss <= 131072)) {
413 
414 	/*
415 	 * Some platforms use a struct sctp_assoc_value as the
416 	 * argument to SCTP_MAXSEG.  Other (older API implementations)
417 	 * take an int.  FreeBSD 10 and CentOS 6 support SCTP_MAXSEG,
418 	 * but OpenSolaris 11 doesn't.
419 	 */
420 #ifdef HAVE_STRUCT_SCTP_ASSOC_VALUE
421         struct sctp_assoc_value av;
422 
423 	/*
424 	 * Some platforms support SCTP_FUTURE_ASSOC, others need to
425 	 * (equivalently) do 0 here.  FreeBSD 10 is an example of the
426 	 * former, CentOS 6 Linux is an example of the latter.
427 	 */
428 #ifdef SCTP_FUTURE_ASSOC
429         av.assoc_id = SCTP_FUTURE_ASSOC;
430 #else
431 	av.assoc_id = 0;
432 #endif
433         av.assoc_value = test->settings->mss;
434 
435         if (setsockopt(s, IPPROTO_SCTP, SCTP_MAXSEG, &av, sizeof(av)) < 0) {
436             saved_errno = errno;
437             close(s);
438             freeaddrinfo(server_res);
439             errno = saved_errno;
440             i_errno = IESETMSS;
441             return -1;
442         }
443 #else
444 	opt = test->settings->mss;
445 
446 	/*
447 	 * Solaris might not support this option.  If it doesn't work,
448 	 * ignore the error (at least for now).
449 	 */
450         if (setsockopt(s, IPPROTO_SCTP, SCTP_MAXSEG, &opt, sizeof(opt)) < 0 &&
451 	    errno != ENOPROTOOPT) {
452             saved_errno = errno;
453             close(s);
454             freeaddrinfo(server_res);
455             errno = saved_errno;
456             i_errno = IESETMSS;
457             return -1;
458         }
459 #endif /* HAVE_STRUCT_SCTP_ASSOC_VALUE */
460     }
461 
462     if (test->settings->num_ostreams > 0) {
463         struct sctp_initmsg initmsg;
464 
465         memset(&initmsg, 0, sizeof(struct sctp_initmsg));
466         initmsg.sinit_num_ostreams = test->settings->num_ostreams;
467 
468         if (setsockopt(s, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(struct sctp_initmsg)) < 0) {
469                 saved_errno = errno;
470                 close(s);
471                 freeaddrinfo(server_res);
472                 errno = saved_errno;
473                 i_errno = IESETSCTPNSTREAM;
474                 return -1;
475         }
476     }
477 
478     /* clients must call bind() followed by sctp_bindx() before connect() */
479     if (!TAILQ_EMPTY(&test->xbind_addrs)) {
480         if (iperf_sctp_bindx(test, s, IPERF_SCTP_CLIENT)) {
481             freeaddrinfo(server_res);
482             close(s);
483             return -1;
484         }
485     }
486 
487     /* TODO support sctp_connectx() to avoid heartbeating. */
488     if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) {
489 	saved_errno = errno;
490 	close(s);
491 	freeaddrinfo(server_res);
492 	errno = saved_errno;
493         i_errno = IESTREAMCONNECT;
494         return -1;
495     }
496 
497     /* Send cookie for verification */
498     if (Nwrite(s, test->cookie, COOKIE_SIZE, Psctp) < 0) {
499 	saved_errno = errno;
500 	close(s);
501 	freeaddrinfo(server_res);
502 	errno = saved_errno;
503         i_errno = IESENDCOOKIE;
504         return -1;
505     }
506 
507     /*
508      * We want to allow fragmentation.  But there's at least one
509      * implementation (Solaris) that doesn't support this option,
510      * even though it defines SCTP_DISABLE_FRAGMENTS.  So we have to
511      * try setting the option and ignore the error, if it doesn't
512      * work.
513      */
514     opt = 0;
515     if (setsockopt(s, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &opt, sizeof(opt)) < 0 &&
516 	errno != ENOPROTOOPT) {
517         saved_errno = errno;
518         close(s);
519         freeaddrinfo(server_res);
520         errno = saved_errno;
521         i_errno = IESETSCTPDISABLEFRAG;
522         return -1;
523     }
524 
525     freeaddrinfo(server_res);
526     return s;
527 #else
528     i_errno = IENOSCTP;
529     return -1;
530 #endif /* HAVE_SCTP_H */
531 }
532 
533 
534 
535 int
iperf_sctp_init(struct iperf_test * test)536 iperf_sctp_init(struct iperf_test *test)
537 {
538 #if defined(HAVE_SCTP_H)
539     return 0;
540 #else
541     i_errno = IENOSCTP;
542     return -1;
543 #endif /* HAVE_SCTP_H */
544 }
545 
546 
547 
548 /* iperf_sctp_bindx
549  *
550  * handle binding to multiple endpoints (-X parameters)
551  */
552 int
iperf_sctp_bindx(struct iperf_test * test,int s,int is_server)553 iperf_sctp_bindx(struct iperf_test *test, int s, int is_server)
554 {
555 #if defined(HAVE_SCTP_H)
556     struct addrinfo hints;
557     char portstr[6];
558     char *servname;
559     struct addrinfo *ai, *ai0;
560     struct sockaddr *xaddrs;
561     struct xbind_entry *xbe, *xbe0;
562     char *bp;
563     size_t xaddrlen;
564     int nxaddrs;
565     int retval;
566     int domain;
567     int saved_errno;
568 
569     domain = test->settings->domain;
570     xbe0 = NULL;
571     retval = 0;
572 
573     if (TAILQ_EMPTY(&test->xbind_addrs))
574         return retval; /* nothing to do */
575 
576     memset(&hints, 0, sizeof(hints));
577     hints.ai_family = (domain == AF_UNSPEC ? AF_INET6 : domain);
578     hints.ai_socktype = SOCK_STREAM;
579     servname = NULL;
580     if (is_server) {
581         hints.ai_flags |= AI_PASSIVE;
582         snprintf(portstr, 6, "%d", test->server_port);
583         servname = portstr;
584     }
585 
586     /* client: must pop first -X address and call bind().
587      * sctp_bindx() must see the ephemeral port chosen by bind().
588      * we deliberately ignore the -B argument in this case.
589      */
590     if (!is_server) {
591         struct sockaddr *sa;
592         struct sockaddr_in *sin;
593         struct sockaddr_in6 *sin6;
594         int eport;
595 
596         xbe0 = TAILQ_FIRST(&test->xbind_addrs);
597         TAILQ_REMOVE(&test->xbind_addrs, xbe0, link);
598 
599         if ((gerror = getaddrinfo(xbe0->name, servname, &hints, &xbe0->ai)) != 0) {
600             i_errno = IESETSCTPBINDX;
601             retval = -1;
602             goto out;
603         }
604 
605         ai = xbe0->ai;
606         if (domain != AF_UNSPEC && domain != ai->ai_family) {
607             i_errno = IESETSCTPBINDX;
608             retval = -1;
609             goto out;
610         }
611         if (bind(s, (struct sockaddr *)ai->ai_addr, ai->ai_addrlen) < 0) {
612             i_errno = IESETSCTPBINDX;
613             retval = -1;
614             goto out;
615         }
616 
617         /* if only one -X argument, nothing more to do */
618         if (TAILQ_EMPTY(&test->xbind_addrs))
619             goto out;
620 
621         sa = (struct sockaddr *)ai->ai_addr;
622         if (sa->sa_family == AF_INET) {
623             sin = (struct sockaddr_in *)ai->ai_addr;
624             eport = sin->sin_port;
625         } else if (sa->sa_family == AF_INET6) {
626             sin6 = (struct sockaddr_in6 *)ai->ai_addr;
627             eport = sin6->sin6_port;
628         } else {
629             i_errno = IESETSCTPBINDX;
630             retval = -1;
631             goto out;
632         }
633         snprintf(portstr, 6, "%d", ntohs(eport));
634         servname = portstr;
635     }
636 
637     /* pass 1: resolve and compute lengths. */
638     nxaddrs = 0;
639     xaddrlen = 0;
640     TAILQ_FOREACH(xbe, &test->xbind_addrs, link) {
641         if (xbe->ai != NULL)
642             freeaddrinfo(xbe->ai);
643         if ((gerror = getaddrinfo(xbe->name, servname, &hints, &xbe->ai)) != 0) {
644             i_errno = IESETSCTPBINDX;
645             retval = -1;
646             goto out;
647         }
648         ai0 = xbe->ai;
649         for (ai = ai0; ai; ai = ai->ai_next) {
650             if (domain != AF_UNSPEC && domain != ai->ai_family)
651                 continue;
652             xaddrlen += ai->ai_addrlen;
653             ++nxaddrs;
654         }
655     }
656 
657     /* pass 2: copy into flat buffer. */
658     xaddrs = (struct sockaddr *)malloc(xaddrlen);
659     if (!xaddrs) {
660             i_errno = IESETSCTPBINDX;
661             retval = -1;
662             goto out;
663     }
664     bp = (char *)xaddrs;
665     TAILQ_FOREACH(xbe, &test->xbind_addrs, link) {
666         ai0 = xbe->ai;
667         for (ai = ai0; ai; ai = ai->ai_next) {
668             if (domain != AF_UNSPEC && domain != ai->ai_family)
669                 continue;
670 	    memcpy(bp, ai->ai_addr, ai->ai_addrlen);
671             bp += ai->ai_addrlen;
672         }
673     }
674 
675     if (sctp_bindx(s, xaddrs, nxaddrs, SCTP_BINDX_ADD_ADDR) == -1) {
676         saved_errno = errno;
677         close(s);
678         free(xaddrs);
679         errno = saved_errno;
680         i_errno = IESETSCTPBINDX;
681         retval = -1;
682         goto out;
683     }
684 
685     free(xaddrs);
686     retval = 0;
687 
688 out:
689     /* client: put head node back. */
690     if (!is_server && xbe0)
691         TAILQ_INSERT_HEAD(&test->xbind_addrs, xbe0, link);
692 
693     TAILQ_FOREACH(xbe, &test->xbind_addrs, link) {
694         if (xbe->ai) {
695             freeaddrinfo(xbe->ai);
696             xbe->ai = NULL;
697         }
698     }
699 
700     return retval;
701 #else
702     i_errno = IENOSCTP;
703     return -1;
704 #endif /* HAVE_SCTP_H */
705 }
706