1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Copyright (C) 2016 Intel Corporation.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the QtNetwork module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or (at your option) the GNU General
29 ** Public license version 3 or any later version approved by the KDE Free
30 ** Qt Foundation. The licenses are as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32 ** included in the packaging of this file. Please review the following
33 ** information to ensure the GNU General Public License requirements will
34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35 ** https://www.gnu.org/licenses/gpl-3.0.html.
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41 #define WIN32_LEAN_AND_MEAN 1
42
43 #include "qnetworkinterface.h"
44 #include "qnetworkinterface_p.h"
45
46 #ifndef QT_NO_NETWORKINTERFACE
47
48 #include <qhostinfo.h>
49 #include <qhash.h>
50 #include <qurl.h>
51
52 // Since we need to include winsock2.h, we need to define WIN32_LEAN_AND_MEAN
53 // (above) so windows.h won't include winsock.h.
54 // In addition, we need to include winsock2.h before iphlpapi.h and we need
55 // to include ws2ipdef.h to work around an MinGW-w64 bug
56 // (http://sourceforge.net/p/mingw-w64/mailman/message/32935366/)
57 #include <winsock2.h>
58 #include <ws2ipdef.h>
59 #include <wincrypt.h>
60 #include <iphlpapi.h>
61 #include <ws2tcpip.h>
62
63 #include <qt_windows.h>
64
65 // In case these aren't defined
66 #define IF_TYPE_IEEE80216_WMAN 237
67 #define IF_TYPE_IEEE802154 259
68
69 QT_BEGIN_NAMESPACE
70
addressFromSockaddr(sockaddr * sa)71 static QHostAddress addressFromSockaddr(sockaddr *sa)
72 {
73 QHostAddress address;
74 if (!sa)
75 return address;
76
77 if (sa->sa_family == AF_INET) {
78 address.setAddress(htonl(reinterpret_cast<const sockaddr_in *>(sa)->sin_addr.s_addr));
79 } else if (sa->sa_family == AF_INET6) {
80 auto sai6 = reinterpret_cast<const sockaddr_in6 *>(sa);
81 address.setAddress(sai6->sin6_addr.s6_addr);
82 if (sai6->sin6_scope_id)
83 address.setScopeId(QNetworkInterfaceManager::interfaceNameFromIndex(sai6->sin6_scope_id));
84 } else {
85 qWarning("Got unknown socket family %d", sa->sa_family);
86 }
87 return address;
88
89 }
90
interfaceIndexFromName(const QString & name)91 uint QNetworkInterfaceManager::interfaceIndexFromName(const QString &name)
92 {
93 NET_IFINDEX id;
94 NET_LUID luid;
95 if (ConvertInterfaceNameToLuidW(reinterpret_cast<const wchar_t *>(name.constData()), &luid) == NO_ERROR
96 && ConvertInterfaceLuidToIndex(&luid, &id) == NO_ERROR)
97 return uint(id);
98 return 0;
99 }
100
interfaceNameFromIndex(uint index)101 QString QNetworkInterfaceManager::interfaceNameFromIndex(uint index)
102 {
103 NET_LUID luid;
104 if (ConvertInterfaceIndexToLuid(index, &luid) == NO_ERROR) {
105 WCHAR buf[IF_MAX_STRING_SIZE + 1];
106 if (ConvertInterfaceLuidToNameW(&luid, buf, sizeof(buf)/sizeof(buf[0])) == NO_ERROR)
107 return QString::fromWCharArray(buf);
108 }
109 return QString::number(index);
110 }
111
interfaceListing()112 static QList<QNetworkInterfacePrivate *> interfaceListing()
113 {
114 QList<QNetworkInterfacePrivate *> interfaces;
115 IP_ADAPTER_ADDRESSES staticBuf[2]; // 2 is arbitrary
116 PIP_ADAPTER_ADDRESSES pAdapter = staticBuf;
117 ULONG bufSize = sizeof staticBuf;
118
119 ULONG flags = GAA_FLAG_INCLUDE_PREFIX |
120 GAA_FLAG_SKIP_DNS_SERVER |
121 GAA_FLAG_SKIP_MULTICAST;
122 ULONG retval = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAdapter, &bufSize);
123 if (retval == ERROR_BUFFER_OVERFLOW) {
124 // need more memory
125 pAdapter = reinterpret_cast<IP_ADAPTER_ADDRESSES *>(malloc(bufSize));
126 if (!pAdapter)
127 return interfaces;
128 // try again
129 if (GetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAdapter, &bufSize) != ERROR_SUCCESS) {
130 free(pAdapter);
131 return interfaces;
132 }
133 } else if (retval != ERROR_SUCCESS) {
134 // error
135 return interfaces;
136 }
137
138 // iterate over the list and add the entries to our listing
139 for (PIP_ADAPTER_ADDRESSES ptr = pAdapter; ptr; ptr = ptr->Next) {
140 // the structure grows over time, so let's make sure the fields
141 // introduced in Windows Vista are present (Luid is the furthest
142 // field we access from IP_ADAPTER_ADDRESSES_LH)
143 Q_ASSERT(ptr->Length >= offsetof(IP_ADAPTER_ADDRESSES, Luid));
144 Q_ASSERT(ptr->Length >= offsetof(IP_ADAPTER_ADDRESSES, Ipv6IfIndex));
145
146 QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate;
147 interfaces << iface;
148
149 iface->index = 0;
150 if (ptr->Ipv6IfIndex != 0)
151 iface->index = ptr->Ipv6IfIndex;
152 else if (ptr->IfIndex != 0)
153 iface->index = ptr->IfIndex;
154
155 iface->mtu = qMin<qint64>(ptr->Mtu, INT_MAX);
156 iface->flags = QNetworkInterface::CanBroadcast;
157 if (ptr->OperStatus == IfOperStatusUp)
158 iface->flags |= QNetworkInterface::IsUp | QNetworkInterface::IsRunning;
159 if ((ptr->Flags & IP_ADAPTER_NO_MULTICAST) == 0)
160 iface->flags |= QNetworkInterface::CanMulticast;
161 if (ptr->IfType == IF_TYPE_PPP)
162 iface->flags |= QNetworkInterface::IsPointToPoint;
163
164 switch (ptr->IfType) {
165 case IF_TYPE_ETHERNET_CSMACD:
166 iface->type = QNetworkInterface::Ethernet;
167 break;
168
169 case IF_TYPE_FDDI:
170 iface->type = QNetworkInterface::Fddi;
171 break;
172
173 case IF_TYPE_PPP:
174 iface->type = QNetworkInterface::Ppp;
175 break;
176
177 case IF_TYPE_SLIP:
178 iface->type = QNetworkInterface::Slip;
179 break;
180
181 case IF_TYPE_SOFTWARE_LOOPBACK:
182 iface->type = QNetworkInterface::Loopback;
183 iface->flags |= QNetworkInterface::IsLoopBack;
184 break;
185
186 case IF_TYPE_IEEE80211:
187 iface->type = QNetworkInterface::Ieee80211;
188 break;
189
190 case IF_TYPE_IEEE1394:
191 iface->type = QNetworkInterface::Ieee1394;
192 break;
193
194 case IF_TYPE_IEEE80216_WMAN:
195 iface->type = QNetworkInterface::Ieee80216;
196 break;
197
198 case IF_TYPE_IEEE802154:
199 iface->type = QNetworkInterface::Ieee802154;
200 break;
201 }
202
203 // use ConvertInterfaceLuidToNameW because that returns a friendlier name, though not
204 // as "friendly" as FriendlyName below
205 WCHAR buf[IF_MAX_STRING_SIZE + 1];
206 if (ConvertInterfaceLuidToNameW(&ptr->Luid, buf, sizeof(buf)/sizeof(buf[0])) == NO_ERROR)
207 iface->name = QString::fromWCharArray(buf);
208 if (iface->name.isEmpty())
209 iface->name = QString::fromLocal8Bit(ptr->AdapterName);
210
211 iface->friendlyName = QString::fromWCharArray(ptr->FriendlyName);
212 if (ptr->PhysicalAddressLength)
213 iface->hardwareAddress = iface->makeHwAddress(ptr->PhysicalAddressLength,
214 ptr->PhysicalAddress);
215
216 // parse the IP (unicast) addresses
217 for (PIP_ADAPTER_UNICAST_ADDRESS addr = ptr->FirstUnicastAddress; addr; addr = addr->Next) {
218 Q_ASSERT(addr->Length >= offsetof(IP_ADAPTER_UNICAST_ADDRESS, OnLinkPrefixLength));
219
220 // skip addresses in invalid state
221 if (addr->DadState == IpDadStateInvalid)
222 continue;
223
224 QNetworkAddressEntry entry;
225 entry.setIp(addressFromSockaddr(addr->Address.lpSockaddr));
226 entry.setPrefixLength(addr->OnLinkPrefixLength);
227
228 auto toDeadline = [](ULONG lifetime) -> QDeadlineTimer {
229 if (lifetime == 0xffffffffUL)
230 return QDeadlineTimer::Forever;
231 return QDeadlineTimer(lifetime * 1000);
232 };
233 entry.setAddressLifetime(toDeadline(addr->ValidLifetime), toDeadline(addr->PreferredLifetime));
234 entry.setDnsEligibility(addr->Flags & IP_ADAPTER_ADDRESS_DNS_ELIGIBLE ?
235 QNetworkAddressEntry::DnsEligible :
236 QNetworkAddressEntry::DnsIneligible);
237
238 iface->addressEntries << entry;
239 }
240 }
241
242 if (pAdapter != staticBuf)
243 free(pAdapter);
244
245 return interfaces;
246 }
247
scan()248 QList<QNetworkInterfacePrivate *> QNetworkInterfaceManager::scan()
249 {
250 return interfaceListing();
251 }
252
localDomainName()253 QString QHostInfo::localDomainName()
254 {
255 FIXED_INFO info, *pinfo;
256 ULONG bufSize = sizeof info;
257 pinfo = &info;
258 if (GetNetworkParams(pinfo, &bufSize) == ERROR_BUFFER_OVERFLOW) {
259 pinfo = reinterpret_cast<FIXED_INFO *>(malloc(bufSize));
260 if (!pinfo)
261 return QString();
262 // try again
263 if (GetNetworkParams(pinfo, &bufSize) != ERROR_SUCCESS) {
264 free(pinfo);
265 return QString(); // error
266 }
267 }
268
269 QString domainName = QUrl::fromAce(pinfo->DomainName);
270
271 if (pinfo != &info)
272 free(pinfo);
273
274 return domainName;
275 }
276
277 QT_END_NAMESPACE
278
279 #endif // QT_NO_NETWORKINTERFACE
280