• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "platform/impl/network_interface.h"
6 
7 #include <winsock2.h>
8 #include <ws2tcpip.h>
9 #include <iphlpapi.h>
10 
11 #include "util/osp_logging.h"
12 
13 namespace openscreen {
14 
GetAllInterfaces()15 std::vector<InterfaceInfo> GetAllInterfaces() {
16     constexpr size_t INITIAL_BUFFER_SIZE = 15000;
17     ULONG outbuflen = INITIAL_BUFFER_SIZE;
18     std::vector<unsigned char> charbuf(INITIAL_BUFFER_SIZE);
19     PIP_ADAPTER_ADDRESSES paddrs = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(charbuf.data());
20     DWORD ret = NO_ERROR;
21     constexpr int MAX_RETRIES = 5;
22 
23     for (int i = 0; i < MAX_RETRIES; ++i) {
24         // TODO: This does not include the loopback interface. Decide if we need it.
25         ret = GetAdaptersAddresses(AF_UNSPEC /* get both v4/v6 addrs */,
26                                    GAA_FLAG_INCLUDE_PREFIX,
27                                    NULL,
28                                    paddrs,
29                                    &outbuflen);
30         if (ret == ERROR_BUFFER_OVERFLOW) {
31             charbuf.resize(outbuflen);
32             continue;
33         }
34         break;
35     }
36 
37     if (ret != NO_ERROR) {
38         OSP_DVLOG << "GetAdapterAddresses failed err=" << ret;
39         return std::vector<InterfaceInfo>();
40     }
41 
42     std::vector<InterfaceInfo> infos;
43     auto pcurraddrs = paddrs;
44     while (pcurraddrs != nullptr) {
45         // TODO: return the interfaces
46         OSP_DVLOG << "\tIfIndex=" << pcurraddrs->IfIndex;
47         OSP_DVLOG << "\tAdapter name=" << pcurraddrs->AdapterName;
48 
49         // Ignore interfaces that are down
50         if (pcurraddrs->OperStatus == IfOperStatusDown) {
51             pcurraddrs = pcurraddrs->Next;
52             continue;
53         }
54 
55         infos.emplace_back();
56         InterfaceInfo& info = infos.back();
57 
58         info.index = pcurraddrs->IfIndex;
59         std::memcpy(info.hardware_address.data(), pcurraddrs->PhysicalAddress,
60                 std::min((unsigned long)sizeof(info.hardware_address),
61                     pcurraddrs->PhysicalAddressLength));
62         info.name = pcurraddrs->AdapterName;
63 
64         // Determine the interface type
65         switch (pcurraddrs->IfType) {
66             case IF_TYPE_ETHERNET_CSMACD:
67                 info.type = InterfaceInfo::Type::kEthernet;
68                 break;
69             case IF_TYPE_IEEE80211:
70                 info.type = InterfaceInfo::Type::kWifi;
71                 break;
72             case IF_TYPE_SOFTWARE_LOOPBACK:
73                 info.type = InterfaceInfo::Type::kLoopback;
74                 break;
75             default:
76                 info.type = InterfaceInfo::Type::kOther;
77                 break;
78         }
79 
80         auto punicast = pcurraddrs->FirstUnicastAddress;
81         if (punicast != nullptr) {
82             for (int i = 0; punicast != nullptr; ++i) {
83                 if (punicast->Address.lpSockaddr->sa_family == AF_INET) {
84                     sockaddr_in* sa_in = (sockaddr_in*)punicast->Address.lpSockaddr;
85                     char buff[100];
86                     DWORD bufflen = 100;
87                     OSP_DVLOG << "\tIPV4:" << inet_ntop(AF_INET, &(sa_in->sin_addr), buff, bufflen);
88                     OSP_DVLOG << "\t  prefixsize=" << (unsigned int)punicast->OnLinkPrefixLength;
89                     IPAddress ip(IPAddress::Version::kV4,
90                             reinterpret_cast<uint8_t*>(&(sa_in->sin_addr.s_addr)));
91                     info.addresses.emplace_back(ip, punicast->OnLinkPrefixLength);
92                 } else if (punicast->Address.lpSockaddr->sa_family == AF_INET6) {
93                     sockaddr_in6* sa_in6 = (sockaddr_in6*)punicast->Address.lpSockaddr;
94                     char buff[100];
95                     DWORD bufflen = 100;
96                     OSP_DVLOG << "\tIPV6:" << inet_ntop(AF_INET6, &(sa_in6->sin6_addr), buff, bufflen);
97                     OSP_DVLOG << "\t  prefixsize=" << (unsigned int)punicast->OnLinkPrefixLength;
98                     IPAddress ip(IPAddress::Version::kV6,
99                             reinterpret_cast<uint8_t*>(&(sa_in6->sin6_addr.s6_addr)));
100                     info.addresses.emplace_back(ip, punicast->OnLinkPrefixLength);
101                 } else {
102                     OSP_DVLOG << "\tUNSPEC";
103                 }
104                 punicast = punicast->Next;
105             }
106         }
107         OSP_DVLOG << "\tIfType=" << pcurraddrs->IfType;
108         OSP_DVLOG << "\tDescription=" << pcurraddrs->Description;
109         OSP_DVLOG << "\tFreindlyName=" << pcurraddrs->FriendlyName;
110         pcurraddrs = pcurraddrs->Next;
111     }
112     return infos;
113 }
114 
115 }  // namespace openscreen
116