This commit is contained in:
Kovid Goyal 2015-06-03 17:58:27 +05:30
parent 658061968b
commit f2ad28b964

View File

@ -104,9 +104,10 @@ _BROWSER_TIME = 500
# Some DNS constants # Some DNS constants
_MDNS_ADDR = '224.0.0.251' _MDNS_ADDR = '224.0.0.251'
_MDNS_PORT = 5353; _MDNS_PORT = 5353
_DNS_PORT = 53; _DNS_PORT = 53
_DNS_TTL = 60 * 60; # one hour default TTL _DNS_TTL = 60 * 60
# one hour default TTL
_MAX_MSG_TYPICAL = 1460 # unused _MAX_MSG_TYPICAL = 1460 # unused
_MAX_MSG_ABSOLUTE = 8972 _MAX_MSG_ABSOLUTE = 8972
@ -218,6 +219,7 @@ class BadTypeInNameException(Exception):
pass pass
class BadDomainName(Exception): class BadDomainName(Exception):
def __init__(self, pos): def __init__(self, pos):
Exception.__init__(self, "at position " + str(pos)) Exception.__init__(self, "at position " + str(pos))
@ -227,6 +229,7 @@ class BadDomainNameCircular(BadDomainName):
# implementation classes # implementation classes
class DNSEntry(object): class DNSEntry(object):
"""A DNS entry""" """A DNS entry"""
def __init__(self, name, type, clazz): def __init__(self, name, type, clazz):
@ -275,6 +278,7 @@ class DNSEntry(object):
return result return result
class DNSQuestion(DNSEntry): class DNSQuestion(DNSEntry):
"""A DNS question entry""" """A DNS question entry"""
def __init__(self, name, type, clazz): def __init__(self, name, type, clazz):
@ -292,6 +296,7 @@ class DNSQuestion(DNSEntry):
class DNSRecord(DNSEntry): class DNSRecord(DNSEntry):
"""A DNS record - like a DNS entry, but has a TTL""" """A DNS record - like a DNS entry, but has a TTL"""
def __init__(self, name, type, clazz, ttl): def __init__(self, name, type, clazz, ttl):
@ -353,6 +358,7 @@ class DNSRecord(DNSEntry):
return DNSEntry.toString(self, "record", arg) return DNSEntry.toString(self, "record", arg)
class DNSAddress(DNSRecord): class DNSAddress(DNSRecord):
"""A DNS address record""" """A DNS address record"""
def __init__(self, name, type, clazz, ttl, address): def __init__(self, name, type, clazz, ttl, address):
@ -377,6 +383,7 @@ class DNSAddress(DNSRecord):
return 'record[%s]' % self.address return 'record[%s]' % self.address
class DNSHinfo(DNSRecord): class DNSHinfo(DNSRecord):
"""A DNS host information record""" """A DNS host information record"""
def __init__(self, name, type, clazz, ttl, cpu, os): def __init__(self, name, type, clazz, ttl, cpu, os):
@ -400,6 +407,7 @@ class DNSHinfo(DNSRecord):
return self.cpu + " " + self.os return self.cpu + " " + self.os
class DNSPointer(DNSRecord): class DNSPointer(DNSRecord):
"""A DNS pointer record""" """A DNS pointer record"""
def __init__(self, name, type, clazz, ttl, alias): def __init__(self, name, type, clazz, ttl, alias):
@ -421,6 +429,7 @@ class DNSPointer(DNSRecord):
return self.toString(self.alias) return self.toString(self.alias)
class DNSText(DNSRecord): class DNSText(DNSRecord):
"""A DNS text record""" """A DNS text record"""
def __init__(self, name, type, clazz, ttl, text): def __init__(self, name, type, clazz, ttl, text):
@ -445,6 +454,7 @@ class DNSText(DNSRecord):
return self.toString(self.text) return self.toString(self.text)
class DNSService(DNSRecord): class DNSService(DNSRecord):
"""A DNS service record""" """A DNS service record"""
def __init__(self, name, type, clazz, ttl, priority, weight, port, server): def __init__(self, name, type, clazz, ttl, priority, weight, port, server):
@ -472,6 +482,7 @@ class DNSService(DNSRecord):
return self.toString("%s:%s" % (self.server, self.port)) return self.toString("%s:%s" % (self.server, self.port))
class DNSIncoming(object): class DNSIncoming(object):
"""Object representation of an incoming DNS packet""" """Object representation of an incoming DNS packet"""
def __init__(self, data): def __init__(self, data):
@ -566,7 +577,8 @@ class DNSIncoming(object):
elif info[0] == _TYPE_TXT: elif info[0] == _TYPE_TXT:
rec = DNSText(domain, info[0], info[1], info[2], self.readString(info[3])) rec = DNSText(domain, info[0], info[1], info[2], self.readString(info[3]))
elif info[0] == _TYPE_SRV: elif info[0] == _TYPE_SRV:
rec = DNSService(domain, info[0], info[1], info[2], self.readUnsignedShort(), self.readUnsignedShort(), self.readUnsignedShort(), self.readName()) rec = DNSService(domain, info[0], info[1], info[2], self.readUnsignedShort(),
self.readUnsignedShort(), self.readUnsignedShort(), self.readName())
elif info[0] == _TYPE_HINFO: elif info[0] == _TYPE_HINFO:
rec = DNSHinfo(domain, info[0], info[1], info[2], self.readCharacterString(), self.readCharacterString()) rec = DNSHinfo(domain, info[0], info[1], info[2], self.readCharacterString(), self.readCharacterString())
elif info[0] == _TYPE_AAAA: elif info[0] == _TYPE_AAAA:
@ -628,6 +640,7 @@ class DNSIncoming(object):
class DNSOutgoing(object): class DNSOutgoing(object):
"""Object representation of an outgoing packet""" """Object representation of an outgoing packet"""
def __init__(self, flags, multicast=1): def __init__(self, flags, multicast=1):
@ -790,6 +803,7 @@ class DNSOutgoing(object):
class DNSCache(object): class DNSCache(object):
"""A cache of DNS entries""" """A cache of DNS entries"""
def __init__(self): def __init__(self):
@ -835,7 +849,8 @@ class DNSCache(object):
def entries(self): def entries(self):
"""Returns a list of all entries""" """Returns a list of all entries"""
def add(x, y): return x+y def add(x, y):
return x+y
try: try:
return reduce(add, self.cache.values()) return reduce(add, self.cache.values())
except: except:
@ -843,6 +858,7 @@ class DNSCache(object):
class Engine(threading.Thread): class Engine(threading.Thread):
"""An engine wraps read access to sockets, allowing objects that """An engine wraps read access to sockets, allowing objects that
need to receive data from sockets to be called back when the need to receive data from sockets to be called back when the
sockets are ready. sockets are ready.
@ -914,6 +930,7 @@ class Engine(threading.Thread):
self.condition.release() self.condition.release()
class Listener(object): class Listener(object):
"""A Listener is used by this module to listen on the multicast """A Listener is used by this module to listen on the multicast
group to which DNS messages are sent, allowing the implementation group to which DNS messages are sent, allowing the implementation
to cache information as it arrives. to cache information as it arrives.
@ -945,6 +962,7 @@ class Listener(object):
class Reaper(threading.Thread): class Reaper(threading.Thread):
"""A Reaper is used by this module to remove cache entries that """A Reaper is used by this module to remove cache entries that
have expired.""" have expired."""
@ -976,6 +994,7 @@ class Reaper(threading.Thread):
class ServiceBrowser(threading.Thread): class ServiceBrowser(threading.Thread):
"""Used to browse for a service of a specific type. """Used to browse for a service of a specific type.
The listener object will have its addService() and The listener object will have its addService() and
@ -1055,6 +1074,7 @@ class ServiceBrowser(threading.Thread):
class ServiceInfo(object): class ServiceInfo(object):
"""Service information""" """Service information"""
def __init__(self, type, name, address=None, port=None, weight=0, priority=0, properties=None, server=None): def __init__(self, type, name, address=None, port=None, weight=0, priority=0, properties=None, server=None):
@ -1259,6 +1279,7 @@ class ServiceInfo(object):
class Zeroconf(object): class Zeroconf(object):
"""Implementation of Zeroconf Multicast DNS Service Discovery """Implementation of Zeroconf Multicast DNS Service Discovery
Supports registration, unregistration, queries and browsing. Supports registration, unregistration, queries and browsing.
@ -1361,10 +1382,7 @@ class Zeroconf(object):
changed if needed to make it unique on the network.""" changed if needed to make it unique on the network."""
self.checkService(info) self.checkService(info)
self.services[info.name.lower()] = info self.services[info.name.lower()] = info
if self.servicetypes.has_key(info.type): self.servicetypes.set(info.type, self.servicetypes.get(info.type, 0) + 1)
self.servicetypes[info.type]+=1
else:
self.servicetypes[info.type]=1
now = currentTimeMillis() now = currentTimeMillis()
nextTime = now nextTime = now
i = 0 i = 0
@ -1542,13 +1560,16 @@ class Zeroconf(object):
if question.type in (_TYPE_A, _TYPE_AAAA, _TYPE_ANY): if question.type in (_TYPE_A, _TYPE_AAAA, _TYPE_ANY):
for service in self.services.values(): for service in self.services.values():
if service.server == question.name.lower(): if service.server == question.name.lower():
out.addAnswer(msg, DNSAddress(question.name, address_type(service.address), _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.address)) out.addAnswer(
msg, DNSAddress(question.name, address_type(service.address), _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.address))
service = self.services.get(question.name.lower(), None) service = self.services.get(question.name.lower(), None)
if not service: continue if not service:
continue
if question.type == _TYPE_SRV or question.type == _TYPE_ANY: if question.type == _TYPE_SRV or question.type == _TYPE_ANY:
out.addAnswer(msg, DNSService(question.name, _TYPE_SRV, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.priority, service.weight, service.port, service.server)) out.addAnswer(msg, DNSService(question.name, _TYPE_SRV, _CLASS_IN | _CLASS_UNIQUE,
_DNS_TTL, service.priority, service.weight, service.port, service.server))
if question.type == _TYPE_TXT or question.type == _TYPE_ANY: if question.type == _TYPE_TXT or question.type == _TYPE_ANY:
out.addAnswer(msg, DNSText(question.name, _TYPE_TXT, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.text)) out.addAnswer(msg, DNSText(question.name, _TYPE_TXT, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.text))
if question.type == _TYPE_SRV: if question.type == _TYPE_SRV: