def handleQuery(self, msg, addr, port): """Deal with incoming query packets. Provides a response if possible.""" out = None # Support unicast client responses # if port != dns._MDNS_PORT: out = dns.DNSOutgoing(dns._FLAGS_QR_RESPONSE | dns._FLAGS_AA, 0) for question in msg.questions: out.addQuestion(question) log.debug( 'Questions...') for question in msg.questions: log.debug( 'Question: %s', question ) if question.type == dns._TYPE_PTR: for service in list(self.services.values()): if question.name == service.type: log.info( 'Service query found %s', service.name ) if out is None: out = dns.DNSOutgoing(dns._FLAGS_QR_RESPONSE | dns._FLAGS_AA) out.addAnswer(msg, dns.DNSPointer(service.type, dns._TYPE_PTR, dns._CLASS_IN, dns._DNS_TTL, service.name)) # devices such as AAstra phones will not re-query to # resolve the pointer, they expect the final IP to show up # in the response out.addAdditionalAnswer(dns.DNSText(service.name, dns._TYPE_TXT, dns._CLASS_IN | dns._CLASS_UNIQUE, dns._DNS_TTL, service.text)) out.addAdditionalAnswer(dns.DNSService(service.name, dns._TYPE_SRV, dns._CLASS_IN | dns._CLASS_UNIQUE, dns._DNS_TTL, service.priority, service.weight, service.port, service.server)) out.addAdditionalAnswer(dns.DNSAddress(service.server, dns._TYPE_A, dns._CLASS_IN | dns._CLASS_UNIQUE, dns._DNS_TTL, service.address)) else: try: if out is None: out = dns.DNSOutgoing(dns._FLAGS_QR_RESPONSE | dns._FLAGS_AA) # Answer A record queries for any service addresses we know if question.type == dns._TYPE_A or question.type == dns._TYPE_ANY: for service in list(self.services.values()): if service.server == question.name.lower(): out.addAnswer(msg, DNSAddress(question.name, dns._TYPE_A, dns._CLASS_IN | dns._CLASS_UNIQUE, dns._DNS_TTL, service.address)) service = self.services.get(question.name.lower(), None) if not service: continue if question.type == dns._TYPE_SRV or question.type == dns._TYPE_ANY: out.addAnswer(msg, dns.DNSService(question.name, dns._TYPE_SRV, dns._CLASS_IN | dns._CLASS_UNIQUE, dns._DNS_TTL, service.priority, service.weight, service.port, service.server)) if question.type == dns._TYPE_TXT or question.type == dns._TYPE_ANY: out.addAnswer(msg, dns.DNSText(question.name, dns._TYPE_TXT, dns._CLASS_IN | dns._CLASS_UNIQUE, dns._DNS_TTL, service.text)) if question.type == dns._TYPE_SRV: out.addAdditionalAnswer(dns.DNSAddress(service.server, dns._TYPE_A, dns._CLASS_IN | dns._CLASS_UNIQUE, dns._DNS_TTL, service.address)) except Exception as err: log.error( 'Error handling query: %s',traceback.format_exc() ) if out is not None and out.answers: out.id = msg.id self.send(out, addr, port) else: log.debug( 'No answer for %s', [q for q in msg.questions] )
def registerService(self, info, ttl=dns._DNS_TTL): """Registers service information to the network with a default TTL of 60 seconds. Zeroconf will then respond to requests for information for that service. The name of the service may be changed if needed to make it unique on the network.""" #print "REGISTERING SERVICE!" #log.debug(">>",self.services[info.name.lower()]) #import pdb #pdb.set_trace() self.checkService(info) self.services[info.name.lower()] = info log.debug(">>",self.services[info.name.lower()]) now = dns.currentTimeMillis() nextTime = now i = 0 while i < 3: if now < nextTime: self.wait(nextTime - now) now = dns.currentTimeMillis() continue out = dns.DNSOutgoing(dns._FLAGS_QR_RESPONSE | dns._FLAGS_AA) out.addAnswerAtTime(dns.DNSPointer(info.type, dns._TYPE_PTR, dns._CLASS_IN, ttl, info.name), 0) out.addAnswerAtTime(dns.DNSService(info.name, dns._TYPE_SRV, dns._CLASS_IN, ttl, info.priority, info.weight, info.port, info.server), 0) out.addAnswerAtTime(dns.DNSText(info.name, dns._TYPE_TXT, dns._CLASS_IN, ttl, info.text), 0) if info.address: out.addAnswerAtTime(dns.DNSAddress(info.server, dns._TYPE_A, dns._CLASS_IN, ttl, info.address), 0) self.send(out) i += 1 nextTime += _REGISTER_TIME print("registerService end")
def unregisterAllServices(self): """Unregister all registered services.""" if len(self.services) > 0: now = dns.currentTimeMillis() nextTime = now i = 0 while i < 3: if now < nextTime: self.wait(nextTime - now) now = dns.currentTimeMillis() continue out = dns.DNSOutgoing(dns._FLAGS_QR_RESPONSE | dns._FLAGS_AA) for info in self.services.values(): out.addAnswerAtTime( dns.DNSPointer(info.type, dns._TYPE_PTR, dns._CLASS_IN, 0, info.name), 0) out.addAnswerAtTime( dns.DNSService(info.name, dns._TYPE_SRV, dns._CLASS_IN, 0, info.priority, info.weight, info.port, info.server), 0) out.addAnswerAtTime( dns.DNSText(info.name, dns._TYPE_TXT, dns._CLASS_IN, 0, info.text), 0) if info.address: out.addAnswerAtTime( dns.DNSAddress(info.server, dns._TYPE_A, dns._CLASS_IN, 0, info.address), 0) self.send(out) i += 1 nextTime += _UNREGISTER_TIME
def unregisterService(self, info): """Unregister a service.""" try: del (self.services[info.name.lower()]) except: pass now = dns.currentTimeMillis() nextTime = now i = 0 while i < 3: if now < nextTime: self.wait(nextTime - now) now = dns.currentTimeMillis() continue out = dns.DNSOutgoing(dns._FLAGS_QR_RESPONSE | dns._FLAGS_AA) out.addAnswerAtTime( dns.DNSPointer(info.type, dns._TYPE_PTR, dns._CLASS_IN, 0, info.name), 0) out.addAnswerAtTime( dns.DNSService(info.name, dns._TYPE_SRV, dns._CLASS_IN, 0, info.priority, info.weight, info.port, info.name), 0) out.addAnswerAtTime( dns.DNSText(info.name, dns._TYPE_TXT, dns._CLASS_IN, 0, info.text), 0) if info.address: out.addAnswerAtTime( dns.DNSAddress(info.server, dns._TYPE_A, dns._CLASS_IN, 0, info.address), 0) self.send(out) i += 1 nextTime += _UNREGISTER_TIME
def serviceAnnouncement( cls, info, ttl=dns._DNS_TTL ): out = dns.DNSOutgoing(dns._FLAGS_QR_RESPONSE | dns._FLAGS_AA) out.addAnswerAtTime(dns.DNSPointer(info.type, dns._TYPE_PTR, dns._CLASS_IN, ttl, info.name), 0) out.addAnswerAtTime(dns.DNSService(info.name, dns._TYPE_SRV, dns._CLASS_IN, ttl, info.priority, info.weight, info.port, info.server), 0) out.addAnswerAtTime(dns.DNSText(info.name, dns._TYPE_TXT, dns._CLASS_IN, ttl, info.text), 0) if info.address: out.addAnswerAtTime(dns.DNSAddress(info.server, dns._TYPE_A, dns._CLASS_IN, ttl, info.address), 0) return out
def responses(self, question, msg, out): """Adds all responses to out which match the given question Note that the incoming query may suppress our responses by having cache times higher than our records. That is, out.answers may be null even if we have the records that match the query. """ log.debug('Question: %s', question) for service in self.services.values(): if question.type == dns._TYPE_PTR: if question.name.lower() in (service.type.lower(), service.name.lower()): log.debug('Service query found %s', service.name) out.addAnswer( msg, dns.DNSPointer(question.name, dns._TYPE_PTR, dns._CLASS_IN, dns._DNS_TTL, service.name)) # devices such as AAstra phones will not re-query to # resolve the pointer, they expect the final IP to show up # in the response out.addAdditionalAnswer( dns.DNSText(service.name, dns._TYPE_TXT, dns._CLASS_IN | dns._CLASS_UNIQUE, dns._DNS_TTL, service.text)) out.addAdditionalAnswer( dns.DNSService(service.name, dns._TYPE_SRV, dns._CLASS_IN | dns._CLASS_UNIQUE, dns._DNS_TTL, service.priority, service.weight, service.port, service.server)) out.addAdditionalAnswer( dns.DNSAddress(service.server, dns._TYPE_A, dns._CLASS_IN | dns._CLASS_UNIQUE, dns._DNS_TTL, service.address)) else: if question.type in (dns._TYPE_A, ): if service.server.lower() == question.name.lower(): out.addAnswer( msg, dns.DNSAddress(question.name, dns._TYPE_A, dns._CLASS_IN | dns._CLASS_UNIQUE, dns._DNS_TTL, service.address)) if question.type in (dns._TYPE_SRV, dns._TYPE_ANY): if question.name.lower() in (service.name.lower(), service.server.lower(), service.type.lower()): out.addAnswer( msg, dns.DNSService(question.name, dns._TYPE_SRV, dns._CLASS_IN | dns._CLASS_UNIQUE, dns._DNS_TTL, service.priority, service.weight, service.port, service.server)) if question.type in (dns._TYPE_TXT, dns._TYPE_ANY): if question.name.lower() in (service.name.lower(), service.server.lower(), service.type.lower()): out.addAnswer( msg, dns.DNSText(question.name, dns._TYPE_TXT, dns._CLASS_IN | dns._CLASS_UNIQUE, dns._DNS_TTL, service.text)) if question.type in (dns._TYPE_SRV, dns._TYPE_ANY): # srv queries need the address for aastra-style single query if question.name.lower() in (service.name.lower(), service.server.lower(), service.type.lower()): out.addAdditionalAnswer( dns.DNSAddress(service.server, dns._TYPE_A, dns._CLASS_IN | dns._CLASS_UNIQUE, dns._DNS_TTL, service.address))