| 41 | static std::atomic<bool> interruptSocks5Recv(false); |
| 42 | |
| 43 | std::vector<CNetAddr> WrappedGetAddrInfo(const std::string& name, bool allow_lookup) |
| 44 | { |
| 45 | addrinfo ai_hint{}; |
| 46 | // We want a TCP port, which is a streaming socket type |
| 47 | ai_hint.ai_socktype = SOCK_STREAM; |
| 48 | ai_hint.ai_protocol = IPPROTO_TCP; |
| 49 | // We don't care which address family (IPv4 or IPv6) is returned |
| 50 | ai_hint.ai_family = AF_UNSPEC; |
| 51 | // If we allow lookups of hostnames, use the AI_ADDRCONFIG flag to only |
| 52 | // return addresses whose family we have an address configured for. |
| 53 | // |
| 54 | // If we don't allow lookups, then use the AI_NUMERICHOST flag for |
| 55 | // getaddrinfo to only decode numerical network addresses and suppress |
| 56 | // hostname lookups. |
| 57 | ai_hint.ai_flags = allow_lookup ? AI_ADDRCONFIG : AI_NUMERICHOST; |
| 58 | |
| 59 | addrinfo* ai_res{nullptr}; |
| 60 | const int n_err{getaddrinfo(name.c_str(), nullptr, &ai_hint, &ai_res)}; |
| 61 | if (n_err != 0) { |
| 62 | return {}; |
| 63 | } |
| 64 | |
| 65 | // Traverse the linked list starting with ai_trav. |
| 66 | addrinfo* ai_trav{ai_res}; |
| 67 | std::vector<CNetAddr> resolved_addresses; |
| 68 | while (ai_trav != nullptr) { |
| 69 | if (ai_trav->ai_family == AF_INET) { |
| 70 | assert(ai_trav->ai_addrlen >= sizeof(sockaddr_in)); |
| 71 | resolved_addresses.emplace_back(reinterpret_cast<sockaddr_in*>(ai_trav->ai_addr)->sin_addr); |
| 72 | } |
| 73 | if (ai_trav->ai_family == AF_INET6) { |
| 74 | assert(ai_trav->ai_addrlen >= sizeof(sockaddr_in6)); |
| 75 | const sockaddr_in6* s6{reinterpret_cast<sockaddr_in6*>(ai_trav->ai_addr)}; |
| 76 | resolved_addresses.emplace_back(s6->sin6_addr, s6->sin6_scope_id); |
| 77 | } |
| 78 | ai_trav = ai_trav->ai_next; |
| 79 | } |
| 80 | freeaddrinfo(ai_res); |
| 81 | |
| 82 | return resolved_addresses; |
| 83 | } |
| 84 | |
| 85 | DNSLookupFn g_dns_lookup{WrappedGetAddrInfo}; |
| 86 | |