dns_cache.hpp

1. Overview

The dns_cache.hpp header defines the DNSCache class, a thread-safe, in-memory caching component for Domain Name System (DNS) resolution results. The cache is designed to reduce lookup latency and network overhead by storing recently resolved IP addresses with configurable time-to-live (TTL) semantics.

Functionally, DNSCache provides:

  • Centralized caching of hostname-to-address mappings
  • TTL-based expiration of cached entries
  • Thread-safe concurrent access via mutex synchronization
  • Support for multi-address (A/AAAA) resolution results
  • Singleton-based global access

2. Dependencies and Includes

#include <string>
#include <vector>
#include <unordered_map>
#include <mutex>
#include <chrono>
  • <string> – storage of hostnames and textual IP addresses
  • <vector> – container for multiple resolved addresses
  • <unordered_map> – hash-based lookup table for cache entries
  • <mutex> – synchronization primitive for thread-safe access
  • <chrono> – time measurement for TTL and expiration handling

3. Class Declaration and Scope

class DNSCache

The DNSCache class is implemented as a process-wide singleton. Copy and assignment operations are explicitly disabled to enforce single-instance semantics.


4. Singleton Access

static DNSCache& instance();

Returns the global cache instance. Initialization is performed lazily and is thread-safe under standard C++ initialization rules.


5. Public Interface

5.1 Multi-Address Lookup

bool lookup(const std::string& host,
            std::vector<std::string>& out);

Retrieves all cached IP addresses for the specified hostname. If a valid, non-expired entry exists, the addresses are copied into out and the method returns true. Otherwise, it returns false.


5.2 Single-Address Lookup

std::string lookup_one(const std::string& host);

Returns a single cached address for the given hostname, typically the first available entry. If no valid cache entry exists, an empty string is returned.


5.3 Cache Storage

void store(const std::string& host,
           const std::vector<std::string>& addrs,
           int ttl_seconds = -1);

Stores a set of resolved addresses in the cache with an associated expiration time. If ttl_seconds is negative, the default TTL is applied.


5.4 Default TTL Configuration

void set_default_ttl(int seconds);

Updates the default time-to-live value (in seconds) used for new cache entries when no explicit TTL is provided.


5.5 Cache Maintenance

void clear();
size_t size() const;

Clears all cached entries and returns the current number of stored records. These operations are thread-safe and suitable for maintenance and diagnostics.


6. Internal Data Model

struct DNSResult {
    std::vector<std::string> addrs;
    std::chrono::steady_clock::time_point expires;
};

Represents a cached DNS resolution result, including a list of IP addresses and a monotonic expiration timestamp.


7. Internal State and Synchronization

mutable std::mutex mu_;
std::unordered_map<std::string, DNSResult> map_;
int default_ttl_ = 60;
  • mu_ – mutex protecting all accesses to the internal cache map
  • map_ – associative container mapping hostnames to cached results
  • default_ttl_ – default expiration interval in seconds (default: 60s)

8. Expiration and Timing Strategy

The cache uses std::chrono::steady_clock to compute expiration timestamps. This ensures that TTL calculations are not affected by system clock adjustments.

On each lookup:

  • Expired entries are detected using the monotonic clock
  • Stale results are ignored and may be purged
  • Only valid records are returned to callers

9. Usage Scenarios

  • Accelerating repeated DNS lookups in network clients
  • Reducing external resolver traffic
  • Supporting high-throughput scanning and monitoring components
  • Providing consistent resolution results across threads

10. Security and Performance Considerations

  • Cache poisoning: callers must ensure that only trusted resolver results are stored to avoid propagation of malicious mappings
  • Memory growth: unbounded caching may increase memory usage; consider periodic eviction policies for long-running processes
  • TTL tuning: overly long TTL values may lead to stale routing data, while very short TTLs reduce cache effectiveness
  • Thread contention: high-frequency access may cause mutex contention; consider sharding or lock-free strategies if scalability becomes critical
  • Consistency: concurrent updates and lookups are serialized to ensure coherent visibility across threads
  • Input validation: hostnames should be normalized before use to avoid duplicate or malformed cache entries