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 &ifr;
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