Netif.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. #include "pch.h"
  2. #include <WinSock2.h>
  3. #include <iphlpapi.h>
  4. #include "Netif.h"
  5. #if __has_include("Netif.g.cpp")
  6. #include "Netif.g.cpp"
  7. #endif
  8. constexpr auto WORKING_BUFFER_SIZE = 15000;
  9. constexpr auto ADDR_BUFFER_SIZE = 64;
  10. constexpr auto MAX_TRIES = 3;
  11. #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
  12. #define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
  13. namespace winrt::Maple_App::implementation
  14. {
  15. Netif::Netif(const hstring& desc, addresses_t addresses)
  16. : m_desc(desc), m_addresses(std::move(addresses))
  17. {
  18. for (auto const& [af, a] : m_addresses)
  19. {
  20. if (af != AF_INET)
  21. {
  22. continue;
  23. }
  24. if (!m_addr.empty())
  25. {
  26. m_addr = m_addr + L",";
  27. }
  28. m_addr = m_addr + a;
  29. }
  30. for (auto const& [af, a] : m_addresses)
  31. {
  32. if (af != AF_INET6)
  33. {
  34. continue;
  35. }
  36. if (!m_addr.empty())
  37. {
  38. m_addr = m_addr + L",";
  39. }
  40. m_addr = m_addr + a;
  41. }
  42. }
  43. hstring Netif::Desc()
  44. {
  45. return m_desc;
  46. }
  47. hstring Netif::Addr()
  48. {
  49. return m_addr;
  50. }
  51. hstring Netif::IpSummary()
  52. {
  53. // auto const parent = VisualTreeHelper::GetParent(templateRoot);
  54. int cnt4 = 0, cnt6 = 0;
  55. for (auto const& [af, _] : m_addresses)
  56. {
  57. switch (af)
  58. {
  59. case AF_INET: cnt4++; break;
  60. case AF_INET6: cnt6++; break;
  61. default: break;
  62. }
  63. }
  64. return to_hstring(cnt4) + L" IPv4 address" + (cnt4 > 1 ? L"es" : L"") + L"; "
  65. + to_hstring(cnt6) + L" IPv6 address" + (cnt6 > 1 ? L"es" : L"");
  66. }
  67. hstring Netif::IpLines()
  68. {
  69. hstring ret;
  70. for (auto const& [_, addr] : m_addresses)
  71. {
  72. if (ret.empty())
  73. {
  74. ret = ret + addr;
  75. }
  76. else
  77. {
  78. ret = ret + L"\r\n" + addr;
  79. }
  80. }
  81. return ret;
  82. }
  83. std::vector<Maple_App::Netif> Netif::EnumerateInterfaces() {
  84. /* Declare and initialize variables */
  85. DWORD dwRetVal = 0;
  86. unsigned int i = 0;
  87. // Set the flags to pass to GetAdaptersAddresses
  88. ULONG flags =
  89. GAA_FLAG_SKIP_ANYCAST
  90. | GAA_FLAG_SKIP_MULTICAST
  91. | GAA_FLAG_SKIP_DNS_SERVER
  92. | GAA_FLAG_SKIP_FRIENDLY_NAME;
  93. // default to unspecified address family (both)
  94. ULONG family = AF_UNSPEC;
  95. PIP_ADAPTER_ADDRESSES pAddresses = NULL;
  96. ULONG outBufLen = 0;
  97. ULONG Iterations = 0;
  98. PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
  99. PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
  100. // Allocate a 15 KB buffer to start with.
  101. outBufLen = WORKING_BUFFER_SIZE;
  102. std::array<WCHAR, ADDR_BUFFER_SIZE> addrBuf{};
  103. auto sniffed = Netif::SniffBestInterface();
  104. do {
  105. pAddresses = (IP_ADAPTER_ADDRESSES*)MALLOC(outBufLen);
  106. if (pAddresses == NULL) {
  107. throw std::bad_alloc{};
  108. }
  109. dwRetVal =
  110. GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);
  111. if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
  112. FREE(pAddresses);
  113. pAddresses = NULL;
  114. }
  115. else {
  116. break;
  117. }
  118. Iterations++;
  119. } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));
  120. if (dwRetVal != NO_ERROR) {
  121. if (pAddresses) {
  122. FREE(pAddresses);
  123. }
  124. return {};
  125. }
  126. // If successful, output some information from the data we received
  127. std::vector<Maple_App::Netif> ret;
  128. pCurrAddresses = pAddresses;
  129. while (pCurrAddresses) {
  130. if (!(pCurrAddresses->Flags & (IP_ADAPTER_IPV4_ENABLED | IP_ADAPTER_IPV6_ENABLED))) {
  131. pCurrAddresses = pCurrAddresses->Next;
  132. continue;
  133. }
  134. const auto friendlyName = to_hstring(pCurrAddresses->FriendlyName);
  135. std::vector<std::pair<ADDRESS_FAMILY, hstring>> addrs;
  136. hstring desc = friendlyName;
  137. if (friendlyName != L"Maple" && std::make_optional(pCurrAddresses->IfIndex) == sniffed) {
  138. desc = L"★" + desc;
  139. }
  140. pUnicast = pCurrAddresses->FirstUnicastAddress;
  141. if (pUnicast != NULL) {
  142. for (i = 0; pUnicast != NULL; i++) {
  143. auto bufSize = static_cast<DWORD>(addrBuf.size());
  144. auto af = pUnicast->Address.lpSockaddr->sa_family;
  145. if (af == AF_INET || af == AF_INET6) {
  146. if (FAILED(WSAAddressToStringW(pUnicast->Address.lpSockaddr, pUnicast->Address.iSockaddrLength, nullptr, addrBuf.data(), &bufSize))) {
  147. pUnicast = pUnicast->Next;
  148. continue;
  149. }
  150. }
  151. else
  152. {
  153. pUnicast = pUnicast->Next;
  154. continue;
  155. }
  156. if (bufSize > 0) {
  157. bufSize--;
  158. }
  159. addrs.emplace_back(std::make_pair(af, hstring(addrBuf.data(), bufSize)));
  160. pUnicast = pUnicast->Next;
  161. }
  162. }
  163. if (!addrs.empty()) {
  164. ret.emplace_back(winrt::make<Netif>(desc, addrs));
  165. }
  166. pCurrAddresses = pCurrAddresses->Next;
  167. }
  168. FREE(pAddresses);
  169. return ret;
  170. }
  171. std::optional<DWORD> Netif::SniffBestInterface()
  172. {
  173. sockaddr saddr{};
  174. saddr.sa_family = AF_INET;
  175. saddr.sa_data[0] = 0;
  176. saddr.sa_data[1] = 53;
  177. memset(&saddr.sa_data[2], 8, 4);
  178. DWORD bestIfInd;
  179. if (FAILED(GetBestInterfaceEx(&saddr, &bestIfInd))) {
  180. return std::nullopt;
  181. }
  182. return { bestIfInd };
  183. }
  184. }