dns_util.hpp

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() and addrinfo structures
  • <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 true immediately
  • Initialize addrinfo hints and call getaddrinfo() with AF_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_INET results are converted with INET_ADDRSTRLEN
  • IPv6: AF_INET6 results are converted with INET6_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_seconds is provided, the cache implementation may apply it as the expiration interval
  • If ttl_seconds is 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 host is 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 after getaddrinfo()
  • 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