9#ifndef QT_NO_NETWORKINTERFACE
12#include <qobjectdefs.h>
13#include <qscopeguard.h>
14#include <qvarlengtharray.h>
19#include <linux/if_arp.h>
20#include <linux/netlink.h>
21#include <linux/rtnetlink.h>
22#include <linux/wireless.h>
23#include <sys/socket.h>
26#define ARPHRD_PHONET 820
27#define ARPHRD_PHONET_PIPE 821
28#define ARPHRD_IEEE802154 804
29#define ARPHRD_6LOWPAN 825
39 switch (ushort(arptype)) {
41 return QNetworkInterface::Loopback;
45 if (qt_safe_ioctl(socket, SIOCGIWMODE, req) >= 0)
46 return QNetworkInterface::Wifi;
47 return QNetworkInterface::Ethernet;
53 return QNetworkInterface::Slip;
56 return QNetworkInterface::CanBus;
59 return QNetworkInterface::Ppp;
62 return QNetworkInterface::Fddi;
64 case ARPHRD_IEEE80211:
65 case ARPHRD_IEEE80211_PRISM:
66 case ARPHRD_IEEE80211_RADIOTAP:
67 return QNetworkInterface::Ieee80211;
70 return QNetworkInterface::Ieee802154;
74 return QNetworkInterface::Phonet;
77 return QNetworkInterface::SixLoWPAN;
83 return QNetworkInterface::Virtual;
85 return QNetworkInterface::Unknown;
91template <
typename Lambda>
struct ProcessNetlinkRequest
93 using FunctionTraits = QtPrivate::FunctionPointer<
decltype(&Lambda::operator())>;
94 using FirstArgumentPointer =
typename FunctionTraits::Arguments::Car;
95 using FirstArgument = std::remove_pointer_t<FirstArgumentPointer>;
96 static_assert(std::is_pointer_v<FirstArgumentPointer>);
97 static_assert(std::is_aggregate_v<FirstArgument>);
99 static int expectedTypeForRequest(
int rtype)
101 static_assert(RTM_NEWADDR == RTM_GETADDR - 2);
102 static_assert(RTM_NEWLINK == RTM_GETLINK - 2);
103 Q_ASSERT(rtype == RTM_GETADDR || rtype == RTM_GETLINK);
107 void operator()(
int sock, nlmsghdr *hdr,
char *buf, size_t bufsize, Lambda &&func)
110 if (send(sock, hdr, hdr->nlmsg_len, 0) != ssize_t(hdr->nlmsg_len))
114 int expectedType = expectedTypeForRequest(hdr->nlmsg_type);
115 const bool isDump = hdr->nlmsg_flags & NLM_F_DUMP;
117 qsizetype len = recv(sock, buf, bufsize, 0);
118 hdr =
reinterpret_cast<
struct nlmsghdr *>(buf);
119 if (!NLMSG_OK(hdr, quint32(len)))
122 auto arg =
static_cast<FirstArgument *>(NLMSG_DATA(hdr));
123 size_t payloadLen = NLMSG_PAYLOAD(hdr, 0);
126 Q_ASSERT(isDump == !!(hdr->nlmsg_flags & NLM_F_MULTI));
129 if (hdr->nlmsg_type == expectedType && payloadLen >=
sizeof(FirstArgument))
130 return void(func(arg, payloadLen));
134 if (hdr->nlmsg_type == NLMSG_DONE)
136 if (hdr->nlmsg_type != expectedType || payloadLen <
sizeof(FirstArgument))
138 func(arg, payloadLen);
141 hdr = NLMSG_NEXT(hdr, len);
142 arg =
static_cast<FirstArgument *>(NLMSG_DATA(hdr));
143 payloadLen = NLMSG_PAYLOAD(hdr, 0);
144 }
while (NLMSG_OK(hdr, quint32(len)));
151 if (NLMSG_OK(hdr, quint32(len)))
152 qWarning(
"QNetworkInterface/AF_NETLINK: received unknown packet type (%d) or too short (%u)",
153 hdr->nlmsg_type, hdr->nlmsg_len);
155 qWarning(
"QNetworkInterface/AF_NETLINK: received invalid packet with size %d",
int(len));
162template <
typename Lambda>
163void processNetlinkRequest(
int sock,
struct nlmsghdr *hdr,
char *buf, size_t bufsize, Lambda &&l)
165 ProcessNetlinkRequest<Lambda>()(sock, hdr, buf, bufsize,
std::forward<Lambda>(l));
172 if (name.size() >= IFNAMSIZ)
175 int socket = qt_safe_socket(AF_INET, SOCK_DGRAM, 0);
179 strcpy(req.ifr_name, name.toLatin1().constData());
181 if (qt_safe_ioctl(socket, SIOCGIFINDEX, &req) >= 0)
182 index = req.ifr_ifindex;
183 qt_safe_close(socket);
190 int socket = qt_safe_socket(AF_INET, SOCK_DGRAM, 0);
193 req.ifr_ifindex = index;
195 if (qt_safe_ioctl(socket, SIOCGIFNAME, &req) >= 0) {
196 qt_safe_close(socket);
197 return QString::fromLatin1(req.ifr_name);
199 qt_safe_close(socket);
206 QList<QNetworkInterfacePrivate *> result;
212 struct ifinfomsg ifi;
214 memset(&ifi_req, 0,
sizeof(ifi_req));
216 ifi_req.req.nlmsg_len =
sizeof(ifi_req);
217 ifi_req.req.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
218 ifi_req.req.nlmsg_type = RTM_GETLINK;
221 processNetlinkRequest(sock, &ifi_req.req, buf, BufferSize, [&](ifinfomsg *ifi, size_t len) {
224 iface->flags = convertFlags(ifi->ifi_flags);
227 auto rta =
reinterpret_cast<
struct rtattr *>(ifi + 1);
229 for ( ; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
230 int payloadLen = RTA_PAYLOAD(rta);
231 auto payloadPtr =
reinterpret_cast<
char *>(RTA_DATA(rta));
233 switch (rta->rta_type) {
235 iface->hardwareAddress =
236 iface->makeHwAddress(payloadLen,
reinterpret_cast<uchar *>(payloadPtr));
240 Q_ASSERT(payloadLen <=
int(
sizeof(req.ifr_name)));
241 memcpy(req.ifr_name, payloadPtr, payloadLen);
242 iface->name = QString::fromLatin1(payloadPtr, payloadLen - 1);
246 Q_ASSERT(payloadLen ==
sizeof(
int));
247 iface
->mtu = *
reinterpret_cast<
int *>(payloadPtr);
251 if (*payloadPtr != IF_OPER_UNKNOWN) {
253 iface->flags &= ~QNetworkInterface::IsRunning;
254 if (*payloadPtr == IF_OPER_UP)
255 iface->flags |= QNetworkInterface::IsRunning;
261 if (Q_UNLIKELY(iface->name.isEmpty())) {
262 qWarning(
"QNetworkInterface: found interface %d with no name", iface
->index);
265 iface->type = probeIfType(sock, &req, ifi->ifi_type);
266 result.append(iface);
272static void getAddresses(
int sock,
char *buf, QList<QNetworkInterfacePrivate *> &result)
277 struct ifaddrmsg ifa;
279 memset(&ifa_req, 0,
sizeof(ifa_req));
281 ifa_req.req.nlmsg_len =
sizeof(ifa_req);
282 ifa_req.req.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
283 ifa_req.req.nlmsg_type = RTM_GETADDR;
284 ifa_req.req.nlmsg_seq = 1;
287 processNetlinkRequest(sock, &ifa_req.req, buf, BufferSize, [&](ifaddrmsg *ifa, size_t len) {
288 if (Q_UNLIKELY(ifa->ifa_family != AF_INET && ifa->ifa_family !=
AF_INET6)) {
295 for (
auto candidate : std::as_const(result)) {
296 if (candidate->index !=
int(ifa->ifa_index))
302 if (Q_UNLIKELY(!iface)) {
303 qWarning(
"QNetworkInterface/AF_NETLINK: found unknown interface with index %d", ifa->ifa_index);
308 quint32 flags = ifa->ifa_flags;
310 auto makeAddress = [=](uchar *ptr,
int len) {
312 if (ifa->ifa_family == AF_INET) {
314 addr.setAddress(qFromBigEndian<quint32>(ptr));
317 addr.setAddress(ptr);
320 if (addr.isLinkLocal())
321 addr.setScopeId(iface->name);
327 auto rta =
reinterpret_cast<
struct rtattr *>(ifa + 1);
329 for ( ; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
330 int payloadLen = RTA_PAYLOAD(rta);
331 auto payloadPtr =
reinterpret_cast<uchar *>(RTA_DATA(rta));
333 switch (rta->rta_type) {
336 if (entry.ip().isNull())
337 entry.setIp(makeAddress(payloadPtr, payloadLen));
342 entry.setIp(makeAddress(payloadPtr, payloadLen));
346 Q_ASSERT(ifa->ifa_family == AF_INET);
347 entry.setBroadcast(makeAddress(payloadPtr, payloadLen));
351 if (size_t(payloadLen) >=
sizeof(ifa_cacheinfo)) {
352 auto cacheinfo =
reinterpret_cast<ifa_cacheinfo *>(payloadPtr);
353 auto toDeadline = [](quint32 lifetime) -> QDeadlineTimer {
354 if (lifetime == quint32(-1))
355 return QDeadlineTimer::Forever;
356 return QDeadlineTimer(lifetime * 1000);
358 entry.setAddressLifetime(toDeadline(cacheinfo->ifa_prefered), toDeadline(cacheinfo->ifa_valid));
363 Q_ASSERT(payloadLen == 4);
364 flags = qFromUnaligned<quint32>(payloadPtr);
369 if (ifa->ifa_family ==
AF_INET6 && (ifa->ifa_flags & IFA_F_DADFAILED))
373 QNetworkInterfacePrivate::calculateDnsEligibility(&entry,
374 flags & IFA_F_TEMPORARY,
375 flags & IFA_F_DEPRECATED);
378 if (!entry.ip().isNull()) {
379 entry.setPrefixLength(ifa->ifa_prefixlen);
380 iface->addressEntries.append(entry);
388 QList<QNetworkInterfacePrivate *> result;
389 int sock = qt_safe_socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
391 qErrnoWarning(
"Could not create AF_NETLINK socket");
395 const auto sg = qScopeGuard([&] { qt_safe_close(sock); });
398 const int bufferSize = BufferSize;
399 setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &bufferSize,
sizeof(bufferSize));
401 QByteArray buffer(BufferSize, Qt::Uninitialized);
402 char *buf = buffer.data();
404 result = getInterfaces(sock, buf);
405 getAddresses(sock, buf, result);
The QNetworkAddressEntry class stores one IP address supported by a network interface,...
#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
static QList< QNetworkInterfacePrivate * > getInterfaces(int sock, char *buf)