xref: /aosp_15_r20/external/openscreen/platform/impl/network_interface_win.cc (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
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     DWORD ret = NO_ERROR;
20     constexpr int MAX_RETRIES = 5;
21 
22     for (int i = 0; i < MAX_RETRIES; ++i) {
23         // TODO: This does not include the loopback interface. Decide if we need it.
24         ret = GetAdaptersAddresses(AF_UNSPEC /* get both v4/v6 addrs */,
25                                    GAA_FLAG_INCLUDE_PREFIX,
26                                    NULL,
27                                    reinterpret_cast<IP_ADAPTER_ADDRESSES*>(charbuf.data()),
28                                    &outbuflen);
29         if (ret == ERROR_BUFFER_OVERFLOW) {
30             charbuf.resize(outbuflen);
31             continue;
32         }
33         break;
34     }
35 
36     if (ret != NO_ERROR) {
37         OSP_DVLOG << "GetAdapterAddresses failed err=" << ret;
38         return std::vector<InterfaceInfo>();
39     }
40 
41     std::vector<InterfaceInfo> infos;
42     auto pcurraddrs = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(charbuf.data());
43     while (pcurraddrs != nullptr) {
44         // TODO: return the interfaces
45         OSP_DVLOG << "\tIfIndex=" << pcurraddrs->IfIndex;
46         OSP_DVLOG << "\tAdapter name=" << pcurraddrs->AdapterName;
47 
48         // Ignore interfaces that are down
49         if (pcurraddrs->OperStatus == IfOperStatusDown) {
50             pcurraddrs = pcurraddrs->Next;
51             continue;
52         }
53 
54         infos.emplace_back();
55         InterfaceInfo& info = infos.back();
56 
57         info.index = pcurraddrs->IfIndex;
58         std::memcpy(info.hardware_address.data(), pcurraddrs->PhysicalAddress,
59                 std::min((unsigned long)sizeof(info.hardware_address),
60                     pcurraddrs->PhysicalAddressLength));
61         info.name = pcurraddrs->AdapterName;
62 
63         // Determine the interface type
64         switch (pcurraddrs->IfType) {
65             case IF_TYPE_ETHERNET_CSMACD:
66                 info.type = InterfaceInfo::Type::kEthernet;
67                 break;
68             case IF_TYPE_IEEE80211:
69                 info.type = InterfaceInfo::Type::kWifi;
70                 break;
71             case IF_TYPE_SOFTWARE_LOOPBACK:
72                 info.type = InterfaceInfo::Type::kLoopback;
73                 break;
74             default:
75                 info.type = InterfaceInfo::Type::kOther;
76                 break;
77         }
78 
79         auto punicast = pcurraddrs->FirstUnicastAddress;
80         if (punicast != nullptr) {
81             for (int i = 0; punicast != nullptr; ++i) {
82                 if (punicast->Address.lpSockaddr->sa_family == AF_INET) {
83                     sockaddr_in* sa_in = (sockaddr_in*)punicast->Address.lpSockaddr;
84                     char buff[100];
85                     DWORD bufflen = 100;
86                     OSP_DVLOG << "\tIPV4:" << inet_ntop(AF_INET, &(sa_in->sin_addr), buff, bufflen);
87                     OSP_DVLOG << "\t  prefixsize=" << (unsigned int)punicast->OnLinkPrefixLength;
88                     IPAddress ip(IPAddress::Version::kV4,
89                             reinterpret_cast<uint8_t*>(&(sa_in->sin_addr.s_addr)));
90                     info.addresses.emplace_back(ip, punicast->OnLinkPrefixLength);
91                 } else if (punicast->Address.lpSockaddr->sa_family == AF_INET6) {
92                     sockaddr_in6* sa_in6 = (sockaddr_in6*)punicast->Address.lpSockaddr;
93                     char buff[100];
94                     DWORD bufflen = 100;
95                     OSP_DVLOG << "\tIPV6:" << inet_ntop(AF_INET6, &(sa_in6->sin6_addr), buff, bufflen);
96                     OSP_DVLOG << "\t  prefixsize=" << (unsigned int)punicast->OnLinkPrefixLength;
97                     IPAddress ip(IPAddress::Version::kV6,
98                             reinterpret_cast<uint8_t*>(&(sa_in6->sin6_addr.s6_addr)));
99                     info.addresses.emplace_back(ip, punicast->OnLinkPrefixLength);
100                 } else {
101                     OSP_DVLOG << "\tUNSPEC";
102                 }
103                 punicast = punicast->Next;
104             }
105         }
106         OSP_DVLOG << "\tIfType=" << pcurraddrs->IfType;
107         // TODO: Convert the wide strings to the proper narrow encoding (e.g.
108         // UTF-8) rather than print the addresses.
109         OSP_DVLOG << "\tDescription=" << static_cast<void*>(pcurraddrs->Description);
110         OSP_DVLOG << "\tFriendlyName=" << static_cast<void*>(pcurraddrs->FriendlyName);
111         pcurraddrs = pcurraddrs->Next;
112     }
113     return infos;
114 }
115 
116 }  // namespace openscreen
117