Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qnetworkinterface_linux.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 Intel Corporation.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qnetworkinterface.h"
7
8#ifndef QT_NO_NETWORKINTERFACE
9
10#include <qendian.h>
11#include <qobjectdefs.h>
12#include <qvarlengtharray.h>
13
14// according to rtnetlink(7)
15#include <asm/types.h>
16#include <linux/if.h>
17#include <linux/if_arp.h>
18#include <linux/netlink.h>
19#include <linux/rtnetlink.h>
20#include <linux/wireless.h>
21#include <sys/socket.h>
22
23/* in case these aren't defined in linux/if_arp.h (added since 2.6.28) */
24#define ARPHRD_PHONET 820 /* v2.6.29: PhoNet media type */
25#define ARPHRD_PHONET_PIPE 821 /* v2.6.29: PhoNet pipe header */
26#define ARPHRD_IEEE802154 804 /* v2.6.31 */
27#define ARPHRD_6LOWPAN 825 /* v3.14: IPv6 over LoWPAN */
28
30
31enum {
32 BufferSize = 8192
33};
34
35static QNetworkInterface::InterfaceType probeIfType(int socket, struct ifreq *req, short arptype)
36{
37 switch (ushort(arptype)) {
38 case ARPHRD_LOOPBACK:
40
41 case ARPHRD_ETHER:
42 // check if it's a WiFi interface
43 if (qt_safe_ioctl(socket, SIOCGIWMODE, req) >= 0)
46
47 case ARPHRD_SLIP:
48 case ARPHRD_CSLIP:
49 case ARPHRD_SLIP6:
50 case ARPHRD_CSLIP6:
52
53 case ARPHRD_CAN:
55
56 case ARPHRD_PPP:
58
59 case ARPHRD_FDDI:
61
62 case ARPHRD_IEEE80211:
63 case ARPHRD_IEEE80211_PRISM:
64 case ARPHRD_IEEE80211_RADIOTAP:
66
69
70 case ARPHRD_PHONET:
73
74 case ARPHRD_6LOWPAN:
76
77 case ARPHRD_TUNNEL:
78 case ARPHRD_TUNNEL6:
79 case ARPHRD_NONE:
80 case ARPHRD_VOID:
82 }
84}
85
86
87namespace {
88struct NetlinkSocket
89{
90 int sock;
91 NetlinkSocket(int bufferSize)
92 {
93 sock = qt_safe_socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
94 if (Q_UNLIKELY(sock == -1))
95 qErrnoWarning("Could not create AF_NETLINK socket");
96
97 // set buffer length
98 socklen_t len = sizeof(bufferSize);
99 setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &bufferSize, len);
100 }
101
102 ~NetlinkSocket()
103 {
104 if (sock != -1)
105 qt_safe_close(sock);
106 }
107
108 operator int() const { return sock; }
109};
110
111template <typename Lambda> struct ProcessNetlinkRequest
112{
113 using FunctionTraits = QtPrivate::FunctionPointer<decltype(&Lambda::operator())>;
114 using FirstArgumentPointer = typename FunctionTraits::Arguments::Car;
115 using FirstArgument = std::remove_pointer_t<FirstArgumentPointer>;
116 static_assert(std::is_pointer_v<FirstArgumentPointer>);
117 static_assert(std::is_aggregate_v<FirstArgument>);
118
119 static int expectedTypeForRequest(int rtype)
120 {
121 static_assert(RTM_NEWADDR == RTM_GETADDR - 2);
122 static_assert(RTM_NEWLINK == RTM_GETLINK - 2);
123 Q_ASSERT(rtype == RTM_GETADDR || rtype == RTM_GETLINK);
124 return rtype - 2;
125 }
126
127 void operator()(int sock, nlmsghdr *hdr, char *buf, size_t bufsize, Lambda &&func)
128 {
129 // send the request
130 if (send(sock, hdr, hdr->nlmsg_len, 0) != ssize_t(hdr->nlmsg_len))
131 return;
132
133 // receive and parse the request
134 int expectedType = expectedTypeForRequest(hdr->nlmsg_type);
135 const bool isDump = hdr->nlmsg_flags & NLM_F_DUMP;
136 forever {
137 qsizetype len = recv(sock, buf, bufsize, 0);
138 hdr = reinterpret_cast<struct nlmsghdr *>(buf);
139 if (!NLMSG_OK(hdr, quint32(len)))
140 return;
141
142 auto arg = static_cast<FirstArgument *>(NLMSG_DATA(hdr));
143 size_t payloadLen = NLMSG_PAYLOAD(hdr, 0);
144
145 // is this a multipart message?
146 Q_ASSERT(isDump == !!(hdr->nlmsg_flags & NLM_F_MULTI));
147 if (!isDump) {
148 // no, single message
149 if (hdr->nlmsg_type == expectedType && payloadLen >= sizeof(FirstArgument))
150 return void(func(arg, payloadLen));
151 } else {
152 // multipart, parse until done
153 do {
154 if (hdr->nlmsg_type == NLMSG_DONE)
155 return;
156 if (hdr->nlmsg_type != expectedType || payloadLen < sizeof(FirstArgument))
157 break;
158 func(arg, payloadLen);
159
160 // NLMSG_NEXT also updates the len variable
161 hdr = NLMSG_NEXT(hdr, len);
162 arg = static_cast<FirstArgument *>(NLMSG_DATA(hdr));
163 payloadLen = NLMSG_PAYLOAD(hdr, 0);
164 } while (NLMSG_OK(hdr, quint32(len)));
165
166 if (len == 0)
167 continue; // get new datagram
168 }
169
170#ifndef QT_NO_DEBUG
171 if (NLMSG_OK(hdr, quint32(len)))
172 qWarning("QNetworkInterface/AF_NETLINK: received unknown packet type (%d) or too short (%u)",
173 hdr->nlmsg_type, hdr->nlmsg_len);
174 else
175 qWarning("QNetworkInterface/AF_NETLINK: received invalid packet with size %d", int(len));
176#endif
177 return;
178 }
179 }
180};
181
182template <typename Lambda>
183void processNetlinkRequest(int sock, struct nlmsghdr *hdr, char *buf, size_t bufsize, Lambda &&l)
184{
185 ProcessNetlinkRequest<Lambda>()(sock, hdr, buf, bufsize, std::forward<Lambda>(l));
186}
187}
188
190{
191 uint index = 0;
192 if (name.size() >= IFNAMSIZ)
193 return index;
194
195 int socket = qt_safe_socket(AF_INET, SOCK_DGRAM, 0);
196 if (socket >= 0) {
197 struct ifreq req;
198 req.ifr_ifindex = 0;
199 strcpy(req.ifr_name, name.toLatin1().constData());
200
201 if (qt_safe_ioctl(socket, SIOCGIFINDEX, &req) >= 0)
202 index = req.ifr_ifindex;
204 }
205 return index;
206}
207
209{
210 int socket = qt_safe_socket(AF_INET, SOCK_DGRAM, 0);
211 if (socket >= 0) {
212 struct ifreq req;
213 req.ifr_ifindex = index;
214
215 if (qt_safe_ioctl(socket, SIOCGIFNAME, &req) >= 0) {
217 return QString::fromLatin1(req.ifr_name);
218 }
220 }
221 return QString();
222}
223
224static QList<QNetworkInterfacePrivate *> getInterfaces(int sock, char *buf)
225{
226 QList<QNetworkInterfacePrivate *> result;
227 struct ifreq req;
228
229 // request all links
230 struct {
231 struct nlmsghdr req;
232 struct ifinfomsg ifi;
233 } ifi_req;
234 memset(&ifi_req, 0, sizeof(ifi_req));
235
236 ifi_req.req.nlmsg_len = sizeof(ifi_req);
237 ifi_req.req.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
238 ifi_req.req.nlmsg_type = RTM_GETLINK;
239
240 // parse the interfaces
241 processNetlinkRequest(sock, &ifi_req.req, buf, BufferSize, [&](ifinfomsg *ifi, size_t len) {
242 auto iface = new QNetworkInterfacePrivate;
243 iface->index = ifi->ifi_index;
244 iface->flags = convertFlags(ifi->ifi_flags);
245
246 // read attributes
247 auto rta = reinterpret_cast<struct rtattr *>(ifi + 1);
248 len -= sizeof(*ifi);
249 for ( ; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
250 int payloadLen = RTA_PAYLOAD(rta);
251 auto payloadPtr = reinterpret_cast<char *>(RTA_DATA(rta));
252
253 switch (rta->rta_type) {
254 case IFLA_ADDRESS: // link-level address
255 iface->hardwareAddress =
256 iface->makeHwAddress(payloadLen, reinterpret_cast<uchar *>(payloadPtr));
257 break;
258
259 case IFLA_IFNAME: // interface name
260 Q_ASSERT(payloadLen <= int(sizeof(req.ifr_name)));
261 memcpy(req.ifr_name, payloadPtr, payloadLen); // including terminating NUL
262 iface->name = QString::fromLatin1(payloadPtr, payloadLen - 1);
263 break;
264
265 case IFLA_MTU:
266 Q_ASSERT(payloadLen == sizeof(int));
267 iface->mtu = *reinterpret_cast<int *>(payloadPtr);
268 break;
269
270 case IFLA_OPERSTATE: // operational state
271 if (*payloadPtr != IF_OPER_UNKNOWN) {
272 // override the flag
273 iface->flags &= ~QNetworkInterface::IsRunning;
274 if (*payloadPtr == IF_OPER_UP)
275 iface->flags |= QNetworkInterface::IsRunning;
276 }
277 break;
278 }
279 }
280
281 if (Q_UNLIKELY(iface->name.isEmpty())) {
282 qWarning("QNetworkInterface: found interface %d with no name", iface->index);
283 delete iface;
284 } else {
285 iface->type = probeIfType(sock, &req, ifi->ifi_type);
286 result.append(iface);
287 }
288 });
289 return result;
290}
291
292static void getAddresses(int sock, char *buf, QList<QNetworkInterfacePrivate *> &result)
293{
294 // request all addresses
295 struct {
296 struct nlmsghdr req;
297 struct ifaddrmsg ifa;
298 } ifa_req;
299 memset(&ifa_req, 0, sizeof(ifa_req));
300
301 ifa_req.req.nlmsg_len = sizeof(ifa_req);
302 ifa_req.req.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
303 ifa_req.req.nlmsg_type = RTM_GETADDR;
304 ifa_req.req.nlmsg_seq = 1;
305
306 // parse the addresses
307 processNetlinkRequest(sock, &ifa_req.req, buf, BufferSize, [&](ifaddrmsg *ifa, size_t len) {
308 if (Q_UNLIKELY(ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6)) {
309 // unknown address types
310 return;
311 }
312
313 // find the interface this is relevant to
314 QNetworkInterfacePrivate *iface = nullptr;
315 for (auto candidate : std::as_const(result)) {
316 if (candidate->index != int(ifa->ifa_index))
317 continue;
318 iface = candidate;
319 break;
320 }
321
322 if (Q_UNLIKELY(!iface)) {
323 qWarning("QNetworkInterface/AF_NETLINK: found unknown interface with index %d", ifa->ifa_index);
324 return;
325 }
326
328 quint32 flags = ifa->ifa_flags; // may be overwritten by IFA_FLAGS
329
330 auto makeAddress = [=](uchar *ptr, int len) {
332 if (ifa->ifa_family == AF_INET) {
333 Q_ASSERT(len == 4);
334 addr.setAddress(qFromBigEndian<quint32>(ptr));
335 } else {
336 Q_ASSERT(len == 16);
337 addr.setAddress(ptr);
338
339 // do we need a scope ID?
340 if (addr.isLinkLocal())
341 addr.setScopeId(iface->name);
342 }
343 return addr;
344 };
345
346 // read attributes
347 auto rta = reinterpret_cast<struct rtattr *>(ifa + 1);
348 len -= sizeof(*ifa);
349 for ( ; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
350 int payloadLen = RTA_PAYLOAD(rta);
351 auto payloadPtr = reinterpret_cast<uchar *>(RTA_DATA(rta));
352
353 switch (rta->rta_type) {
354 case IFA_ADDRESS:
355 // Local address (all interfaces except for point-to-point)
356 if (entry.ip().isNull())
357 entry.setIp(makeAddress(payloadPtr, payloadLen));
358 break;
359
360 case IFA_LOCAL:
361 // Override the local address (point-to-point interfaces)
362 entry.setIp(makeAddress(payloadPtr, payloadLen));
363 break;
364
365 case IFA_BROADCAST:
366 Q_ASSERT(ifa->ifa_family == AF_INET);
367 entry.setBroadcast(makeAddress(payloadPtr, payloadLen));
368 break;
369
370 case IFA_CACHEINFO:
371 if (size_t(payloadLen) >= sizeof(ifa_cacheinfo)) {
372 auto cacheinfo = reinterpret_cast<ifa_cacheinfo *>(payloadPtr);
373 auto toDeadline = [](quint32 lifetime) -> QDeadlineTimer {
374 if (lifetime == quint32(-1))
376 return QDeadlineTimer(lifetime * 1000);
377 };
378 entry.setAddressLifetime(toDeadline(cacheinfo->ifa_prefered), toDeadline(cacheinfo->ifa_valid));
379 }
380 break;
381
382 case IFA_FLAGS:
383 Q_ASSERT(payloadLen == 4);
384 flags = qFromUnaligned<quint32>(payloadPtr);
385 break;
386 }
387 }
388
389 if (ifa->ifa_family == AF_INET6 && (ifa->ifa_flags & IFA_F_DADFAILED))
390 return;
391
392 // now handle flags
394 flags & IFA_F_TEMPORARY,
395 flags & IFA_F_DEPRECATED);
396
397
398 if (!entry.ip().isNull()) {
399 entry.setPrefixLength(ifa->ifa_prefixlen);
400 iface->addressEntries.append(entry);
401 }
402 });
403}
404
405QList<QNetworkInterfacePrivate *> QNetworkInterfaceManager::scan()
406{
407 // open netlink socket
408 QList<QNetworkInterfacePrivate *> result;
409 NetlinkSocket sock(BufferSize);
410 if (Q_UNLIKELY(sock == -1))
411 return result;
412
414 char *buf = buffer.data();
415
418
419 return result;
420}
421
423
424#endif // QT_NO_NETWORKINTERFACE
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
static constexpr ForeverConstant Forever
The QHostAddress class provides an IP address.
The QNetworkAddressEntry class stores one IP address supported by a network interface,...
static uint interfaceIndexFromName(const QString &name)
static QString interfaceNameFromIndex(uint index)
static void calculateDnsEligibility(QNetworkAddressEntry *entry, bool isTemporary, bool isDeprecated)
InterfaceType
Specifies the type of hardware (PHY layer, OSI level 1) this interface is, if it could be determined.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
void qErrnoWarning(const char *msg,...)
Combined button and popup list for selecting options.
constexpr Initialization Uninitialized
#define Q_UNLIKELY(x)
static int qt_safe_close(int fd)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
static constexpr int BufferSize
#define forever
Definition qforeach.h:78
#define qWarning
Definition qlogging.h:166
static ControlElement< T > * ptr(QWidget *widget)
#define AF_INET6
static int qt_safe_ioctl(int sockfd, unsigned long request, T arg)
static int qt_safe_socket(int domain, int type, int protocol, int flags=0)
Definition qnet_unix_p.h:45
#define ARPHRD_PHONET
#define ARPHRD_PHONET_PIPE
static void getAddresses(int sock, char *buf, QList< QNetworkInterfacePrivate * > &result)
static QNetworkInterface::InterfaceType probeIfType(int socket, struct ifreq *req, short arptype)
#define ARPHRD_IEEE802154
#define ARPHRD_6LOWPAN
static QList< QNetworkInterfacePrivate * > getInterfaces(int sock, char *buf)
GLuint index
[2]
GLenum GLuint buffer
GLenum GLuint GLenum GLsizei const GLchar * buf
GLbitfield flags
GLsizei bufsize
GLuint name
GLenum func
Definition qopenglext.h:663
GLuint entry
GLenum const void * addr
GLuint64EXT * result
[6]
GLenum GLsizei len
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
unsigned int quint32
Definition qtypes.h:50
unsigned char uchar
Definition qtypes.h:32
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned int uint
Definition qtypes.h:34
unsigned short ushort
Definition qtypes.h:33
if(qFloatDistance(a, b)<(1<< 7))
[0]
QTcpSocket sock
[2]
QTcpSocket * socket
[1]