Package lib :: Package cuckoo :: Package common :: Module dns
[hide private]
[frames] | no frames]

Source Code for Module lib.cuckoo.common.dns

  1  # Copyright (C) 2010-2014 Cuckoo Foundation. 
  2  # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org 
  3  # See the file 'docs/LICENSE' for copying permission. 
  4   
  5  import select 
  6  import socket 
  7  import threading 
  8   
  9  try: 
 10      import pycares 
 11      HAVE_CARES = True 
 12  except: 
 13      HAVE_CARES = False 
 14   
 15  #try: 
 16  #    import gevent, gevent.socket 
 17  #    HAVE_GEVENT = True 
 18  #except: 
 19  HAVE_GEVENT = False 
 20   
 21   
 22  # these are used by all resolvers 
 23  DNS_TIMEOUT = 5 
 24  DNS_TIMEOUT_VALUE = "" 
 25   
26 -def set_timeout(value):
27 global DNS_TIMEOUT 28 DNS_TIMEOUT = value
29
30 -def set_timeout_value(value):
31 global DNS_TIMEOUT_VALUE 32 DNS_TIMEOUT_VALUE = value
33 34 35 # standard gethostbyname in thread 36 # http://code.activestate.com/recipes/473878/
37 -def with_timeout(func, args=(), kwargs={}):
38 """This function will spawn a thread and run the given function 39 using the args, kwargs and return the given default value if the 40 timeout_duration is exceeded. 41 """ 42 class ResultThread(threading.Thread): 43 daemon = True 44 def __init__(self): 45 threading.Thread.__init__(self) 46 self.result, self.error = None, None
47 def run(self): 48 try: 49 self.result = func(*args, **kwargs) 50 except Exception, e: 51 self.error = e 52 53 it = ResultThread() 54 it.start() 55 it.join(DNS_TIMEOUT) 56 if it.isAlive(): 57 return DNS_TIMEOUT_VALUE 58 else: 59 if it.error: 60 raise it.error 61 return it.result 62
63 -def resolve_thread(name):
64 return with_timeout(gethostbyname, (name,))
65
66 -def gethostbyname(name):
67 try: 68 ip = socket.gethostbyname(name) 69 except socket.gaierror: 70 ip = "" 71 return ip
72 73 74 # C-ARES (http://c-ares.haxx.se/)
75 -def resolve_cares(name):
76 # create new c-ares channel 77 careschan = pycares.Channel(timeout=DNS_TIMEOUT, tries=1) 78 79 # if we don't get a response we return the default value 80 result = Resultholder() 81 result.value = DNS_TIMEOUT_VALUE 82 83 def setresult_cb(res, error): 84 # ignore error and just take first result ip (randomized anyway) 85 if res and res.addresses: 86 result.value = res.addresses[0]
87 88 # resolve with cb 89 careschan.gethostbyname(name, socket.AF_INET, setresult_cb) 90 91 # now do the actual work 92 readfds, writefds = careschan.getsock() 93 canreadfds, canwritefds, _ = select.select(readfds, writefds, [], 94 DNS_TIMEOUT) 95 for rfd in canreadfds: 96 careschan.process_fd(rfd, -1) 97 98 # if the query did not succeed, setresult was not called and we just 99 # return result destroy the channel first to not leak anything 100 careschan.destroy() 101 return result.value 102 103 # workaround until py3 nonlocal (for c-ares and gevent)
104 -class Resultholder:
105 pass
106 107 108 # gevent based resolver with timeout
109 -def resolve_gevent(name):
110 result = resolve_gevent_real(name) 111 # if it failed, do this a second time because of strange libevent behavior 112 # basically sometimes the Timeout fires immediately instead of after 113 # DNS_TIMEOUT 114 if result == DNS_TIMEOUT_VALUE: 115 result = resolve_gevent_real(name) 116 return result
117
118 -def resolve_gevent_real(name):
119 result = DNS_TIMEOUT_VALUE 120 with gevent.Timeout(DNS_TIMEOUT, False): 121 try: 122 result = gevent.socket.gethostbyname(name) 123 except socket.gaierror: 124 pass 125 126 return result
127 128 129 # choose resolver automatically
130 -def resolve(name):
131 if HAVE_CARES: 132 return resolve_cares(name) 133 elif HAVE_GEVENT: 134 return resolve_gevent(name) 135 else: 136 return resolve_thread(name)
137 138 # another alias 139 resolve_best = resolve 140