1 import os.path as _os_path
2 import pickle as _pickle
4 import socket as _socket
7 class Resolver (object):
8 """A simple reverse-DNS resolver.
10 Maintains a class-level cache of resolved IPs to avoid repeated
11 lookups on the same IP address.
13 Avoid hanging if we can't resolve a name.
16 >>> if hasattr(_socket, 'setdefaulttimeout'):
17 ... socket.setdefaulttimeout(5) # set 5 second timeout
20 >>> r.IP = {} # clear cache of date from previous tests
21 >>> r.resolve('198.41.0.4')
24 {'198.41.0.4': ('a.root-servers.net', [], ['198.41.0.4'])}
26 If you want to give shorter names to various DNS names, you can
27 add an entry to the class-level ``REGEXPS``. The entry should use
28 your name as the key, and a list of matching regexps as the value.
29 You need to enable this enhanced resolution using the ``smart``
32 >>> r.resolve('66.249.68.33')
33 'crawl-66-249-68-33.googlebot.com'
34 >>> r = Resolver(smart=True)
35 >>> r.resolve('66.249.68.34')
41 'feedburner': [_re.compile('.*rate-limited-proxy-.*.google.com.*')],
46 'msnbot', # a.k.a: bingbot
49 REGEXPS[bot] = [_re.compile('.*{}.*'.format(bot))]
51 _cache_file = _os_path.expanduser(
52 _os_path.join('~', '.apachelog-resolver.cache'))
56 def __init__(self, smart=False):
62 if not self._cache_loaded:
63 self._cache_loaded = True
65 with open(self._cache_file, 'rb') as f:
66 self.IP = _pickle.load(f)
67 self._cache_dirty = False
75 self.load_cache() # avoid clobbering unloaded content
77 with open(self._cache_file, 'wb') as f:
78 _pickle.dump(self.IP, f)
80 def resolve(self, ip):
82 self._cache_dirty = True
84 self.IP[ip] = _socket.gethostbyaddr(ip)
85 except _socket.herror as e:
86 self.IP[ip] = (ip, [], [ip])
87 except _socket.gaierror as e:
88 self.IP[ip] = (ip, [], [ip])
91 self._smart_resolve(ip)
94 def _smart_resolve(self, ip):
97 for name,regexps in self.REGEXPS.items():
98 for regexp in regexps:
99 if regexp.match(self.IP[ip][0]):
100 self.IP[ip] = (name, x[1], x[2])
103 "Return a set of IP addresses used by a smart-resolved name."
105 for ip,values in self.IP.items():
106 if values[0] == name: