Extract focused modules to reduce proxywatchd.py complexity: - stats.py: JudgeStats, Stats, regexes, ssl_targets (557 lines) - mitm.py: MITMCertStats, cert extraction functions (239 lines) - dns.py: socks4_resolve with TTL caching (86 lines) - job.py: PriorityJobQueue, calculate_priority (103 lines) proxywatchd.py reduced from 2488 to 1591 lines (-36%).
87 lines
2.1 KiB
Python
87 lines
2.1 KiB
Python
#!/usr/bin/env python2
|
|
"""DNS resolution with caching for PPF proxy testing."""
|
|
from __future__ import division
|
|
|
|
import time
|
|
|
|
from misc import _log
|
|
import rocksock
|
|
|
|
# Module-level config reference
|
|
config = None
|
|
|
|
# DNS cache: {hostname: (ip, timestamp)}
|
|
cached_dns = {}
|
|
DNS_CACHE_TTL = 3600 # 1 hour
|
|
|
|
|
|
def set_config(cfg):
|
|
"""Set the config object (called from proxywatchd/ppf)."""
|
|
global config
|
|
config = cfg
|
|
|
|
|
|
def socks4_resolve(srvname, server_port):
|
|
"""Resolve hostname to IP for SOCKS4 (which requires numeric IP).
|
|
|
|
Caches results for DNS_CACHE_TTL seconds to avoid repeated lookups.
|
|
|
|
Args:
|
|
srvname: Hostname to resolve
|
|
server_port: Port number (for resolution)
|
|
|
|
Returns:
|
|
IP address string, or False on failure
|
|
"""
|
|
now = time.time()
|
|
# Check cache with TTL
|
|
if srvname in cached_dns:
|
|
ip, ts = cached_dns[srvname]
|
|
if now - ts < DNS_CACHE_TTL:
|
|
if config and config.watchd.debug:
|
|
_log("using cached ip (%s) for %s" % (ip, srvname), "debug")
|
|
return ip
|
|
# Expired - fall through to re-resolve
|
|
|
|
# Resolve hostname
|
|
dns_fail = False
|
|
try:
|
|
af, sa = rocksock.resolve(rocksock.RocksockHostinfo(srvname, server_port), want_v4=True)
|
|
if sa is not None:
|
|
cached_dns[srvname] = (sa[0], now)
|
|
return sa[0]
|
|
else:
|
|
dns_fail = True
|
|
except rocksock.RocksockException as e:
|
|
assert(e.get_errortype() == rocksock.RS_ET_GAI)
|
|
dns_fail = True
|
|
|
|
if dns_fail:
|
|
_log("could not resolve connection target %s" % srvname, "ERROR")
|
|
return False
|
|
return srvname
|
|
|
|
|
|
def clear_cache():
|
|
"""Clear the DNS cache."""
|
|
global cached_dns
|
|
cached_dns = {}
|
|
|
|
|
|
def cache_stats():
|
|
"""Return DNS cache statistics.
|
|
|
|
Returns:
|
|
dict with count, oldest_age, newest_age
|
|
"""
|
|
if not cached_dns:
|
|
return {'count': 0, 'oldest_age': 0, 'newest_age': 0}
|
|
|
|
now = time.time()
|
|
ages = [now - ts for _, ts in cached_dns.values()]
|
|
return {
|
|
'count': len(cached_dns),
|
|
'oldest_age': max(ages),
|
|
'newest_age': min(ages),
|
|
}
|