| 243 | |
| 244 | template <typename Handler> |
| 245 | void queryDns(const Handler& handler, std::optional<sf::Time> timeout, const std::vector<Query>& queries) |
| 246 | { |
| 247 | const auto hasIpV6 = std::any_of(queries.begin(), |
| 248 | queries.end(), |
| 249 | [](const auto& query) { |
| 250 | return std::any_of(query.servers.begin(), |
| 251 | query.servers.end(), |
| 252 | [](const auto& server) { return server.isV6(); }); |
| 253 | }); |
| 254 | |
| 255 | sf::UdpSocket socket; |
| 256 | if (socket.bind(sf::Socket::AnyPort, hasIpV6 ? sf::IpAddress::AnyV6 : sf::IpAddress::AnyV4) != sf::Socket::Status::Done) |
| 257 | return; |
| 258 | |
| 259 | static std::atomic_uint16_t nextTransactionId{1}; |
| 260 | const auto transactionId = nextTransactionId.fetch_add(1); |
| 261 | |
| 262 | const auto parseResponse = [&](const std::vector<char>& buffer) |
| 263 | { |
| 264 | const auto* begin = buffer.data(); |
| 265 | const auto* ptr = begin; |
| 266 | const auto* end = ptr + buffer.size(); |
| 267 | |
| 268 | // Verify matching transaction ID |
| 269 | if (const auto responseTransactionId = readU16(ptr, end); responseTransactionId != transactionId) |
| 270 | return false; |
| 271 | |
| 272 | // Ensure response and no error |
| 273 | if (const auto flags = readU16(ptr, end); !(flags & 0x8000) || (flags & 0x000F)) |
| 274 | return false; |
| 275 | |
| 276 | const auto questions = readU16(ptr, end); |
| 277 | const auto answers = readU16(ptr, end); |
| 278 | readU16(ptr, end); // Authority RRs |
| 279 | readU16(ptr, end); // Additional RRs |
| 280 | |
| 281 | for (auto i = 0u; (i < questions) && (ptr < end); ++i) |
| 282 | { |
| 283 | readName(ptr, end, begin); |
| 284 | readU16(ptr, end); // Type |
| 285 | readU16(ptr, end); // Class |
| 286 | } |
| 287 | |
| 288 | auto handled = false; |
| 289 | |
| 290 | for (auto i = 0u; (i < answers) && (ptr < end); ++i) |
| 291 | { |
| 292 | readU16(ptr, end); // Name |
| 293 | const auto responseType = readU16(ptr, end); |
| 294 | const auto responseClass = readU16(ptr, end); |
| 295 | readU32(ptr, end); // TTL |
| 296 | const auto length = readU16(ptr, end); |
| 297 | |
| 298 | if (length == 0) |
| 299 | continue; |
| 300 | |
| 301 | if (ptr + length <= end) |
| 302 | { |
no test coverage detected