refactor: extract modules from proxywatchd.py
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%).
This commit is contained in:
86
dns.py
Normal file
86
dns.py
Normal file
@@ -0,0 +1,86 @@
|
||||
#!/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),
|
||||
}
|
||||
Reference in New Issue
Block a user