3 |
import time |
import time |
4 |
import socket |
import socket |
5 |
import random |
import random |
6 |
import adns, ADNS |
from error import log |
7 |
|
try: |
8 |
|
import adns, ADNS |
9 |
|
_have_adns = True |
10 |
|
except ImportError: |
11 |
|
log("No ADNS library found, using synchronous name lookups.") |
12 |
|
_have_adns = False |
13 |
|
|
14 |
class NameFormatException(Exception): |
class NameFormatException(Exception): |
15 |
pass |
pass |
16 |
|
|
17 |
class MyQE(ADNS.QueryEngine): |
if _have_adns: |
18 |
def lookup_a_record(self, name, callback, extra): |
class MyQE(ADNS.QueryEngine): |
19 |
self.submit(name, adns.rr.A, callback = callback, extra = extra) |
def lookup_a_record(self, name, callback, extra): |
20 |
|
self.submit(name, adns.rr.A, callback = callback, extra = extra) |
21 |
class LookupManager: |
|
22 |
namecache = {} |
class LookupManager: |
23 |
queryengine = MyQE() |
namecache = {} |
24 |
|
queryengine = MyQE() |
25 |
def __init__(self, mintime=86400, maxtime=259200): |
|
26 |
self.mintime = mintime |
def __init__(self, mintime=86400, maxtime=259200): |
27 |
self.maxtime = maxtime |
self.mintime = mintime |
28 |
|
self.maxtime = maxtime |
29 |
def _lookup(self, name, callback, cbw): |
|
30 |
now = time.time() |
def _lookup(self, name, callback, cbw): |
31 |
ip = self.namecache.get(name, None) |
now = time.time() |
32 |
expiretime = 0 |
ip = self.namecache.get(name, None) |
33 |
if ip is not None: |
expiretime = 0 |
34 |
ip, expiretime = ip |
if ip is not None: |
35 |
if now < expiretime: |
ip, expiretime = ip |
36 |
cbw.cb(ip) |
if now < expiretime: |
37 |
return |
cbw.cb(ip) |
38 |
self.queryengine.lookup_a_record(name, callback, cbw) |
return |
39 |
|
self.queryengine.lookup_a_record(name, callback, cbw) |
40 |
def lookup(self, name, callback, data=None): |
|
41 |
cbw = CBWrapper(name, callback, data) |
def lookup(self, name, callback, data=None): |
42 |
try: |
cbw = CBWrapper(name, callback, data) |
43 |
name = name.encode('ascii') |
try: |
44 |
except UnicodeError: |
name = name.encode('ascii') |
45 |
raise NameFormatException, "Host names must be ASCII" |
except UnicodeError: |
46 |
self._lookup(name, self.adns_callback, cbw) |
raise NameFormatException, "Host names must be ASCII" |
47 |
|
self._lookup(name, self.adns_callback, cbw) |
48 |
|
|
49 |
def adns_callback(self, answer, qname, rr, flags, cbwrapper): |
def adns_callback(self, answer, qname, rr, flags, cbwrapper): |
50 |
now = int(time.time()) |
now = int(time.time()) |
51 |
ips = answer[3] |
ips = answer[3] |
52 |
ip = None |
ip = None |
53 |
if answer[1] and not ips: |
if answer[1] and not ips: |
54 |
# we got a cname even though we asked for an a record |
# we got a cname even though we asked for an a record |
55 |
self._lookup(answer[1], self.adns_callback, cbwrapper) |
self._lookup(answer[1], self.adns_callback, cbwrapper) |
56 |
return |
return |
57 |
elif ips: |
elif ips: |
58 |
ip = ips[0] |
ip = ips[0] |
59 |
self.namecache[qname] = (ip, now + random.randint( |
self.namecache[qname] = (ip, now+random.randint(self.mintime, |
60 |
now+self.mintime, now+self.maxtime)) |
self.maxtime)) |
61 |
cbwrapper.cb(ip) |
cbwrapper.cb(ip) |
62 |
|
|
63 |
def poll(self, timeout=0.1): |
def poll(self, timeout=0.1): |
64 |
self.queryengine.run(timeout) |
self.queryengine.run(timeout) |
65 |
|
|
66 |
class CBWrapper: |
class CBWrapper: |
67 |
def __init__(self, name, callback, data): |
def __init__(self, name, callback, data): |
68 |
self.name = name |
self.name = name |
69 |
self.data = data |
self.data = data |
70 |
self.callback = callback |
self.callback = callback |
71 |
|
|
72 |
|
def cb(self, ip): |
73 |
|
self.callback(self.name, ip, self.data) |
74 |
|
|
75 |
|
else: |
76 |
|
class LookupManager: |
77 |
|
NameFormatException = NameFormatException |
78 |
|
namecache = {} |
79 |
|
|
80 |
|
def __init__(self, mintime=86400, maxtime=259200): |
81 |
|
self.mintime = mintime |
82 |
|
self.maxtime = maxtime |
83 |
|
|
84 |
|
def _lookup(self, name): |
85 |
|
now = time.time() |
86 |
|
ip = self.namecache.get(name, None) |
87 |
|
expiretime = 0 |
88 |
|
if ip is not None: |
89 |
|
ip, expiretime = ip |
90 |
|
if now < expiretime: |
91 |
|
return ip |
92 |
|
try: |
93 |
|
ip = socket.gethostbyname(name) |
94 |
|
except socket.error: |
95 |
|
ip = None |
96 |
|
now = int(time.time()) |
97 |
|
self.namecache[name] = (ip, now + random.randint(self.mintime, |
98 |
|
self.maxtime)) |
99 |
|
return ip |
100 |
|
|
101 |
|
def lookup(self, name, callback, data=None): |
102 |
|
try: |
103 |
|
name = name.encode('ascii') |
104 |
|
except UnicodeError: |
105 |
|
raise NameFormatException, "Host names must be ASCII" |
106 |
|
ip = self._lookup(name) |
107 |
|
callback(name, ip, data) |
108 |
|
|
109 |
def cb(self, ip): |
def poll(self, timeout=0.1): |
110 |
self.callback(self.name, ip, self.data) |
pass |
111 |
|
|