def handle(server, raddress, message): try: message = dns.message.from_wire(message) except: print "Error decoding DNS message" return if message.edns < 0: print "Received non-EDNS message, ignoring" return if not (message.opcode() == 5 and message.authority): print "Received non-UPDATE message, ignoring" return info = {'records': [], 'addresses': []} # Try to guess the interface this came in on for iface in netifaces.interfaces(): ifaddresses = netifaces.ifaddresses(iface) for af, addresses in ifaddresses.items(): if af != 2: # AF_INET continue for address in addresses: net = IPy.IP(address['addr']).make_net(address['netmask']) if IPy.IP(raddress[0]) in net: info['mymac'] = ifaddresses[17][0]['addr'] info['myif'] = iface for rrset in message.authority: info['records'].append(rrset) _add_addresses(info, rrset) for option in message.options: if option.otype == 2: info['ttl'] = struct.unpack("!L", option.data) if option.otype == 4: info['othermac'] = option.data.encode('hex_codec')[4:] # TODO: endsflags seems to indicate some other TTL # TODO: Better composability manage_host(info) _answer(server.socket, raddress, message)
def handle(self, message, raddress): try: #with ignored(dns.message.BadEDNS): message = dns.message.from_wire(message, ignore_trailing=True) except dns.message.BadEDNS: #yosemite's discoveryd sends an OPT record per active NIC, dnspython doesn't like more than 1 OPT record # https://github.com/rthalley/dnspython/blob/master/dns/message.py#L642 # so turn off Wi-Fi for ethernet-connected clients pass #or send back an nxdomain or servfail except: #no way to just catch dns.exceptions.* logging.warning("Error decoding DNS message from {}".format( raddress[0])) logging.debug(traceback.format_exc()) return if message.edns < 0: logging.warning( "Received non-EDNS message from {}, ignoring".format( raddress[0])) return if not (message.opcode() == 5 and message.authority): logging.warning( "Received non-UPDATE message from {}, ignoring".format( raddress[0])) return logging.debug("Received SPS registration from {}, parsing".format( raddress[0])) info = {'records': [], 'addresses': []} # Try to guess the interface this came in on # todo - precompute this table on new()? for iface in netifaces.interfaces(): ifaddresses = netifaces.ifaddresses(iface) for af, addresses in ifaddresses.items(): if af not in (netifaces.AF_INET, netifaces.AF_INET6): continue for address in addresses: mask = address['netmask'] if af == netifaces.AF_INET6: mask = ( mask.count('f') * 4 ) # convert linux masks to prefix length...gooney if address['addr'].find('%') > -1: continue #more linux ipv6 stupidity iface_net = ipaddress.ip_interface('{}/{}'.format( address['addr'], mask)).network if ipaddress.ip_address(raddress[0]) in iface_net: info['mymac'] = ifaddresses[ netifaces.AF_LINK][0]['addr'] info['myif'] = iface for rrset in message.authority: rrset.rdclass %= dns.rdataclass.UNIQUE #remove cache-flush bit #rrset.rdata = rrset.rdata.decode(utf-8) info['records'].append(rrset) self._add_addresses(info, rrset) logging.debug('NSUPDATE START--\n\n{}\n\n{}\n\n--NSUPDATE END'.format( message, message.options)) for option in message.options: if option.otype == dns.edns.UL: info['ttl'] = option.lease #send-WOL-no-later-than timer TTL if option.otype == dns.edns.OWNER: info['othermac'] = option.pmac #WOL target mac #if option.passwd: # password required in wakeup packet # mDNS.c:SendSPSRegistrationForOwner() doesn't seem to add a password self._answer(raddress, message) if len(message.options) == 2: # need both an owner and an update-lease option, else its just a post-wake notification (incremented seq number) manage_host(info)