def testName(self): for n in self.names: # encode the name f = StringIO() dns.Name(n).encode(f) # decode the name f.seek(0, 0) result = dns.Name() result.decode(f) self.assertEquals(result.name, n)
def _fetchServers(self, host): try: service = "_matrix._tcp.%s" % host answers, auth, add = yield client.lookupService(service) except DNSNameError: answers = [] if (len(answers) == 1 and answers[0].type == dns.SRV and answers[0].payload and answers[0].payload.target == dns.Name(".")): raise DNSNameError("Service %s unavailable", service) servers = [] for answer in answers: if answer.type != dns.SRV or not answer.payload: continue payload = answer.payload servers.append(ThreepidBinder._Server( host=str(payload.target), port=int(payload.port), priority=int(payload.priority), weight=int(payload.weight) )) servers.sort() defer.returnValue(servers)
def fetch_servers(self): try: answers, auth, add = yield client.lookupService(self.service_name) except DNSNameError: answers = [] if (len(answers) == 1 and answers[0].type == dns.SRV and answers[0].payload and answers[0].payload.target == dns.Name('.')): raise ConnectError("Service %s unavailable", self.service_name) self.servers = [] self.used_servers = [] for answer in answers: if answer.type != dns.SRV or not answer.payload: continue payload = answer.payload self.servers.append( self._Server(host=str(payload.target), port=int(payload.port), priority=int(payload.priority), weight=int(payload.weight))) self.servers.sort()
async def resolve_service(self, service_name: bytes) -> List["Server"]: """Look up a SRV record :param service_name: The record to look up. :returns a list of the SRV records, or an empty list if none found. """ now = int(self._get_time()) cache_entry = self._cache.get(service_name, None) if cache_entry: if all(s.expires > now for s in cache_entry): servers = list(cache_entry) return servers try: answers, _, _ = await self._lookup_service(service_name.decode()) except DNSNameError: # TODO: cache this. We can get the SOA out of the exception, and use # the negative-TTL value. return [] except DomainError as e: # We failed to resolve the name (other than a NameError) # Try something in the cache, else rereaise cache_entry = self._cache.get(service_name, None) if cache_entry: logger.warning( "Failed to resolve %r, falling back to cache. %r", service_name, e) return list(cache_entry) else: raise e if (len(answers) == 1 and answers[0].type == dns.SRV and answers[0].payload and answers[0].payload.target == dns.Name(b".")): raise ConnectError("Service %s unavailable" % service_name.decode()) servers = [] for answer in answers: if answer.type != dns.SRV or not answer.payload: continue payload = answer.payload servers.append( Server( host=payload.target.name, port=payload.port, priority=payload.priority, weight=payload.weight, expires=now + answer.ttl, )) self._cache[service_name] = list(servers) return servers
def resolve_service(service_name, dns_client=client, cache=SERVER_CACHE, clock=time): cache_entry = cache.get(service_name, None) if cache_entry: if all(s.expires > int(clock.time()) for s in cache_entry): servers = list(cache_entry) defer.returnValue(servers) servers = [] try: try: answers, _, _ = yield dns_client.lookupService(service_name) except DNSNameError: defer.returnValue([]) if (len(answers) == 1 and answers[0].type == dns.SRV and answers[0].payload and answers[0].payload.target == dns.Name('.')): raise ConnectError("Service %s unavailable" % service_name) for answer in answers: if answer.type != dns.SRV or not answer.payload: continue payload = answer.payload hosts = yield _get_hosts_for_srv_record( dns_client, str(payload.target) ) for (ip, ttl) in hosts: host_ttl = min(answer.ttl, ttl) servers.append(_Server( host=ip, port=int(payload.port), priority=int(payload.priority), weight=int(payload.weight), expires=int(clock.time()) + host_ttl, )) servers.sort() cache[service_name] = list(servers) except DomainError as e: # We failed to resolve the name (other than a NameError) # Try something in the cache, else rereaise cache_entry = cache.get(service_name, None) if cache_entry: logger.warn( "Failed to resolve %r, falling back to cache. %r", service_name, e ) servers = list(cache_entry) else: raise e defer.returnValue(servers)
def resolve_service(service_name, dns_client=client, cache=SERVER_CACHE): servers = [] try: try: answers, _, _ = yield dns_client.lookupService(service_name) except DNSNameError: defer.returnValue([]) if (len(answers) == 1 and answers[0].type == dns.SRV and answers[0].payload and answers[0].payload.target == dns.Name('.')): raise ConnectError("Service %s unavailable", service_name) for answer in answers: if answer.type != dns.SRV or not answer.payload: continue payload = answer.payload host = str(payload.target) try: answers, _, _ = yield dns_client.lookupAddress(host) except DNSNameError: continue ips = [ answer.payload.dottedQuad() for answer in answers if answer.type == dns.A and answer.payload ] for ip in ips: servers.append( _Server(host=ip, port=int(payload.port), priority=int(payload.priority), weight=int(payload.weight))) servers.sort() cache[service_name] = list(servers) except DomainError as e: # We failed to resolve the name (other than a NameError) # Try something in the cache, else rereaise cache_entry = cache.get(service_name, None) if cache_entry: logger.warn("Failed to resolve %r, falling back to cache. %r", service_name, e) servers = list(cache_entry) else: raise e defer.returnValue(servers)
def nameFromRawData(self, labels, offset=None): name = b'.'.join(labels) if offset is None: return dns.Name(name=name) visited = set() visited.add(offset) while 1: l = ord(self.data[offset]) offset += 1 if l == 0: return dns.Name(name) if (l >> 6) == 3: offset = (l & 63) << 8 | ord(self.data[offset]) if offset in visited: raise ValueError("Compression loop in compressed name") visited.add(offset) continue label = self.data[offset:offset + l] offset += l if name == b'': name = label else: name = name + b'.' + label
def _cbGotServers(self, result): answers, auth, add = result if len(answers) == 1 and answers[0].type == dns.SRV \ and answers[0].payload \ and answers[0].payload.target == dns.Name(b'.'): # decidedly not available raise error.DNSLookupError("Service %s not available for domain %s." % (repr(self.service), repr(self.domain))) self.servers = [] self.orderedServers = [] for a in answers: if a.type != dns.SRV or not a.payload: continue self.orderedServers.append(a.payload)
class SRVConnector: """A connector that looks up DNS SRV records. See RFC2782.""" implements(interfaces.IConnector) stopAfterDNS = 0 def __init__( self, reactor, service, domain, factory, protocol='tcp', connectFuncName='connectTCP', connectFuncArgs=(), connectFuncKwArgs={}, defaultPort=None, ): """ @param domain: The domain to connect to. If passed as a unicode string, it will be encoded using C{idna} encoding. @type domain: L{bytes} or L{unicode} @param defaultPort: Optional default port number to be used when SRV lookup fails and the service name is unknown. This should be the port number associated with the service name as defined by the IANA registry. @type defaultPort: C{int} """ self.reactor = reactor self.service = service if isinstance(domain, unicode): domain = domain.encode('idna') self.domain = domain self.factory = factory self.protocol = protocol self.connectFuncName = connectFuncName self.connectFuncArgs = connectFuncArgs self.connectFuncKwArgs = connectFuncKwArgs self._defaultPort = defaultPort self.connector = None self.servers = None self.orderedServers = None # list of servers already used in this round def connect(self): """Start connection to remote server.""" self.factory.doStart() self.factory.startedConnecting(self) if not self.servers: if self.domain is None: self.connectionFailed( error.DNSLookupError("Domain is not defined.")) return d = client.lookupService( '_%s._%s.%s' % (self.service, self.protocol, self.domain)) d.addCallbacks(self._cbGotServers, self._ebGotServers) d.addCallback(lambda x, self=self: self._reallyConnect()) if self._defaultPort: d.addErrback(self._ebServiceUnknown) d.addErrback(self.connectionFailed) elif self.connector is None: self._reallyConnect() else: self.connector.connect() def _ebGotServers(self, failure): failure.trap(DNSNameError) # Some DNS servers reply with NXDOMAIN when in fact there are # just no SRV records for that domain. Act as if we just got an # empty response and use fallback. self.servers = [] self.orderedServers = [] def _cbGotServers(self, (answers, auth, add)): if len(answers) == 1 and answers[0].type == dns.SRV \ and answers[0].payload \ and answers[0].payload.target == dns.Name('.'): # decidedly not available raise error.DNSLookupError( "Service %s not available for domain %s." % (repr(self.service), repr(self.domain))) self.servers = [] self.orderedServers = [] for a in answers: if a.type != dns.SRV or not a.payload: continue self.orderedServers.append((a.payload.priority, a.payload.weight, str(a.payload.target), a.payload.port))
class SRVMediaRelayBase(object): def __init__(self): self.shutting_down = False self.srv_monitor = RecurrentCall(RelayConfig.dns_check_interval, self._do_lookup) self._do_lookup() def _do_lookup(self): defers = [] for addr, port, is_domain in RelayConfig.dispatchers: if is_domain: defer = lookupService("_sip._udp.%s" % addr) defer.addCallback(self._cb_got_srv, port) defer.addErrback(self._eb_no_srv, addr, port) defers.append(defer) else: defers.append(succeed((addr, port))) defer = DeferredList(defers) defer.addCallback(self._cb_got_all) return KeepRunning def _cb_got_srv(self, (answers, auth, add), port): for answer in answers: if answer.type == dns.SRV and answer.payload and answer.payload.target != dns.Name( "."): return str(answer.payload.target), port raise DomainError
def resolve_service(self, service_name): """Look up a SRV record :param service_name: The record to look up. :type service_name: bytes :returns a list of the SRV records, or an empty list if none found. :rtype: Deferred[list[Server]] """ now = int(self._get_time()) if not isinstance(service_name, bytes): raise TypeError("%r is not a byte string" % (service_name, )) cache_entry = self._cache.get(service_name, None) if cache_entry: if all(s.expires > now for s in cache_entry): servers = list(cache_entry) defer.returnValue(servers) try: answers, _, _ = yield self._dns_client.lookupService(service_name) except DNSNameError: # TODO: cache this. We can get the SOA out of the exception, and use # the negative-TTL value. defer.returnValue([]) except DomainError as e: # We failed to resolve the name (other than a NameError) # Try something in the cache, else rereaise cache_entry = self._cache.get(service_name, None) if cache_entry: logger.warn("Failed to resolve %r, falling back to cache. %r", service_name, e) defer.returnValue(list(cache_entry)) else: raise e if (len(answers) == 1 and answers[0].type == dns.SRV and answers[0].payload and answers[0].payload.target == dns.Name(b'.')): raise ConnectError("Service %s unavailable" % service_name) servers = [] for answer in answers: if answer.type != dns.SRV or not answer.payload: continue payload = answer.payload servers.append( Server( host=payload.target.name, port=payload.port, priority=payload.priority, weight=payload.weight, expires=now + answer.ttl, )) self._cache[service_name] = list(servers) defer.returnValue(servers)
def lookupAllRecords(self, name, timeout=None): """ @see: twisted.names.client.lookupAllRecords """ return self._lookup(name, dns.IN, dns.ALL_RECORDS, timeout) def getHostByName(self, name, timeout=None, effort=10): """ @see: twisted.names.client.getHostByName """ # XXX - respect timeout return self.lookupAllRecords(name, timeout).addCallback( self._cbRecords, name, effort) def _cbRecords(self, (ans, auth, add), name, effort): result = extractRecord(self, dns.Name(name), ans + auth + add, effort) if not result: raise error.DNSLookupError(name) return result def extractRecord(resolver, name, answers, level=10): if not level: return None if hasattr(socket, 'inet_ntop'): for r in answers: if r.name == name and r.type == dns.A6: return socket.inet_ntop(socket.AF_INET6, r.payload.address) for r in answers: if r.name == name and r.type == dns.AAAA: return socket.inet_ntop(socket.AF_INET6, r.payload.address)
class SRVConnector: """A connector that looks up DNS SRV records. See RFC2782.""" implements(interfaces.IConnector) stopAfterDNS=0 def __init__(self, reactor, service, domain, factory, protocol='tcp', connectFuncName='connectTCP', connectFuncArgs=(), connectFuncKwArgs={}, ): self.reactor = reactor self.service = service self.domain = domain self.factory = factory self.protocol = protocol self.connectFuncName = connectFuncName self.connectFuncArgs = connectFuncArgs self.connectFuncKwArgs = connectFuncKwArgs self.connector = None self.servers = None self.orderedServers = None # list of servers already used in this round def connect(self): """Start connection to remote server.""" self.factory.doStart() self.factory.startedConnecting(self) if not self.servers: if self.domain is None: self.connectionFailed(error.DNSLookupError("Domain is not defined.")) return d = client.lookupService('_%s._%s.%s' % (self.service, self.protocol, self.domain)) d.addCallbacks(self._cbGotServers, self._ebGotServers) d.addCallback(lambda x, self=self: self._reallyConnect()) d.addErrback(self.connectionFailed) elif self.connector is None: self._reallyConnect() else: self.connector.connect() def _ebGotServers(self, failure): failure.trap(DNSNameError) # Some DNS servers reply with NXDOMAIN when in fact there are # just no SRV records for that domain. Act as if we just got an # empty response and use fallback. self.servers = [] self.orderedServers = [] def _cbGotServers(self, (answers, auth, add)): if len(answers) == 1 and answers[0].type == dns.SRV \ and answers[0].payload \ and answers[0].payload.target == dns.Name('.'): # decidedly not available raise error.DNSLookupError("Service %s not available for domain %s." % (repr(self.service), repr(self.domain))) self.servers = [] self.orderedServers = [] for a in answers: if a.type != dns.SRV or not a.payload: continue self.orderedServers.append((a.payload.priority, a.payload.weight, str(a.payload.target), a.payload.port))
def _cbRecords(self, records, name, effort): (ans, auth, add) = records result = extractRecord(self, dns.Name(name), ans + auth + add, effort) if not result: raise error.DNSLookupError(name) return result
def __init__(self, name=b'', type=dns.A, cls=dns.IN, hostname=None): self.name = dns.Name(name) self.type = type self.cls = cls self.hostname = hostname
_initResolver() lookup = "{}._tcp.{}".format( service, domain, ) log.debug("DNS SRV: lookup: {l}", l=lookup) try: answers = (yield DebugResolver.lookupService(lookup))[0] except (DomainError, AuthoritativeDomainError), e: log.debug("DNS SRV: lookup failed: {exc}", exc=e) returnValue(None) if (len(answers) == 1 and answers[0].type == dns.SRV and answers[0].payload and answers[0].payload.target == dns.Name('.')): # decidedly not available log.debug("DNS SRV: disabled: {l}", l=lookup) returnValue(None) servers = [] for a in answers: if a.type != dns.SRV or not a.payload: continue servers.append((a.payload.priority, a.payload.weight, str(a.payload.target), a.payload.port)) log.debug("DNS SRV: lookup results: {l}\n{s}", l=lookup, s=servers)
def fix_names(result): # Make sure names in response match what the client asked format for answer in result[0]: answer.name = dns.Name(real_name) print("RESULT: {}".format(result)) return result
async def resolve_service(self, service_name: bytes) -> List[Server]: """Look up a SRV record Args: service_name: record to look up Returns: a list of the SRV records, or an empty list if none found """ now = int(self._get_time()) if not isinstance(service_name, bytes): raise TypeError("%r is not a byte string" % (service_name, )) cache_entry = self._cache.get(service_name, None) if cache_entry: if all(s.expires > now for s in cache_entry): servers = list(cache_entry) return _sort_server_list(servers) try: answers, _, _ = await make_deferred_yieldable( self._dns_client.lookupService(service_name)) except DNSNameError: # TODO: cache this. We can get the SOA out of the exception, and use # the negative-TTL value. return [] except DomainError as e: # We failed to resolve the name (other than a NameError) # Try something in the cache, else rereaise cache_entry = self._cache.get(service_name, None) if cache_entry: logger.warning( "Failed to resolve %r, falling back to cache. %r", service_name, e) return list(cache_entry) else: raise e if (len(answers) == 1 and answers[0].type == dns.SRV and answers[0].payload and answers[0].payload.target == dns.Name(b".")): raise ConnectError(f"Service {service_name!r} unavailable") servers = [] for answer in answers: if answer.type != dns.SRV or not answer.payload: continue payload = answer.payload servers.append( Server( host=payload.target.name, port=payload.port, priority=payload.priority, weight=payload.weight, expires=now + answer.ttl, )) self._cache[service_name] = list(servers) return _sort_server_list(servers)