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