summaryrefslogtreecommitdiffstats
path: root/src/network/socket/qnativesocketengine_unix.cpp
diff options
context:
space:
mode:
authorIvan Solovev <[email protected]>2025-09-22 11:47:14 +0200
committerIvan Solovev <[email protected]>2025-10-09 16:43:12 +0200
commit83fc4ff9c20eb922113e08ba8566e077ce44dea3 (patch)
tree61a399b1f23e06cba5d5fcb3e8eedbd30d3f1074 /src/network/socket/qnativesocketengine_unix.cpp
parente9778dfe6ead0c4d704570816a56aead084a0263 (diff)
Allow binding a socket to a specific QNetworkInterface
For now, via a private API. Provide a new socket engine option - BindInterfaceIndex, and use it if a valid interface is passed to QAbstractSocketPrivate::bind(). Note that this feature is not fully functional on macOS: both SO_BINDTODEVICE and IP{V6}_BOUND_IF only work for limiting outgoing datagrams. The patch uses IP{V6}_BOUND_IF, because it allows to avoid number -> string -> number conversion. As of now, extra filtering of incoming data should be done on the user side. Task-number: QTBUG-80704 Task-number: QTBUG-139697 Pick-to: 6.10 6.8 Change-Id: Ic207908313d9d25f96c23ecc363181ff0ae8232a Reviewed-by: Thiago Macieira <[email protected]> Reviewed-by: MÃ¥rten Nordheim <[email protected]>
Diffstat (limited to 'src/network/socket/qnativesocketengine_unix.cpp')
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp26
1 files changed, 25 insertions, 1 deletions
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index a9bc2d92b44..b5fbb5c2e00 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -11,6 +11,7 @@
#include "qhostaddress.h"
#include "qvarlengtharray.h"
#include "qnetworkinterface.h"
+#include "qnetworkinterface_p.h"
#include "qendian.h"
#ifdef Q_OS_WASM
#include <private/qeventdispatcher_wasm_p.h>
@@ -82,6 +83,9 @@ static void convertToLevelAndOption(QNativeSocketEngine::SocketOption opt,
case QNativeSocketEngine::MaxStreamsSocketOption:
Q_UNREACHABLE();
+ case QNativeSocketEngine::BindInterfaceIndex:
+ Q_UNREACHABLE(); // handled directly in setOption()
+
case QNativeSocketEngine::BroadcastSocketOption:
n = SO_BROADCAST;
break;
@@ -373,7 +377,27 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
#endif
return false;
}
-
+ case QNativeSocketEngine::BindInterfaceIndex: {
+#if defined(SO_BINDTOIFINDEX) // seen on Linux
+ return ::setsockopt(socketDescriptor, SOL_SOCKET, SO_BINDTOIFINDEX,
+ &v, sizeof(v)) == 0;
+#elif defined(IPV6_BOUND_IF) && defined(IP_BOUND_IF) // seen on Darwin
+ // note: on Darwin, this only limits sending the data, not receiving it
+ if (socketProtocol == QAbstractSocket::IPv6Protocol
+ || socketProtocol == QAbstractSocket::AnyIPProtocol) {
+ return ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_BOUND_IF, &v, sizeof(v)) == 0;
+ } else {
+ return ::setsockopt(socketDescriptor, IPPROTO_IP, IP_BOUND_IF, &v, sizeof(v)) == 0;
+ }
+#elif defined(SO_BINDTODEVICE) && QT_CONFIG(networkinterface)
+ // need to convert to interface name
+ const QByteArray name = QNetworkInterfaceManager::interfaceNameFromIndex(v).toLatin1();
+ return ::setsockopt(socketDescriptor, SOL_SOCKET, SO_BINDTODEVICE,
+ name.data(), socklen_t(name.size())) == 0;
+#else
+ return false;
+#endif
+ }
default:
break;
}