diff --git a/src/wolfio.c b/src/wolfio.c index 8c475aea4..a29223f81 100644 --- a/src/wolfio.c +++ b/src/wolfio.c @@ -51,6 +51,14 @@ Possible IO enable options: * HAVE_HTTP_CLIENT: Enables HTTP client API's default: off (unless HAVE_OCSP or HAVE_CRL_IO defined) * HAVE_IO_TIMEOUT: Enables support for connect timeout default: off + * + * DTLS_RECEIVEFROM_NO_TIMEOUT_ON_INVALID_PEER: This flag has effect only if + * ASN_NO_TIME is enabled. If enabled invalid peers messages are ignored + * indefinetely. If not enabled EmbedReceiveFrom will return timeout after + * DTLS_RECEIVEFROM_MAX_INVALID_PEER number of packets from invalid peers. When + * enabled, without a timer, EmbedReceivefrom can't check if the timeout is + * expired and it may never return under a continous flow of invalid packets. + * default: off */ @@ -59,6 +67,11 @@ Possible IO enable options: but they'll still need SetCallback xxx() at end of file */ +#if defined(NO_ASN_TIME) && !defined(DTLS_RECEIVEFROM_NO_TIMEOUT_ON_INVALID_PEER) \ + && !defined(DTLS_RECEIVEFROM_MAX_INVALID_PEER) +#define DTLS_RECEIVEFROM_MAX_INVALID_PEER 10 +#endif + #if defined(USE_WOLFSSL_IO) || defined(HAVE_HTTP_CLIENT) /* Translates return codes returned from @@ -400,6 +413,11 @@ int EmbedReceiveFrom(WOLFSSL *ssl, char *buf, int sz, void *ctx) SOCKADDR_S lclPeer; SOCKADDR_S* peer; XSOCKLENT peerSz = 0; +#ifndef NO_ASN_TIME + word32 start = 0; +#elif !defined(DTLS_RECEIVEFROM_NO_TIMEOUT_ON_INVALID_PEER) + word32 invalidPeerPackets = 0; +#endif WOLFSSL_ENTER("EmbedReceiveFrom"); @@ -438,10 +456,26 @@ int EmbedReceiveFrom(WOLFSSL *ssl, char *buf, int sz, void *ctx) } #endif /* WOLFSSL_DTLS13 */ - if (!doDtlsTimeout) - dtls_timeout = 0; + do { - if (!wolfSSL_get_using_nonblock(ssl)) { + if (!doDtlsTimeout) { + dtls_timeout = 0; + } + else { +#ifndef NO_ASN_TIME + if (start == 0) { + start = LowResTimer(); + } + else { + dtls_timeout -= LowResTimer() - start; + start = LowResTimer(); + if (dtls_timeout < 0 || dtls_timeout > DTLS_TIMEOUT_MAX) + return WOLFSSL_CBIO_ERR_TIMEOUT; + } +#endif + } + + if (!wolfSSL_get_using_nonblock(ssl)) { #ifdef USE_WINDOWS_API DWORD timeout = dtls_timeout * 1000; #ifdef WOLFSSL_DTLS13 @@ -464,87 +498,101 @@ int EmbedReceiveFrom(WOLFSSL *ssl, char *buf, int sz, void *ctx) #endif /* WOLFSSL_DTLS13 */ timeout.tv_sec = dtls_timeout; #endif - if (setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, - sizeof(timeout)) != 0) { + if (setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, + sizeof(timeout)) != 0) { WOLFSSL_MSG("setsockopt rcvtimeo failed"); + } } - } #ifndef NO_ASN_TIME - else if(IsSCR(ssl)) { - if (ssl->dtls_start_timeout && - LowResTimer() - ssl->dtls_start_timeout > (word32)dtls_timeout) { - ssl->dtls_start_timeout = 0; - return WOLFSSL_CBIO_ERR_TIMEOUT; + else if (IsSCR(ssl)) { + if (ssl->dtls_start_timeout && + LowResTimer() - ssl->dtls_start_timeout > + (word32)dtls_timeout) { + ssl->dtls_start_timeout = 0; + return WOLFSSL_CBIO_ERR_TIMEOUT; + } + else if (!ssl->dtls_start_timeout) { + ssl->dtls_start_timeout = LowResTimer(); + } } - else if (!ssl->dtls_start_timeout) { - ssl->dtls_start_timeout = LowResTimer(); - } - } #endif /* !NO_ASN_TIME */ - recvd = (int)DTLS_RECVFROM_FUNCTION(sd, buf, sz, ssl->rflags, - (SOCKADDR*)peer, peer != NULL ? &peerSz : NULL); + recvd = (int)DTLS_RECVFROM_FUNCTION(sd, buf, sz, ssl->rflags, + (SOCKADDR*)peer, peer != NULL ? &peerSz : NULL); - /* From the RECV(2) man page - * The returned address is truncated if the buffer provided is too small; in - * this case, addrlen will return a value greater than was supplied to the - * call. - */ - if (dtlsCtx->connected) { - /* No need to sanitize the value of peerSz */ - } - else if (dtlsCtx->userSet) { - /* Truncate peer size */ - if (peerSz > (XSOCKLENT)sizeof(lclPeer)) - peerSz = (XSOCKLENT)sizeof(lclPeer); - } - else { - /* Truncate peer size */ - if (peerSz > (XSOCKLENT)dtlsCtx->peer.bufSz) - peerSz = (XSOCKLENT)dtlsCtx->peer.bufSz; - } - - recvd = TranslateReturnCode(recvd, sd); - - if (recvd < 0) { - WOLFSSL_MSG("Embed Receive From error"); - recvd = TranslateIoError(recvd); - if (recvd == WOLFSSL_CBIO_ERR_WANT_READ && - !wolfSSL_dtls_get_using_nonblock(ssl)) { - recvd = WOLFSSL_CBIO_ERR_TIMEOUT; + /* From the RECV(2) man page + * The returned address is truncated if the buffer provided is too + * small; in this case, addrlen will return a value greater than was + * supplied to the call. + */ + if (dtlsCtx->connected) { + /* No need to sanitize the value of peerSz */ } - return recvd; - } - else if (recvd == 0) { - if (!isDGramSock(sd)) { - /* Closed TCP connection */ - recvd = WOLFSSL_CBIO_ERR_CONN_CLOSE; + else if (dtlsCtx->userSet) { + /* Truncate peer size */ + if (peerSz > (XSOCKLENT)sizeof(lclPeer)) + peerSz = (XSOCKLENT)sizeof(lclPeer); } else { - WOLFSSL_MSG("Ignoring 0-length datagram"); + /* Truncate peer size */ + if (peerSz > (XSOCKLENT)dtlsCtx->peer.bufSz) + peerSz = (XSOCKLENT)dtlsCtx->peer.bufSz; } - return recvd; - } - else if (dtlsCtx->connected) { - /* Nothing to do */ - } - else if (dtlsCtx->userSet) { - /* Check we received the packet from the correct peer */ - if (dtlsCtx->peer.sz > 0 && - (peerSz != (XSOCKLENT)dtlsCtx->peer.sz || - !sockAddrEqual(peer, peerSz, (SOCKADDR_S*)dtlsCtx->peer.sa, - dtlsCtx->peer.sz))) { - WOLFSSL_MSG(" Ignored packet from invalid peer"); - return WOLFSSL_CBIO_ERR_WANT_READ; + + recvd = TranslateReturnCode(recvd, sd); + + if (recvd < 0) { + WOLFSSL_MSG("Embed Receive From error"); + recvd = TranslateIoError(recvd); + if (recvd == WOLFSSL_CBIO_ERR_WANT_READ && + !wolfSSL_dtls_get_using_nonblock(ssl)) { + recvd = WOLFSSL_CBIO_ERR_TIMEOUT; + } + return recvd; + } + else if (recvd == 0) { + if (!isDGramSock(sd)) { + /* Closed TCP connection */ + recvd = WOLFSSL_CBIO_ERR_CONN_CLOSE; + } + else { + WOLFSSL_MSG("Ignoring 0-length datagram"); + continue; + } + return recvd; + } + else if (dtlsCtx->connected) { + /* Nothing to do */ + } + else if (dtlsCtx->userSet) { + /* Check we received the packet from the correct peer */ + if (dtlsCtx->peer.sz > 0 && + (peerSz != (XSOCKLENT)dtlsCtx->peer.sz || + !sockAddrEqual(peer, peerSz, (SOCKADDR_S*)dtlsCtx->peer.sa, + dtlsCtx->peer.sz))) { + WOLFSSL_MSG(" Ignored packet from invalid peer"); +#if defined(NO_ASN_TIME) && \ + !defined(DTLS_RECEIVEFROM_NO_TIMEOUT_ON_INVALID_PEER) + if (doDtlsTimeout) { + invalidPeerPackets++; + if (invalidPeerPackets > DTLS_RECEIVEFROM_MAX_INVALID_PEER) + return wolfSSL_dtls_get_using_nonblock(ssl) + ? WOLFSSL_CBIO_ERR_WANT_READ + : WOLFSSL_CBIO_ERR_TIMEOUT; + } +#endif /* NO_ASN_TIME && !DTLS_RECEIVEFROM_NO_TIMEOUT_ON_INVALID_PEER */ + continue; + } + } + else { + /* Store size of saved address */ + dtlsCtx->peer.sz = peerSz; } - } - else { - /* Store size of saved address */ - dtlsCtx->peer.sz = peerSz; - } #ifndef NO_ASN_TIME - ssl->dtls_start_timeout = 0; + ssl->dtls_start_timeout = 0; #endif /* !NO_ASN_TIME */ + break; + } while (1); return recvd; }