diff --git a/src/generic_io.h b/src/generic_io.h index 6f67b24eab1ef6f0419b5f7be9da2ba84a21316a..4147959c92759ec40f7eb78ccbad72a25174200f 100644 --- a/src/generic_io.h +++ b/src/generic_io.h @@ -20,6 +20,8 @@ #pragma once +#include "ip_utils.h" + #include <functional> #include <vector> #include <system_error> @@ -100,6 +102,16 @@ public: return res; } + /// Return the local IP address if known. + /// \note The address is not valid (addr.isUnspecified() returns true) if it's not known + /// or not available. + virtual IpAddr localAddr() const { return {}; } + + /// Return the remote IP address if known. + /// \note The address is not valid (addr.isUnspecified() returns true) if it's not known + /// or not available. + virtual IpAddr remoteAddr() const { return {}; } + protected: GenericSocket() = default; }; diff --git a/src/ice_socket.h b/src/ice_socket.h index a61413aca030be254b8f4b03b32ccdb03797c1e9..b05ae3f6a05f04e84cf61cc9a0150786df009bd5 100644 --- a/src/ice_socket.h +++ b/src/ice_socket.h @@ -87,6 +87,10 @@ public: void setOnRecv(RecvCb&& cb) override; + IpAddr localAddr() const override; + + IpAddr remoteAddr() const override; + private: const int compId_; std::shared_ptr<IceTransport> ice_; diff --git a/src/ice_transport.cpp b/src/ice_transport.cpp index a7fdf5e0de43461926ee1fff255f719c81b40f40..4e02c26378a1e5b83f989b26a30ca9a0eb8f7850 100644 --- a/src/ice_transport.cpp +++ b/src/ice_transport.cpp @@ -1226,6 +1226,18 @@ IceSocketTransport::read(ValueType* buf, std::size_t len, std::error_code& ec) return res; } +IpAddr +IceSocketTransport::localAddr() const +{ + return ice_->getLocalAddress(compId_); +} + +IpAddr +IceSocketTransport::remoteAddr() const +{ + return ice_->getRemoteAddress(compId_); +} + //============================================================================== void diff --git a/src/security/tls_session.cpp b/src/security/tls_session.cpp index b336a4366f462fea77f5a55543f013b3e765ec22..eaee14128bbf6986a06b1d58adb6bba4ab1d2033 100644 --- a/src/security/tls_session.cpp +++ b/src/security/tls_session.cpp @@ -68,6 +68,7 @@ static constexpr auto HEARTBEAT_RETRANS_TIMEOUT = std::chrono::milliseconds(700) static constexpr auto HEARTBEAT_TOTAL_TIMEOUT = HEARTBEAT_RETRANS_TIMEOUT * HEARTBEAT_TRIES; // gnutls heartbeat time limit for heartbeat procedure (in milliseconds) static constexpr int MISS_ORDERING_LIMIT = 32; // maximal accepted distance of out-of-order packet (note: must be a signed type) static constexpr auto RX_OOO_TIMEOUT = std::chrono::milliseconds(1500); +static constexpr int ASYMETRIC_TRANSPORT_MTU_OFFSET = 20; // when client, if your local IP is IPV4 and server is IPV6; you must reduce your MTU to avoid packet too big error on server side. the offset is the difference in size of IP headers // Helper to cast any duration into an integer number of milliseconds template <class Rep, class Period> @@ -923,13 +924,26 @@ TlsSession::TlsSessionImpl::pathMtuHeartbeat() HEARTBEAT_TOTAL_TIMEOUT.count()); int errno_send = GNUTLS_E_SUCCESS; + int mtuOffset = 0; + + // when the remote (server) has a IPV6 interface selected by ICE, and local (client) has a IPV4 selected, + // the path MTU discovery triggers errors for packets too big on server side because of different IP headers overhead. + // Hence we have to signal to the TLS session to reduce the MTU on client size accordingly. + if (transport_.localAddr().isIpv4() and transport_.remoteAddr().isIpv6()) { + mtuOffset = ASYMETRIC_TRANSPORT_MTU_OFFSET; + RING_WARN() << "[TLS] local/remote IP protocol version not alike, use an MTU offset of " + << ASYMETRIC_TRANSPORT_MTU_OFFSET << " bytes to compensate"; + } + mtuProbe_ = MTUS_[0]; + for (auto mtu: MTUS_) { gnutls_dtls_set_mtu(session_, mtu); auto data_mtu = gnutls_dtls_get_data_mtu(session_); RING_DBG() << "[TLS] PMTUD: mtu " << mtu << ", payload " << data_mtu; - auto bytesToSend = data_mtu - 3; // want to know why -3? ask gnutls! + auto bytesToSend = data_mtu - mtuOffset - 3; // want to know why -3? ask gnutls! + do { errno_send = gnutls_heartbeat_ping(session_, bytesToSend, HEARTBEAT_TRIES, GNUTLS_HEARTBEAT_WAIT); } while (errno_send == GNUTLS_E_AGAIN || errno_send == GNUTLS_E_INTERRUPTED);