summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/bio/bss_dgram.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libcrypto/bio/bss_dgram.c')
-rw-r--r--src/lib/libcrypto/bio/bss_dgram.c658
1 files changed, 0 insertions, 658 deletions
diff --git a/src/lib/libcrypto/bio/bss_dgram.c b/src/lib/libcrypto/bio/bss_dgram.c
deleted file mode 100644
index a9657402ce..0000000000
--- a/src/lib/libcrypto/bio/bss_dgram.c
+++ /dev/null
@@ -1,658 +0,0 @@
1/* $OpenBSD: bss_dgram.c,v 1.41 2015/07/20 23:15:28 doug Exp $ */
2/*
3 * DTLS implementation written by Nagendra Modadugu
4 * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
5 */
6/* ====================================================================
7 * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * 3. All advertising materials mentioning features or use of this
22 * software must display the following acknowledgment:
23 * "This product includes software developed by the OpenSSL Project
24 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25 *
26 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27 * endorse or promote products derived from this software without
28 * prior written permission. For written permission, please contact
29 * openssl-core@OpenSSL.org.
30 *
31 * 5. Products derived from this software may not be called "OpenSSL"
32 * nor may "OpenSSL" appear in their names without prior written
33 * permission of the OpenSSL Project.
34 *
35 * 6. Redistributions of any form whatsoever must retain the following
36 * acknowledgment:
37 * "This product includes software developed by the OpenSSL Project
38 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51 * OF THE POSSIBILITY OF SUCH DAMAGE.
52 * ====================================================================
53 *
54 * This product includes cryptographic software written by Eric Young
55 * (eay@cryptsoft.com). This product includes software written by Tim
56 * Hudson (tjh@cryptsoft.com).
57 *
58 */
59
60#include <sys/socket.h>
61#include <sys/time.h>
62
63#include <netinet/in.h>
64
65#include <errno.h>
66#include <netdb.h>
67#include <stdio.h>
68#include <string.h>
69#include <unistd.h>
70
71#include <openssl/opensslconf.h>
72
73#include <openssl/bio.h>
74
75#ifndef OPENSSL_NO_DGRAM
76
77
78static int dgram_write(BIO *h, const char *buf, int num);
79static int dgram_read(BIO *h, char *buf, int size);
80static int dgram_puts(BIO *h, const char *str);
81static long dgram_ctrl(BIO *h, int cmd, long arg1, void *arg2);
82static int dgram_new(BIO *h);
83static int dgram_free(BIO *data);
84static int dgram_clear(BIO *bio);
85
86
87static int BIO_dgram_should_retry(int s);
88
89static BIO_METHOD methods_dgramp = {
90 .type = BIO_TYPE_DGRAM,
91 .name = "datagram socket",
92 .bwrite = dgram_write,
93 .bread = dgram_read,
94 .bputs = dgram_puts,
95 .ctrl = dgram_ctrl,
96 .create = dgram_new,
97 .destroy = dgram_free
98};
99
100
101typedef struct bio_dgram_data_st {
102 union {
103 struct sockaddr sa;
104 struct sockaddr_in sa_in;
105 struct sockaddr_in6 sa_in6;
106 } peer;
107 unsigned int connected;
108 unsigned int _errno;
109 unsigned int mtu;
110 struct timeval next_timeout;
111 struct timeval socket_timeout;
112} bio_dgram_data;
113
114
115BIO_METHOD *
116BIO_s_datagram(void)
117{
118 return (&methods_dgramp);
119}
120
121BIO *
122BIO_new_dgram(int fd, int close_flag)
123{
124 BIO *ret;
125
126 ret = BIO_new(BIO_s_datagram());
127 if (ret == NULL)
128 return (NULL);
129 BIO_set_fd(ret, fd, close_flag);
130 return (ret);
131}
132
133static int
134dgram_new(BIO *bi)
135{
136 bio_dgram_data *data = NULL;
137
138 bi->init = 0;
139 bi->num = 0;
140 data = calloc(1, sizeof(bio_dgram_data));
141 if (data == NULL)
142 return 0;
143 bi->ptr = data;
144
145 bi->flags = 0;
146 return (1);
147}
148
149static int
150dgram_free(BIO *a)
151{
152 bio_dgram_data *data;
153
154 if (a == NULL)
155 return (0);
156 if (!dgram_clear(a))
157 return 0;
158
159 data = (bio_dgram_data *)a->ptr;
160 free(data);
161
162 return (1);
163}
164
165static int
166dgram_clear(BIO *a)
167{
168 if (a == NULL)
169 return (0);
170 if (a->shutdown) {
171 if (a->init) {
172 shutdown(a->num, SHUT_RDWR);
173 close(a->num);
174 }
175 a->init = 0;
176 a->flags = 0;
177 }
178 return (1);
179}
180
181static void
182dgram_adjust_rcv_timeout(BIO *b)
183{
184#if defined(SO_RCVTIMEO)
185 bio_dgram_data *data = (bio_dgram_data *)b->ptr;
186
187 /* Is a timer active? */
188 if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) {
189 struct timeval timenow, timeleft;
190
191 /* Read current socket timeout */
192 socklen_t sz = sizeof(data->socket_timeout);
193 if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
194 &(data->socket_timeout), &sz) < 0) {
195 perror("getsockopt");
196 }
197
198 /* Get current time */
199 gettimeofday(&timenow, NULL);
200
201 /* Calculate time left until timer expires */
202 memcpy(&timeleft, &(data->next_timeout), sizeof(struct timeval));
203 timeleft.tv_sec -= timenow.tv_sec;
204 timeleft.tv_usec -= timenow.tv_usec;
205 if (timeleft.tv_usec < 0) {
206 timeleft.tv_sec--;
207 timeleft.tv_usec += 1000000;
208 }
209
210 if (timeleft.tv_sec < 0) {
211 timeleft.tv_sec = 0;
212 timeleft.tv_usec = 1;
213 }
214
215 /* Adjust socket timeout if next handhake message timer
216 * will expire earlier.
217 */
218 if ((data->socket_timeout.tv_sec == 0 &&
219 data->socket_timeout.tv_usec == 0) ||
220 (data->socket_timeout.tv_sec > timeleft.tv_sec) ||
221 (data->socket_timeout.tv_sec == timeleft.tv_sec &&
222 data->socket_timeout.tv_usec >= timeleft.tv_usec)) {
223 if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
224 &timeleft, sizeof(struct timeval)) < 0) {
225 perror("setsockopt");
226 }
227 }
228 }
229#endif
230}
231
232static void
233dgram_reset_rcv_timeout(BIO *b)
234{
235#if defined(SO_RCVTIMEO)
236 bio_dgram_data *data = (bio_dgram_data *)b->ptr;
237
238 /* Is a timer active? */
239 if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) {
240 if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
241 &(data->socket_timeout), sizeof(struct timeval)) < 0) {
242 perror("setsockopt");
243 }
244 }
245#endif
246}
247
248static int
249dgram_read(BIO *b, char *out, int outl)
250{
251 int ret = 0;
252 bio_dgram_data *data = (bio_dgram_data *)b->ptr;
253
254 struct {
255 socklen_t len;
256 union {
257 struct sockaddr sa;
258 struct sockaddr_in sa_in;
259 struct sockaddr_in6 sa_in6;
260 } peer;
261 } sa;
262
263 sa.len = sizeof(sa.peer);
264
265 if (out != NULL) {
266 errno = 0;
267 memset(&sa.peer, 0, sizeof(sa.peer));
268 dgram_adjust_rcv_timeout(b);
269 ret = recvfrom(b->num, out, outl, 0, &sa.peer.sa, &sa.len);
270
271 if (! data->connected && ret >= 0)
272 BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &sa.peer);
273
274 BIO_clear_retry_flags(b);
275 if (ret < 0) {
276 if (BIO_dgram_should_retry(ret)) {
277 BIO_set_retry_read(b);
278 data->_errno = errno;
279 }
280 }
281
282 dgram_reset_rcv_timeout(b);
283 }
284 return (ret);
285}
286
287static int
288dgram_write(BIO *b, const char *in, int inl)
289{
290 int ret;
291 bio_dgram_data *data = (bio_dgram_data *)b->ptr;
292 errno = 0;
293
294 if (data->connected)
295 ret = write(b->num, in, inl);
296 else {
297 int peerlen = sizeof(data->peer);
298
299 if (data->peer.sa.sa_family == AF_INET)
300 peerlen = sizeof(data->peer.sa_in);
301 else if (data->peer.sa.sa_family == AF_INET6)
302 peerlen = sizeof(data->peer.sa_in6);
303 ret = sendto(b->num, in, inl, 0, &data->peer.sa, peerlen);
304 }
305
306 BIO_clear_retry_flags(b);
307 if (ret <= 0) {
308 if (BIO_dgram_should_retry(ret)) {
309 BIO_set_retry_write(b);
310
311 data->_errno = errno;
312 /*
313 * higher layers are responsible for querying MTU,
314 * if necessary
315 */
316 }
317 }
318 return (ret);
319}
320
321static long
322dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
323{
324 long ret = 1;
325 int *ip;
326 struct sockaddr *to = NULL;
327 bio_dgram_data *data = NULL;
328#if (defined(IP_MTU_DISCOVER) || defined(IP_MTU))
329 int sockopt_val = 0;
330 socklen_t sockopt_len; /* assume that system supporting IP_MTU is
331 * modern enough to define socklen_t */
332 socklen_t addr_len;
333 union {
334 struct sockaddr sa;
335 struct sockaddr_in s4;
336 struct sockaddr_in6 s6;
337 } addr;
338#endif
339
340 data = (bio_dgram_data *)b->ptr;
341
342 switch (cmd) {
343 case BIO_CTRL_RESET:
344 num = 0;
345 case BIO_C_FILE_SEEK:
346 ret = 0;
347 break;
348 case BIO_C_FILE_TELL:
349 case BIO_CTRL_INFO:
350 ret = 0;
351 break;
352 case BIO_C_SET_FD:
353 dgram_clear(b);
354 b->num= *((int *)ptr);
355 b->shutdown = (int)num;
356 b->init = 1;
357 break;
358 case BIO_C_GET_FD:
359 if (b->init) {
360 ip = (int *)ptr;
361 if (ip != NULL)
362 *ip = b->num;
363 ret = b->num;
364 } else
365 ret = -1;
366 break;
367 case BIO_CTRL_GET_CLOSE:
368 ret = b->shutdown;
369 break;
370 case BIO_CTRL_SET_CLOSE:
371 b->shutdown = (int)num;
372 break;
373 case BIO_CTRL_PENDING:
374 case BIO_CTRL_WPENDING:
375 ret = 0;
376 break;
377 case BIO_CTRL_DUP:
378 case BIO_CTRL_FLUSH:
379 ret = 1;
380 break;
381 case BIO_CTRL_DGRAM_CONNECT:
382 to = (struct sockaddr *)ptr;
383 switch (to->sa_family) {
384 case AF_INET:
385 memcpy(&data->peer, to, sizeof(data->peer.sa_in));
386 break;
387 case AF_INET6:
388 memcpy(&data->peer, to, sizeof(data->peer.sa_in6));
389 break;
390 default:
391 memcpy(&data->peer, to, sizeof(data->peer.sa));
392 break;
393 }
394 break;
395 /* (Linux)kernel sets DF bit on outgoing IP packets */
396 case BIO_CTRL_DGRAM_MTU_DISCOVER:
397#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
398 addr_len = (socklen_t)sizeof(addr);
399 memset((void *)&addr, 0, sizeof(addr));
400 if (getsockname(b->num, &addr.sa, &addr_len) < 0) {
401 ret = 0;
402 break;
403 }
404 switch (addr.sa.sa_family) {
405 case AF_INET:
406 sockopt_val = IP_PMTUDISC_DO;
407 ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER,
408 &sockopt_val, sizeof(sockopt_val));
409 if (ret < 0)
410 perror("setsockopt");
411 break;
412#if defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
413 case AF_INET6:
414 sockopt_val = IPV6_PMTUDISC_DO;
415 ret = setsockopt(b->num, IPPROTO_IPV6,
416 IPV6_MTU_DISCOVER, &sockopt_val,
417 sizeof(sockopt_val));
418 if (ret < 0)
419 perror("setsockopt");
420 break;
421#endif
422 default:
423 ret = -1;
424 break;
425 }
426#else
427 ret = -1;
428#endif
429 break;
430 case BIO_CTRL_DGRAM_QUERY_MTU:
431#if defined(IP_MTU)
432 addr_len = (socklen_t)sizeof(addr);
433 memset((void *)&addr, 0, sizeof(addr));
434 if (getsockname(b->num, &addr.sa, &addr_len) < 0) {
435 ret = 0;
436 break;
437 }
438 sockopt_len = sizeof(sockopt_val);
439 switch (addr.sa.sa_family) {
440 case AF_INET:
441 ret = getsockopt(b->num, IPPROTO_IP, IP_MTU,
442 &sockopt_val, &sockopt_len);
443 if (ret < 0 || sockopt_val < 0) {
444 ret = 0;
445 } else {
446 /* we assume that the transport protocol is UDP and no
447 * IP options are used.
448 */
449 data->mtu = sockopt_val - 8 - 20;
450 ret = data->mtu;
451 }
452 break;
453#if defined(IPV6_MTU)
454 case AF_INET6:
455 ret = getsockopt(b->num, IPPROTO_IPV6, IPV6_MTU,
456 &sockopt_val, &sockopt_len);
457 if (ret < 0 || sockopt_val < 0) {
458 ret = 0;
459 } else {
460 /* we assume that the transport protocol is UDP and no
461 * IPV6 options are used.
462 */
463 data->mtu = sockopt_val - 8 - 40;
464 ret = data->mtu;
465 }
466 break;
467#endif
468default:
469 ret = 0;
470 break;
471 }
472#else
473 ret = 0;
474#endif
475 break;
476 case BIO_CTRL_DGRAM_GET_FALLBACK_MTU:
477 switch (data->peer.sa.sa_family) {
478 case AF_INET:
479 ret = 576 - 20 - 8;
480 break;
481 case AF_INET6:
482#ifdef IN6_IS_ADDR_V4MAPPED
483 if (IN6_IS_ADDR_V4MAPPED(&data->peer.sa_in6.sin6_addr))
484 ret = 576 - 20 - 8;
485 else
486#endif
487 ret = 1280 - 40 - 8;
488 break;
489 default:
490 ret = 576 - 20 - 8;
491 break;
492 }
493 break;
494 case BIO_CTRL_DGRAM_GET_MTU:
495 return data->mtu;
496 break;
497 case BIO_CTRL_DGRAM_SET_MTU:
498 data->mtu = num;
499 ret = num;
500 break;
501 case BIO_CTRL_DGRAM_SET_CONNECTED:
502 to = (struct sockaddr *)ptr;
503
504 if (to != NULL) {
505 data->connected = 1;
506 switch (to->sa_family) {
507 case AF_INET:
508 memcpy(&data->peer, to, sizeof(data->peer.sa_in));
509 break;
510 case AF_INET6:
511 memcpy(&data->peer, to, sizeof(data->peer.sa_in6));
512 break;
513 default:
514 memcpy(&data->peer, to, sizeof(data->peer.sa));
515 break;
516 }
517 } else {
518 data->connected = 0;
519 memset(&(data->peer), 0, sizeof(data->peer));
520 }
521 break;
522 case BIO_CTRL_DGRAM_GET_PEER:
523 switch (data->peer.sa.sa_family) {
524 case AF_INET:
525 ret = sizeof(data->peer.sa_in);
526 break;
527 case AF_INET6:
528 ret = sizeof(data->peer.sa_in6);
529 break;
530 default:
531 ret = sizeof(data->peer.sa);
532 break;
533 }
534 if (num == 0 || num > ret)
535 num = ret;
536 memcpy(ptr, &data->peer, (ret = num));
537 break;
538 case BIO_CTRL_DGRAM_SET_PEER:
539 to = (struct sockaddr *) ptr;
540 switch (to->sa_family) {
541 case AF_INET:
542 memcpy(&data->peer, to, sizeof(data->peer.sa_in));
543 break;
544 case AF_INET6:
545 memcpy(&data->peer, to, sizeof(data->peer.sa_in6));
546 break;
547 default:
548 memcpy(&data->peer, to, sizeof(data->peer.sa));
549 break;
550 }
551 break;
552 case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
553 memcpy(&(data->next_timeout), ptr, sizeof(struct timeval));
554 break;
555#if defined(SO_RCVTIMEO)
556 case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT:
557 if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr,
558 sizeof(struct timeval)) < 0) {
559 perror("setsockopt");
560 ret = -1;
561 }
562 break;
563 case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT:
564 {
565 socklen_t sz = sizeof(struct timeval);
566 if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
567 ptr, &sz) < 0) {
568 perror("getsockopt");
569 ret = -1;
570 } else
571 ret = sz;
572 }
573 break;
574#endif
575#if defined(SO_SNDTIMEO)
576 case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT:
577 if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr,
578 sizeof(struct timeval)) < 0) {
579 perror("setsockopt");
580 ret = -1;
581 }
582 break;
583 case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT:
584 {
585 socklen_t sz = sizeof(struct timeval);
586 if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
587 ptr, &sz) < 0) {
588 perror("getsockopt");
589 ret = -1;
590 } else
591 ret = sz;
592 }
593 break;
594#endif
595 case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP:
596 /* fall-through */
597 case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP:
598 if (data->_errno == EAGAIN) {
599 ret = 1;
600 data->_errno = 0;
601 } else
602 ret = 0;
603 break;
604#ifdef EMSGSIZE
605 case BIO_CTRL_DGRAM_MTU_EXCEEDED:
606 if (data->_errno == EMSGSIZE) {
607 ret = 1;
608 data->_errno = 0;
609 } else
610 ret = 0;
611 break;
612#endif
613 default:
614 ret = 0;
615 break;
616 }
617 return (ret);
618}
619
620static int
621dgram_puts(BIO *bp, const char *str)
622{
623 int n, ret;
624
625 n = strlen(str);
626 ret = dgram_write(bp, str, n);
627 return (ret);
628}
629
630
631static int
632BIO_dgram_should_retry(int i)
633{
634 int err;
635
636 if ((i == 0) || (i == -1)) {
637 err = errno;
638 return (BIO_dgram_non_fatal_error(err));
639 }
640 return (0);
641}
642
643int
644BIO_dgram_non_fatal_error(int err)
645{
646 switch (err) {
647 case EINTR:
648 case EAGAIN:
649 case EINPROGRESS:
650 case EALREADY:
651 return (1);
652 default:
653 break;
654 }
655 return (0);
656}
657
658#endif