1 /*******************************************************************************
2 *
3 * Copyright (c) 2020 Jean-Francois Dockes
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * - Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * - Neither name of Intel Corporation nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 ******************************************************************************/
30 #include "netif.h"
31
32 #include <cstring>
33 #include <ostream>
34 #include <vector>
35 #include <iostream>
36 #include <algorithm>
37 #include <numeric>
38 #include <sstream>
39
40 #ifndef _WIN32
41
42 #include <sys/types.h>
43 #include <arpa/inet.h>
44 #include <netinet/in.h>
45 #include <net/if.h>
46 #include <ifaddrs.h>
47 #ifdef __linux__
48 #include <netpacket/packet.h>
49 #else
50 #include <net/if_dl.h>
51 #endif
52
53 #else /* _WIN32 -> */
54 #undef _WIN32_WINNT
55 #define _WIN32_WINNT 0x0600
56
57 #include <winsock2.h>
58 #include <iphlpapi.h>
59 #include <ws2tcpip.h>
60
61 #ifndef __MINGW32__
62 #include "inet_pton.h"
63 #endif
64
65 #endif /* _WIN32 */
66
67
68 #ifndef IN6_IS_ADDR_GLOBAL
69 #define IN6_IS_ADDR_GLOBAL(a) \
70 ((((__const uint32_t *) (a))[0] & htonl(0x70000000)) == htonl (0x20000000))
71 #endif /* IS ADDR GLOBAL */
72
73 #ifndef IN6_IS_ADDR_ULA
74 #define IN6_IS_ADDR_ULA(a) \
75 ((((__const uint32_t *) (a))[0] & htonl(0xfe000000)) == htonl (0xfc000000))
76 #endif /* IS ADDR ULA */
77
78
79 namespace NetIF {
80
81 static FILE *logfp;
82
83 // #define NETIF_DEBUG
84
85 #define LOGERR(X) do { \
86 if (logfp) { \
87 std::ostringstream oss; \
88 oss << X; \
89 fprintf(logfp, "%s", oss.str().c_str()); \
90 } \
91 } while (0)
92 #ifdef NETIF_DEBUG
93 #define LOGDEB(X) LOGERR(X)
94 #else
95 #define LOGDEB(X)
96 #endif
97
98 class IPAddr::Internal {
99 public:
100 bool ok{false};
101 struct sockaddr_storage address{};
102 struct sockaddr *saddr{nullptr};
103 };
104
IPAddr()105 IPAddr::IPAddr()
106 {
107 m = new Internal;
108 m->saddr = reinterpret_cast<struct sockaddr*>(&m->address);
109 }
110
IPAddr(const IPAddr & o)111 IPAddr::IPAddr(const IPAddr& o)
112 {
113 m = new Internal;
114 *m = *(o.m);
115 m->saddr = reinterpret_cast<struct sockaddr*>(&m->address);
116 }
117
operator =(const IPAddr & o)118 IPAddr& IPAddr::operator=(const IPAddr& o)
119 {
120 if (&o != this) {
121 delete m;
122 m = new Internal;
123 *m = *(o.m);
124 m->saddr = reinterpret_cast<struct sockaddr*>(&m->address);
125 }
126 return *this;
127 }
128
IPAddr(const char * caddr)129 IPAddr::IPAddr(const char *caddr)
130 : IPAddr()
131 {
132 if (nullptr != std::strchr(caddr, ':')) {
133 if (inet_pton(AF_INET6, caddr,
134 &reinterpret_cast<struct sockaddr_in6*>(m->saddr)->sin6_addr) == 1) {
135 m->saddr->sa_family = AF_INET6;
136 m->ok = true;
137 }
138 } else {
139 if (inet_pton(AF_INET, caddr,
140 &reinterpret_cast<struct sockaddr_in*>(m->saddr)->sin_addr) == 1) {
141 m->saddr->sa_family = AF_INET;
142 m->ok = true;
143 }
144 }
145 }
146
147 static const uint8_t ipv4mappedprefix[12] = {0,0,0,0,0,0,0,0,0,0,0xff,0xff};
148
IPAddr(const struct sockaddr * sa,bool unmapv4)149 IPAddr::IPAddr(const struct sockaddr *sa, bool unmapv4)
150 : IPAddr()
151 {
152 switch (sa->sa_family) {
153 case AF_INET:
154 memcpy(m->saddr, sa, sizeof(struct sockaddr_in));
155 m->ok = true;
156 break;
157 case AF_INET6:
158 {
159 if (unmapv4) {
160 const uint8_t *bytes =
161 reinterpret_cast<const struct sockaddr_in6 *>(sa)->sin6_addr.s6_addr;
162 if (!memcmp(bytes, ipv4mappedprefix, 12)) {
163 struct sockaddr_in *a = reinterpret_cast<struct sockaddr_in*>(m->saddr);
164 memset(a, 0, sizeof(*a));
165 a->sin_family = AF_INET;
166 memcpy(&a->sin_addr.s_addr, bytes+12, 4);
167 m->ok = true;
168 break;
169 }
170 }
171 // unmapv4==false or not a v4 mapped address, copy v6 address
172 memcpy(m->saddr, sa, sizeof(struct sockaddr_in6));
173 m->ok = true;
174 }
175 break;
176 default:
177 break;
178 }
179 }
180
~IPAddr()181 IPAddr::~IPAddr()
182 {
183 delete m;
184 }
185
ok() const186 bool IPAddr::ok() const
187 {
188 return m->ok;
189 }
190
copyToStorage(struct sockaddr_storage * dest) const191 bool IPAddr::copyToStorage(struct sockaddr_storage *dest) const
192 {
193 if (!m->ok) {
194 *dest = {};
195 return false;
196 }
197 memcpy(dest, &m->address, sizeof(struct sockaddr_storage));
198 return true;
199 }
200
copyToAddr(struct sockaddr * dest) const201 bool IPAddr::copyToAddr(struct sockaddr *dest) const
202 {
203 if (!m->ok) {
204 return false;
205 }
206 switch (m->saddr->sa_family) {
207 case AF_INET:
208 memcpy(dest, m->saddr, sizeof(struct sockaddr_in));
209 break;
210 case AF_INET6:
211 memcpy(dest, m->saddr, sizeof(struct sockaddr_in6));
212 break;
213 default:
214 return false;
215 }
216 return true;
217 }
218
getaddr() const219 const struct sockaddr_storage& IPAddr::getaddr() const
220 {
221 return m->address;
222 }
223
family() const224 IPAddr::Family IPAddr::family() const
225 {
226 if (m->ok) {
227 return static_cast<IPAddr::Family>(m->saddr->sa_family);
228 }
229 return Family::Invalid;
230 }
231
scopetype() const232 IPAddr::Scope IPAddr::scopetype() const
233 {
234 if (!m->ok)
235 return Scope::Invalid;
236 if (family() != Family::IPV6)
237 return Scope::Invalid;
238
239 // Unrouted link-local address. If there are several interfaces on
240 // the host, an additional piece of information (scope id) is
241 // necessary to determine what interface they belong too.
242 // e.g. fe80::1 could exist on both eth0 and eth1, and needs
243 // scopeid 0/1 for complete determination
244 if (IN6_IS_ADDR_LINKLOCAL(
245 &(reinterpret_cast<struct sockaddr_in6*>(m->saddr))->sin6_addr)) {
246 return Scope::LINK;
247 }
248
249 // Site-local addresses are deprecated. Prefix fec0, then locally
250 // chosen network and interface ids. Routable within the
251 // site. They also need a site/scope ID, always 1 if there is only
252 // one site defined.
253 if (IN6_IS_ADDR_SITELOCAL(
254 &(reinterpret_cast<struct sockaddr_in6*>(m->saddr))->sin6_addr)) {
255 return Scope::SITE;
256 }
257
258 // We process unique local addresses and global ones in the same way.
259 return Scope::GLOBAL;
260 }
261
setScopeIdx(const IPAddr & other)262 bool IPAddr::setScopeIdx(const IPAddr& other)
263 {
264 if (family() != Family::IPV6 || other.family() != Family::IPV6 ||
265 scopetype() != Scope::LINK || other.scopetype() != Scope::LINK) {
266 return false;
267 }
268 struct sockaddr_in6 *msa6 = reinterpret_cast<struct sockaddr_in6*>(m->saddr);
269 struct sockaddr_in6 *osa6 = reinterpret_cast<struct sockaddr_in6*>(other.m->saddr);
270 msa6->sin6_scope_id = osa6->sin6_scope_id;
271 return true;
272 }
273
straddr() const274 std::string IPAddr::straddr() const
275 {
276 return straddr(false, false);
277 }
278
straddr(bool setscope,bool forurl) const279 std::string IPAddr::straddr(bool setscope, bool forurl) const
280 {
281 if (!ok())
282 return std::string();
283
284 char buf[200];
285 buf[0] = 0;
286 switch(m->saddr->sa_family) {
287 case AF_INET:
288 inet_ntop(m->saddr->sa_family,
289 &reinterpret_cast<struct sockaddr_in*>(m->saddr)->sin_addr, buf, 200);
290 break;
291 case AF_INET6:
292 {
293 struct sockaddr_in6 *sa6 = reinterpret_cast<struct sockaddr_in6*>(m->saddr);
294 inet_ntop(m->saddr->sa_family, &sa6->sin6_addr, buf, 200);
295 if (!setscope || scopetype() != Scope::LINK) {
296 return buf;
297 }
298 std::string s{buf};
299 char scopebuf[30];
300 snprintf(scopebuf, sizeof(scopebuf), "%u", sa6->sin6_scope_id);
301 s += std::string(forurl ? "%25" : "%") + scopebuf;
302 return s;
303 }
304 break;
305 }
306 return buf;
307 }
308
309 class Interface::Internal {
310 public:
311 unsigned int flags{0};
312 std::string name;
313 std::string friendlyname;
314 int index{-1};
315 std::string hwaddr;
316 std::vector<IPAddr> addresses;
317 std::vector<IPAddr> netmasks;
318 void setflag(Interface::Flags f);
sethwaddr(const char * addr,int len)319 void sethwaddr(const char *addr, int len) {
320 bool isnull{true};
321 for (int i = 0; i < len; i++) {
322 if (addr[i] != 0) {
323 isnull = false;
324 break;
325 }
326 }
327 if (isnull)
328 return;
329 hwaddr.assign(addr, len);
330 flags |= static_cast<unsigned int>(Interface::Flags::HASHWADDR);
331 }
332 };
333
Interface()334 Interface::Interface()
335 {
336 m = new Internal;
337 }
Interface(const Interface & o)338 Interface::Interface(const Interface& o)
339 {
340 m = new Internal;
341 *m = *(o.m);
342 }
operator =(const Interface & o)343 Interface& Interface::operator=(const Interface& o)
344 {
345 if (&o != this) {
346 delete m;
347 m = new Internal;
348 *m = *(o.m);
349 }
350 return *this;
351 }
352
Interface(const char * nm)353 Interface::Interface(const char *nm)
354 : Interface()
355 {
356 m->name = nm;
357 }
Interface(const std::string & nm)358 Interface::Interface(const std::string& nm)
359 : Interface()
360 {
361 m->name = nm;
362 }
~Interface()363 Interface::~Interface()
364 {
365 delete m;
366 }
367
setflag(Interface::Flags f)368 void Interface::Internal::setflag(Interface::Flags f)
369 {
370 flags |= static_cast<unsigned int>(f);
371 }
372
hasflag(Flags f) const373 bool Interface::hasflag(Flags f) const
374 {
375 return (m->flags & static_cast<unsigned int>(f)) != 0;
376 }
377
gethwaddr() const378 const std::string& Interface::gethwaddr() const
379 {
380 return m->hwaddr;
381 }
382
gethexhwaddr() const383 std::string Interface::gethexhwaddr() const
384 {
385 char buf[20];
386 snprintf(buf, 20, "%02x:%02x:%02x:%02x:%02x:%02x",
387 m->hwaddr[0]&0xFF, m->hwaddr[1]&0xFF, m->hwaddr[2]&0xFF,
388 m->hwaddr[3]&0xFF, m->hwaddr[4]&0xFF, m->hwaddr[5]&0xFF);
389 return buf;
390 }
391
getindex() const392 int Interface::getindex() const
393 {
394 return m->index;
395 }
396
getname() const397 const std::string& Interface::getname() const
398 {
399 return m->name;
400 }
401
getfriendlyname() const402 const std::string& Interface::getfriendlyname() const
403 {
404 return m->friendlyname.empty() ? m->name : m->friendlyname;
405 }
406
407 std::pair<const std::vector<IPAddr>&, const std::vector<IPAddr>&>
getaddresses() const408 Interface::getaddresses() const {
409 return {m->addresses, m->netmasks};
410 }
411
trimto(const std::vector<IPAddr> & keep)412 bool Interface::trimto(const std::vector<IPAddr>& keep)
413 {
414 auto mit = m->netmasks.begin();
415 for (auto ait = m->addresses.begin(); ait != m->addresses.end();) {
416 auto it = find_if(keep.begin(), keep.end(),
417 [ait] (const IPAddr& a) {
418 return ait->straddr() == a.straddr();
419 });
420 if (it == keep.end()) {
421 ait = m->addresses.erase(ait);
422 mit = m->netmasks.erase(mit);
423 } else {
424 ait++;
425 mit++;
426 }
427 }
428 return !m->addresses.empty();
429 }
430
firstipv4addr() const431 const IPAddr *Interface::firstipv4addr() const
432 {
433 if (!hasflag(Flags::HASIPV4)) {
434 return nullptr;
435 }
436 for (const auto& entry: m->addresses) {
437 if (entry.family() == IPAddr::Family::IPV4) {
438 return &entry;
439 }
440 }
441 return nullptr;
442 }
443
firstipv6addr(IPAddr::Scope scope) const444 const IPAddr *Interface::firstipv6addr(IPAddr::Scope scope) const
445 {
446 if (!hasflag(Flags::HASIPV6)) {
447 return nullptr;
448 }
449 for (const auto& entry: m->addresses) {
450 if (entry.family() == IPAddr::Family::IPV6 &&
451 (scope != IPAddr::Scope::LINK ||
452 IN6_IS_ADDR_LINKLOCAL(
453 &(reinterpret_cast<struct sockaddr_in6*>(entry.m->saddr))->sin6_addr))) {
454 return &entry;
455 }
456 }
457 return nullptr;
458 }
459
print(std::ostream & out) const460 std::ostream& Interface::print(std::ostream& out) const
461 {
462 out << m->name << ": <";
463 std::vector<std::string> flgs;
464 if (m->flags & static_cast<unsigned int>(Flags::HASIPV4))
465 flgs.emplace_back("HASIPV4");
466 if (m->flags & static_cast<unsigned int>(Flags::HASIPV6))
467 flgs.emplace_back("HASIPV6");
468 if (m->flags & static_cast<unsigned int>(Flags::LOOPBACK))
469 flgs.emplace_back("LOOPBACK");
470 if (m->flags & static_cast<unsigned int>(Flags::UP))
471 flgs.emplace_back("UP");
472 if (m->flags & static_cast<unsigned int>(Flags::MULTICAST))
473 flgs.emplace_back("MULTICAST");
474 if (m->flags & static_cast<unsigned int>(Flags::HASHWADDR))
475 flgs.emplace_back("HASHWADDR");
476 auto it = flgs.begin();
477 if (it != flgs.end())
478 out << *it++;
479 while (it != flgs.end())
480 out << "|" << *it++;
481 out << ">\n";
482 if (!m->hwaddr.empty()) {
483 out << "hwaddr " << gethexhwaddr() << "\n";
484 }
485 for (unsigned int i = 0; i < m->addresses.size(); i++) {
486 out << m->addresses[i].straddr() << " " <<
487 m->netmasks[i].straddr() <<"\n";
488 }
489 return out;
490 }
491
492 class Interfaces::Internal {
493 public:
494 Internal();
495 ~Internal() = default;
496 std::vector<Interface> interfaces;
497 };
498
499
500 #ifndef _WIN32
501
Internal()502 Interfaces::Internal::Internal()
503 {
504 struct ifaddrs *ifap, *ifa;
505
506 /* Get system interface addresses. */
507 if (getifaddrs(&ifap) != 0) {
508 LOGERR("NetIF::Interfaces: getifaddrs failed\n");
509 return;
510 }
511 std::vector<Interface> vifs;
512 for (ifa = ifap; ifa != nullptr; ifa = ifa->ifa_next) {
513 LOGDEB("NetIF::Interfaces: I/F name " << ifa->ifa_name << "\n");
514 // Skip interfaces which are address-less.
515 if (nullptr == ifa->ifa_addr) {
516 LOGDEB("NetIF::Interfaces: Skipping " << ifa->ifa_name <<
517 " because it has no address.\n");
518 continue;
519 }
520 auto ifit = find_if(vifs.begin(), vifs.end(),
521 [ifa] (const Interface& ifr) {
522 return ifa->ifa_name == ifr.m->name;});
523 if (ifit == vifs.end()) {
524 vifs.emplace_back(ifa->ifa_name);
525 ifit = --vifs.end();
526 }
527 if (ifa->ifa_flags & IFF_LOOPBACK) {
528 LOGDEB("NetIF::Interfaces: " << ifa->ifa_name << " is loopback\n");
529 ifit->m->setflag(Interface::Flags::LOOPBACK);
530 }
531 if (ifa->ifa_flags & IFF_UP) {
532 LOGDEB("NetIF::Interfaces: " << ifa->ifa_name << " is UP\n");
533 ifit->m->setflag(Interface::Flags::UP);
534 }
535 if (ifa->ifa_flags & IFF_MULTICAST) {
536 LOGDEB("NetIF::Interfaces: " << ifa->ifa_name << " has MULTICAST\n");
537 ifit->m->setflag(Interface::Flags::MULTICAST);
538 }
539 #ifdef __HAIKU__
540 // It seems that Haiku does not set the MULTICAST flag even on
541 // interfaces which do support the function. So, force it and hope for the
542 // best:
543 ifit->m->setflag(Interface::Flags::MULTICAST);
544 #endif
545 ifit->m->index = if_nametoindex(ifa->ifa_name);
546 switch (ifa->ifa_addr->sa_family) {
547 case AF_INET:
548 case AF_INET6:
549 {
550 ifit->m->addresses.emplace_back(ifa->ifa_addr);
551 ifit->m->netmasks.emplace_back(ifa->ifa_netmask);
552 if (ifa->ifa_addr->sa_family == AF_INET6) {
553 LOGDEB("NetIF::Interfaces: " << ifa->ifa_name << " has IPV6\n");
554 ifit->m->setflag(Interface::Flags::HASIPV6);
555 } else {
556 LOGDEB("NetIF::Interfaces: " << ifa->ifa_name << " has IPV4\n");
557 ifit->m->setflag(Interface::Flags::HASIPV4);
558 }
559 }
560 break;
561 #ifdef __linux__
562 case AF_PACKET:
563 {
564 auto sll = reinterpret_cast<struct sockaddr_ll*>(ifa->ifa_addr);
565 ifit->m->sethwaddr(reinterpret_cast<const char*>(sll->sll_addr), sll->sll_halen);
566 }
567 break;
568 #else
569 case AF_LINK:
570 {
571 auto sdl = reinterpret_cast<struct sockaddr_dl*>(ifa->ifa_addr);
572 LOGDEB("NetIF::Interfaces: " << ifa->ifa_name << " has hwaddr\n");
573 ifit->m->sethwaddr((const char*)LLADDR(sdl), sdl->sdl_alen);
574 }
575 break;
576 #endif
577 default:
578 // common: AF_PACKET: 17
579 LOGDEB("NetIF::Interfaces: " << ifa->ifa_name <<
580 "Unknown family " << ifa->ifa_addr->sa_family << "\n");
581 break;
582 }
583 }
584 interfaces.swap(vifs);
585 freeifaddrs(ifap);
586 }
587
588 #else /* _WIN32 ->*/
589
wchartoutf8(const wchar_t * in,std::string & out,size_t wlen)590 bool wchartoutf8(const wchar_t *in, std::string& out, size_t wlen)
591 {
592 out.clear();
593 if (nullptr == in) {
594 return true;
595 }
596 if (wlen == 0) {
597 wlen = wcslen(in);
598 }
599 int flags = WC_ERR_INVALID_CHARS;
600 int bytes = ::WideCharToMultiByte(CP_UTF8, flags, in, wlen, nullptr, 0, nullptr, nullptr);
601 if (bytes <= 0) {
602 LOGERR("wchartoutf8: conversion error1\n");
603 fwprintf(stderr, L"wchartoutf8: conversion error1 for [%s]\n", in);
604 return false;
605 }
606 char *cp = (char *)malloc(bytes+1);
607 if (nullptr == cp) {
608 LOGERR("wchartoutf8: malloc failed\n");
609 return false;
610 }
611 bytes = ::WideCharToMultiByte(CP_UTF8, flags, in, wlen, cp, bytes, nullptr, nullptr);
612 if (bytes <= 0) {
613 LOGERR("wchartoutf8: CONVERSION ERROR2\n");
614 free(cp);
615 return false;
616 }
617 cp[bytes] = 0;
618 out = cp;
619 free(cp);
620 //fwprintf(stderr, L"wchartoutf8: in: [%s]\n", in);
621 //fprintf(stderr, "wchartoutf8: out: [%s]\n", out.c_str());
622 return true;
623 }
624
netprefixlentomask(uint8_t pfxlen)625 static uint32_t netprefixlentomask(uint8_t pfxlen)
626 {
627 uint32_t out{0};
628 pfxlen = std::min(pfxlen, uint8_t(31));
629 for (int i = 0; i < pfxlen; i++) {
630 out |= 1 << (31-i);
631 }
632 return out;
633 }
634
Internal()635 Interfaces::Internal::Internal()
636 {
637 PIP_ADAPTER_ADDRESSES adapts{nullptr};
638 PIP_ADAPTER_ADDRESSES adapts_item;
639 PIP_ADAPTER_UNICAST_ADDRESS uni_addr;
640 ULONG adapts_sz = 0;
641 ULONG ret;
642 std::vector<Interface> vifs;
643
644 // Note: we are using the GetAdaptersAddresses() call which is the
645 // recommended interface for modern Windows. However the old lib
646 // (-0.17) used getAdaptersInfo(), which gives different names for
647 // the adapters, which means that, e.g. if the adapter name is
648 // specified in the upplay prefs, it will be need to be set again
649 // after changing versions.
650
651 /* Get Adapters addresses required size. */
652 ret = GetAdaptersAddresses(
653 AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, adapts, &adapts_sz);
654 if (ret != ERROR_BUFFER_OVERFLOW) {
655 LOGERR("NetIF::Interfaces: GetAdaptersAddresses: ret1 " << ret <<"\n");
656 return;
657 }
658 /* Allocate enough memory. */
659 adapts = (PIP_ADAPTER_ADDRESSES) malloc(adapts_sz);
660 if (nullptr == adapts) {
661 LOGERR("NetIF::Interfaces: GetAdaptersAddresses: Out of memory\n");
662 return;
663 }
664 /* Do the call that will actually return the info. */
665 ret = GetAdaptersAddresses(
666 AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, adapts, &adapts_sz);
667 if (ret != ERROR_SUCCESS) {
668 LOGERR("NetIF::Interfaces: GetAdaptersAddresses: ret2 " << ret <<"\n");
669 goto out;
670 }
671
672 adapts_item = adapts;
673 while (nullptr != adapts_item) {
674 auto ifit = find_if(vifs.begin(), vifs.end(),
675 [adapts_item] (const Interface& ifr) {
676 return adapts_item->AdapterName == ifr.m->name;});
677 if (ifit == vifs.end()) {
678 LOGDEB("NetIF::Interfaces: I/F friendlyname " << tmpnm <<
679 " AdapterName " << adapts_item->AdapterName << "\n");
680 vifs.emplace_back(adapts_item->AdapterName);
681 ifit = --vifs.end();
682 }
683 if (!wchartoutf8(adapts_item->FriendlyName, ifit->m->friendlyname, 0)) {
684 ifit->m->friendlyname = adapts_item->AdapterName;
685 }
686 if (!(adapts_item->Flags & IP_ADAPTER_NO_MULTICAST)) {
687 LOGDEB("NetIF::Interfaces: " << tmpnm << " has MULTICAST\n");
688 ifit->m->setflag(Interface::Flags::MULTICAST);
689 }
690 if (adapts_item->OperStatus == IfOperStatusUp) {
691 LOGDEB("NetIF::Interfaces: " << tmpnm << " is UP\n");
692 ifit->m->setflag(Interface::Flags::UP);
693 }
694 if (adapts_item->IfType == IF_TYPE_SOFTWARE_LOOPBACK) {
695 LOGDEB("NetIF::Interfaces: " << tmpnm << " is LOOPBACK\n");
696 ifit->m->setflag(Interface::Flags::LOOPBACK);
697 }
698 // Note: upnpapi.c used IfIndex instead.
699 ifit->m->index = adapts_item->Ipv6IfIndex;
700 /* The MAC is in the pAdapter->Address char array */
701 ifit->m->sethwaddr((const char *)adapts_item->PhysicalAddress,
702 adapts_item->PhysicalAddressLength);
703 LOGDEB("NetIF::Interfaces: " << tmpnm << " has hwaddr\n");
704 uni_addr = adapts_item->FirstUnicastAddress;
705 while (uni_addr) {
706 SOCKADDR *ip_addr =
707 reinterpret_cast<SOCKADDR*>(uni_addr->Address.lpSockaddr);
708 switch (ip_addr->sa_family) {
709 case AF_INET:
710 {
711 ifit->m->setflag(Interface::Flags::HASIPV4);
712 LOGDEB("NetIF::Interfaces: " << tmpnm << " has IPV4\n");
713 ifit->m->addresses.emplace_back(ip_addr);
714 uint32_t mask =
715 netprefixlentomask(uni_addr->OnLinkPrefixLength);
716 struct sockaddr_in sa = {};
717 sa.sin_addr.s_addr = mask;
718 ifit->m->netmasks.emplace_back((struct sockaddr*)&sa);
719 }
720 break;
721 case AF_INET6:
722 ifit->m->setflag(Interface::Flags::HASIPV6);
723 LOGDEB("NetIF::Interfaces: " << tmpnm << " has IPV6\n");
724 ifit->m->addresses.emplace_back(ip_addr);
725 // Not for now...
726 ifit->m->netmasks.emplace_back();
727 break;
728
729 default:
730 break;
731 }
732 /* Next address. */
733 uni_addr = uni_addr->Next;
734 }
735
736 /* Next adapter. */
737 adapts_item = adapts_item->Next;
738 }
739 interfaces.swap(vifs);
740
741 out:
742 free(adapts);
743 }
744
745 #endif /* _WIN32 */
746
Interfaces()747 Interfaces::Interfaces()
748 {
749 m = new Internal();
750 }
751
~Interfaces()752 Interfaces::~Interfaces()
753 {
754 delete m;
755 }
756
refresh()757 bool Interfaces::refresh()
758 {
759 delete m;
760 m = new Internal();
761 return true;
762 }
763
setlogfp(FILE * fp)764 void Interfaces::setlogfp(FILE *fp)
765 {
766 logfp = fp;
767 }
768
769 static Interfaces *theInterfacesP;
770
theInterfaces()771 Interfaces *Interfaces::theInterfaces()
772 {
773 if (nullptr == theInterfacesP) {
774 theInterfacesP = new Interfaces();
775 }
776 return theInterfacesP;
777 }
778
print(std::ostream & out)779 std::ostream& Interfaces::print(std::ostream& out) {
780 const auto& ifs = theInterfaces()->m->interfaces;
781 for (const auto& entry : ifs) {
782 entry.print(out);
783 out << "\n";
784 }
785 return out;
786 }
787
select(const Filter & filt) const788 std::vector<Interface> Interfaces::select(const Filter& filt) const
789 {
790 uint32_t yesflags = std::accumulate(filt.needs.begin(), filt.needs.end(), 0,
791 [](uint32_t yes, const NetIF::Interface::Flags &f){ return yes | static_cast<unsigned int>(f); });
792
793 uint32_t noflags = std::accumulate(filt.rejects.begin(), filt.rejects.end(), 0,
794 [](uint32_t no, const NetIF::Interface::Flags &f){ return no | static_cast<unsigned int>(f); });
795
796 LOGDEB("Interfaces::select: yesflags " << std::hex << yesflags <<
797 " noflags " << noflags << std::dec << "\n");
798
799 std::vector<Interface> out;
800 const auto& ifs = theInterfaces()->m->interfaces;
801 std::copy_if(ifs.begin(), ifs.end(), std::back_inserter(out),
802 [=](const NetIF::Interface &entry){
803 return (entry.m->flags & yesflags) == yesflags &&
804 (entry.m->flags & noflags) == 0;});
805 return out;
806 }
807
findByName(const char * nm) const808 Interface *Interfaces::findByName(const char *nm) const
809 {
810 for (auto& ifr : m->interfaces)
811 if (nm == ifr.m->name || nm == ifr.m->friendlyname)
812 return 𝔦
813
814 return nullptr;
815 }
816
interfaceForAddress4(uint32_t peeraddr,const std::vector<Interface> & vifs,IPAddr & hostaddr)817 static const Interface* interfaceForAddress4(
818 uint32_t peeraddr, const std::vector<Interface>& vifs, IPAddr& hostaddr)
819 {
820 struct sockaddr_storage sbuf, mbuf;
821 for (const auto& netif : vifs) {
822 auto addresses = netif.getaddresses();
823 for (unsigned int i = 0; i < addresses.first.size(); i++) {
824 if (addresses.first[i].family() == IPAddr::Family::IPV4) {
825 addresses.first[i].copyToStorage(&sbuf);
826 addresses.second[i].copyToStorage(&mbuf);
827 uint32_t addr = reinterpret_cast<struct sockaddr_in*>(&sbuf)->sin_addr.s_addr;
828 uint32_t mask = reinterpret_cast<struct sockaddr_in*>(&mbuf)->sin_addr.s_addr;
829 if (
830 // Special case for having a single interface with a netmask of ffffffff, which
831 // is apparently common from FreeBSD jails. Just return it, there is no way we
832 // can check anything.
833 ((vifs.size() == 1) && (mask == 0xffffffff)) ||
834 // Normal subnet check
835 ((peeraddr & mask) == (addr & mask)) ) {
836 hostaddr = addresses.first[i];
837 return &netif;
838 }
839 }
840 }
841 }
842 return nullptr;
843 }
844
interfaceForAddress(const IPAddr & addr,const std::vector<Interface> & vifs,IPAddr & hostaddr)845 const Interface *Interfaces::interfaceForAddress(
846 const IPAddr& addr, const std::vector<Interface>& vifs, IPAddr& hostaddr)
847 {
848 struct sockaddr_storage peerbuf;
849 addr.copyToStorage(&peerbuf);
850
851 if (addr.family() == IPAddr::Family::IPV4) {
852 uint32_t peeraddr = reinterpret_cast<struct sockaddr_in*>(
853 &peerbuf)->sin_addr.s_addr;
854 return interfaceForAddress4(peeraddr, vifs, hostaddr);
855 }
856
857 if (addr.family() == IPAddr::Family::IPV6) {
858 auto peeraddr =
859 reinterpret_cast<struct sockaddr_in6*>(&peerbuf);
860 if (IN6_IS_ADDR_V4MAPPED(&peeraddr->sin6_addr)) {
861 uint32_t addr4;
862 memcpy(&addr4, &peeraddr->sin6_addr.s6_addr[12], 4);
863 return interfaceForAddress4(addr4, vifs, hostaddr);
864 }
865
866 int index = -1;
867 if (peeraddr->sin6_scope_id > 0) {
868 index = static_cast<int>(peeraddr->sin6_scope_id);
869 }
870
871 const Interface* netifp{nullptr};
872 for (const auto& netif : vifs) {
873 if (netif.hasflag(Interface::Flags::HASIPV6)) {
874 if (nullptr == netifp) {
875 netifp = &netif;
876 }
877 if (netif.getindex() == index) {
878 netifp = &netif;
879 }
880 }
881 }
882 hostaddr = IPAddr();
883 if (netifp) {
884 const auto ipaddr = netifp->firstipv6addr(IPAddr::Scope::LINK);
885 if (ipaddr) {
886 hostaddr = *ipaddr;
887 }
888 }
889 return netifp;
890 }
891 return nullptr;
892 }
893
interfaceForAddress(const IPAddr & addr,IPAddr & hostaddr)894 const Interface* Interfaces::interfaceForAddress(const IPAddr& addr,
895 IPAddr& hostaddr)
896 {
897 return interfaceForAddress(addr, m->interfaces, hostaddr);
898 }
899
900 } /* namespace NetIF */
901