-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DTLS fragment exceeds MTU size if the certificate is large. #1100
Comments
And what else can we do if OpenSSL doesn't work as expected? There is no way for us to limit the DTLS message size other than calling that OpenSSL API. |
This issue is caused by the use of |
Thanks for the info. BTW are you willing to create a PR for mediasoup as well? If not we'll do but not sure when, we have lot of pending work in different PRs. |
Although I would like to create a PR, I'm currently swamped wth work. We're focusing on adding WHIP support to FFmpeg, and we have already made it work with Janus, pion, and SRS. However, I'm also interested in makeing it work with mediasoup. Once I'm done with the FFmpeg WHIP patch and successfully make it work with mediasoup, I may have some spare time to create a PR for this issue. Even though I'm the maintainer of SRS, a open source WebRTC SFU server, I have strong admiration for mediasoup. 😄 |
Thanks a lot. As said, if you cannot I'll jump into this eventually. |
@ibc I've been able to reproduce it using the initial comment. I can take a look at creating a PR, if no one else has had the time yet? |
We have lot of pending work to do so I'd really appreciate if you could write that PR. Thanks a lot. |
Long time fixed, closing. |
I fail to understand why this issue didn't auto-close. It was fixed by PR #1156 (that targets |
No, it doesn't inherit "Closing" property that way |
So just when the PR targets main branch... ok |
…se it causes a memory leak - Fixes #1340 - Reopents #1100 ### Details As perfectly documented in issue #1340, there is a leak due to the usage of `BIO_set_callback_ex()` whose fix is unclear and, anyway, I'm pretty sure that the usage of that OpenSSL utility makes the performance worse. As a workaround for issue #1100 (which now must be reopened), in order to avoid "DTLS fragment exceeds MTU size if the certificate is large", users should not pass a big DTLS certificate to mediasoup.
Reopening this issue since the PR that fixed it has been reverted: #1342 |
An easy way to check the issue without requiring Wireshark: diff --git a/worker/src/RTC/DtlsTransport.cpp b/worker/src/RTC/DtlsTransport.cpp
index 3bb8a9657..52d1df301 100644
--- a/worker/src/RTC/DtlsTransport.cpp
+++ b/worker/src/RTC/DtlsTransport.cpp
@@ -1201,6 +1201,11 @@ namespace RTC
MS_DEBUG_DEV("%" PRIu64 " bytes of DTLS data ready to sent to the peer", read);
+ if (read > DtlsMtu)
+ {
+ MS_DUMP("--- WARNING: sending data with length %" PRIi64 " bytes > DTMS MTU %i", read, DtlsMtu);
+ }
+
// Notify the listener.
this->listener->OnDtlsTransportSendData(
this, reinterpret_cast<uint8_t*>(data), static_cast<size_t>(read)); diff --git a/worker/src/RTC/WebRtcTransport.cpp b/worker/src/RTC/WebRtcTransport.cpp
index a5deb26fe..73e867ebb 100644
--- a/worker/src/RTC/WebRtcTransport.cpp
+++ b/worker/src/RTC/WebRtcTransport.cpp
@@ -1366,6 +1366,11 @@ namespace RTC
return;
}
+ if (len > 1350)
+ {
+ MS_DUMP("--- WARNING: sending data with length %zu bytes > DTMS MTU 1350", len);
+ }
+
this->iceServer->GetSelectedTuple()->Send(data, len);
// Increase send transmission. With a 16384 bits certificate it prints:
|
Fixes #1100 ### Details I cannot believe that what I've done works. So let me first explain what the problem is (which is perfectly explained in issue #1100), I hope I'm right: As commented in #1100 (comment), the problem we had is: - When it comes to send DTLS data to the remote client, `DtlsTransport::SendPendingOutgoingDtlsData()` in mediasoup calls `read = BIO_get_mem_data(...)`, and obtained `read` maybe higher than our `DtlsMtu = 1350` (for example in DTLS Server Hello message if our certificate is very large). Let's say that `read` is 3000 bytes which is higher than 1350 so problems here. - But we enable all the MTU related stuff in OpenSSL DTLS in `DtlsTransport` so we **know** (and this is proven, see #1100 (comment)) that those 3000 bytes contain **N fragments** of a DTLS packet (in this case Server Hello). - But we don't know how long each fragment is so we cannot read and send them separately. And we don't know it because `read = BIO_get_mem_data(...)` returns the **total** size as explained above. What does this PR? - In `DtlsTransport::SendPendingOutgoingDtlsData()` we call `read = BIO_get_mem_data(...)` as usual. - If `read <= DtlsMtu` then nothing changes, we notify the listener with the full data. - If `read > DtlsMtu` then we split the total `data` into fragments of max `DtlsMtu` bytes and notify the parent separately with each of them. - So the parent (`WebRtcTransport`) will send each fragment into a separate UDP datagram. - And for whatever reason it **WORKS!** ``` DtlsTransport::SendPendingOutgoingDtlsData() | data to be sent is longer than DTLS MTU, fragmenting it [len:6987, DtlsMtu:1350] +248ms DtlsTransport::SendPendingOutgoingDtlsData() | sending fragment [offset:0, len:1350] +0ms DtlsTransport::SendPendingOutgoingDtlsData() | sending fragment [offset:1350, len:1350] +0ms DtlsTransport::SendPendingOutgoingDtlsData() | sending fragment [offset:2700, len:1350] +0ms DtlsTransport::SendPendingOutgoingDtlsData() | sending fragment [offset:4050, len:1350] +0ms DtlsTransport::SendPendingOutgoingDtlsData() | sending fragment [offset:5400, len:1350] +0ms DtlsTransport::SendPendingOutgoingDtlsData() | sending fragment [offset:6750, len:237] +0ms ``` An interesting fact is that, if I remove `SSL_OP_NO_QUERY_MTU` flag in the call to `SSL_CTX_set_options()`, then things don't work and the client/browser keeps sending DTLS Client Hello forever, meaning that the DTLS data it's receiving from mediasoup is invalid. So this is magic. How is possible that this works? AFAIU OpenSSL is generating valid DTLS **fragments** but it doesn't expose them to the application separately (see the problem description above). So does this PR work by accident??? Maybe not! Probably OpenSSL is generating DTLS fragments of **exactly** our given `DtlsMtu` size (which BTW makes sense since we call `SSL_set_mtu(this->ssl, DtlsMtu)` and `DTLS_set_link_mtu(this->ssl, DtlsMtu)`), so if we split the total DTLS data to be sent into fragments of `DtlsMtu` **exact** sizes, then we are **indeed** taking **valid** DTLS fragments, so we can send them into separate UDP datagrams to the client. **IS IT???** **DOES IT MAKE ANY SENSE???** IMHO it does, but I did **NOT** expect this to work.
I'm discarding PR #1343 because its solution is too risky and it is based on non documented OpenSSL behavior that may break in future versions of OpenSSL, plus there is a scenario in which the logic implemented in that PR would be wrong anyway. For future works on this issue (such as writing a custom bio/buffer in which OpenSSL writes so we can frame each written message), let's take the feedback, ideas and discussion in that PR #1343. Some of the useful feedback (about a potential reliable solution) in that closed PR is this one:
|
@gkrol-katmai, I may start working on a reliable solution not sure when, if you wish, please subscribe to this issue so you get notified. |
@ibc All right! I'm subscribed, and feel free to tag me whenever you want. |
Despite mediasoup setting the DTLS MTU using SSL_set_mtu and DTLS_set_link_mtu, if the certificate is large, the UDP packet may still exceed the MTU limit.
Reproduce the bug by:
Generate a large certificate:
mkdir -p server/certs && openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:4096 \ -keyout server/certs/privkey.pem -out server/certs/fullchain.pem
Run server:
Run app:
cd app npm install --legacy-peer-deps npm start
The number 4 packet in the below picture shows that the DTLS packet is 2008 bytes, which exceeds the UDP MTU.
mediasoup-large-cert.pcapng.zip
The text was updated successfully, but these errors were encountered: