1. Overview
The dns_util.hpp header defines the resolve_with_cache inline function, a lightweight DNS resolver that integrates with DNSCache. The function provides a cache-first resolution workflow: on cache hit, it returns immediately; on cache miss, it resolves the hostname using getaddrinfo(), collects IPv4 and IPv6 addresses, stores the results in the cache, and returns the outcome.
Functionally, this module provides:
- Cache-aware hostname resolution using
DNSCache - Dual-stack support (IPv4 and IPv6) via
AF_UNSPEC - Optional TTL control for cached entries
- Low overhead via an inline implementation suitable for frequent use
- Optional timing instrumentation for diagnostics
2. Dependencies and Includes
#include "dns_cache.hpp"
#include <string>
#include <vector>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <chrono>
#include <iostream>
#include <cstring>
- dns_cache.hpp – cache interface for storing and retrieving DNS results
- <string> – hostname input and string-form IP outputs
- <vector> – collection of resolved IP addresses
- <netdb.h> –
getaddrinfo()andaddrinfostructures - <sys/socket.h> – socket structures and address families
- <arpa/inet.h> –
inet_ntop()for IP address formatting - <chrono> – optional timing measurements (latency of resolver calls)
- <iostream> – optional debug output (commented in the implementation)
- <cstring> –
memset()for struct initialization
3. Public Interface
3.1 Cache-Aware Resolver
inline bool resolve_with_cache(const std::string& host,
std::vector<std::string>& addrs,
int ttl_seconds = 0);
Resolves the specified hostname into one or more string-form IP addresses. If cached results exist, returns them immediately. Otherwise, performs a system DNS query using getaddrinfo(), extracts IPv4 and IPv6 addresses, and stores the results in DNSCache.
Returns true on success and fills addrs with at least one IP address. Returns false on failure or if no addresses are produced.
4. Resolution Flow
The function implements the following sequence:
- Attempt
DNSCache::instance().lookup(host, addrs) - If hit, return
trueimmediately - Initialize
addrinfohints and callgetaddrinfo()withAF_UNSPEC - Iterate over results and convert addresses using
inet_ntop() - Free resolver resources via
freeaddrinfo() - If at least one IP was collected, store it via
DNSCache::instance().store() - Return success/failure
5. Address Family Handling
The resolver accepts both IPv4 and IPv6 addresses:
- IPv4:
AF_INETresults are converted withINET_ADDRSTRLEN - IPv6:
AF_INET6results are converted withINET6_ADDRSTRLEN
Addresses are stored as textual representations, suitable for logging, display, or subsequent socket use.
6. TTL Semantics and Caching
if (ok) DNSCache::instance().store(host, addrs, ttl_seconds);
On successful resolution, results are stored in the cache. The TTL is controlled by ttl_seconds:
- If
ttl_secondsis provided, the cache implementation may apply it as the expiration interval - If
ttl_secondsis zero or not meaningful in the underlying cache policy, the cache may fall back to its configured default TTL
7. Diagnostics and Observability
The implementation measures the latency of getaddrinfo() using std::chrono. A debug line is present (commented out) to report the error code and elapsed time to std::cerr.
8. Security and Reliability Considerations
- Input validation: callers should ensure
hostis a normalized hostname to avoid redundant cache keys and malformed resolver inputs - Result sanitization: returned IP strings should be treated as untrusted data when used in logs or UI (avoid injection into structured formats without escaping)
- Cache poisoning: only store results from trusted resolution paths if the application operates in hostile network environments
- Resource handling:
freeaddrinfo()is called to prevent memory leaks aftergetaddrinfo() - Ordering and duplicates: results may include duplicates or multiple addresses; callers may want to de-duplicate or prioritize based on policy (e.g., prefer IPv4 or IPv6)
- Blocking behavior:
getaddrinfo()is a blocking call; in UI contexts, invoke this function off the main thread or use an asynchronous resolver when required