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