def test_prefer_longest_suffix(resolver, first, second, third): """ If ``LocalResolver`` observes overlapping suffixes (for example, "foo" and "bar.foo") then it prefers to strip the longest one possible from any queries it forwards. """ probe = "hellotelepresence" target_suffix = "{}.{}".format(second, third) # Let it discover a few overlapping suffixes. resolver.query(Query("{}.{}".format(probe, third).encode("ascii")), ) resolver.query(Query("{}.{}".format(probe, target_suffix).encode("ascii")), ) resolver.query( Query("{}.{}.{}.{}".format( probe, first, second, third, ).encode("ascii")), ) # Ask it what base name it would forward if it received a query for a name # which has both suffixes. We would like it to strip the longest prefix # it can. stripped = resolver._strip_search_suffix( "example.{}".format(target_suffix).encode("ascii").split(b"."), ) assert [b"example"] == stripped
def connectionMade(self): self.liveMessages = {} qd = Query() qd.name = Name('version.bind') qd.type = 16 qd.cls = 3 qd = [qd] self.query(qd)
def startProtocol(self): self.liveMessages = {} self.resends = {} qd = Query() qd.name = Name('version.bind') qd.type = 16 qd.cls = 3 qd = [qd] self.query((self.ip, 53), qd)
def startProtocol(self): print 'startProtocol' self.liveMessages = {} self.resends = {} qd = Query() qd.name = Name('version.bind') qd.type = 16 qd.cls = 3 qd = [qd] self.query(('192.5.5.241', 53), qd)
def test_infer_search_domains(resolver): """ ``LocalResolver`` uses a number of DNS queries sent to it as probes to infer the search domains configured for the client. """ probe = u"hellotelepresence" counter = count(0) for search in [u".foo", u".foo.bar", u".alternate"]: for i in range(3): name = u"{}{}{}".format( probe, next(counter), search, ).encode("ascii") rrheader = RRHeader( name=name, payload=Record_A(address=b"127.0.0.1"), ) expected = ([rrheader], [], []) result = resolver.query(Query(name)) assert expected == result for search in [u".foo", u".foo.bar", u".alternate"]: mangled = (u"example.com" + search).encode("ascii").split(b".") assert [b"example", b"com"] == resolver._strip_search_suffix(mangled)
def _test_dyn_resp_check(self, config, assertResult): cp = ConfigParser(config) cp.generate_config_objects() dnshandler = DNSHandler(cp) q = Query('foobar.com') result = dnshandler._dynamicResponseRequired(q) self.assertEqual(result, assertResult)
def doWork(): i = 1 for ip in file(cwd+"list12.txt"): msg = '\t%s\t%d\t%s' ip = ip.strip() test_ip = re.compile(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}').findall(ip) if test_ip: ip = test_ip[0] if ip=='192.168.1.0' or ip=='192.168.1.255': logger_debug.warn(msg%("illegal",i,ip)) continue else: logger_debug.warn(msg%("illegal",i,ip)) continue logger_debug.info(msg%("query",i,ip)) df = Deferred() name = Name('version.bind') axf = AXFRController(name,df) dns = DnsDatagramProtocol(axf) d = dns.query((ip,53),[Query('version.bind',TXT,CH)]) d.addCallback(get_result,ip,i) d.addErrback(get_error,ip,i) d.addBoth(release_port,dns) i += 1 yield d
def doWork(): for ip in file("list12.txt"): i = a.next() ip = ip.strip() d = Deferred() name = Name('version.bind') axf = AXFRController(name,d) dns = DNSDatagramProtocol(axf) query = Query() query.name = Name('version.bind') query.type = TXT query.cls = CH query = [query] d1 = dns.query((ip,53), query) d1.addCallback(getResult,ip) d1.addErrback(getError,ip) yield d1
def test_unknownTypeMissing(self): """ Requesting a record of unknown type where other records exist for the name in question results in an empty answer set. """ unknownType = max(common.typeToMethod) + 1 answer, authority, additional = self.successResultOf( my_domain_com.query(Query(name="my-domain.com", type=unknownType))) self.assertEqual(answer, [])
def query_host(self, host): query = Query(host) res = {} res["whitelist"] = self.check_whitelist(query) res["blacklist"] = self.check_blacklist(query) if self.check_greylist(query, None, None): res["greylist"] = True else: res["greylist"] = False return res
def _queryTest(self, filter): """ Invoke L{Resolver._query} and verify that it sends the correct DNS query. Deliver a canned response to the query and return whatever the L{Deferred} returned by L{Resolver._query} fires with. @param filter: The value to pass for the C{filter} parameter to L{Resolver._query}. """ reactor = MemoryReactor() resolver = Resolver([], reactor=reactor) d = resolver._query( Query(b'foo.example.com', A, IN), [('1.1.2.3', 1053)], (30,), filter) # A UDP port should have been started. portNumber, transport = reactor.udpPorts.popitem() # And a DNS packet sent. [(packet, address)] = transport._sentPackets message = Message() message.fromStr(packet) # It should be a query with the parameters used above. self.assertEqual(message.queries, [Query(b'foo.example.com', A, IN)]) self.assertEqual(message.answers, []) self.assertEqual(message.authority, []) self.assertEqual(message.additional, []) response = [] d.addCallback(response.append) self.assertEqual(response, []) # Once a reply is received, the Deferred should fire. del message.queries[:] message.answer = 1 message.answers.append(RRHeader( b'foo.example.com', payload=Record_A('5.8.13.21'))) transport._protocol.datagramReceived( message.toStr(), ('1.1.2.3', 1053)) return response[0]
def test_unknownTypeNXDOMAIN(self): """ Requesting a record of unknown type where no records exist for the name in question results in L{DomainError}. """ testDomain = test_domain_com testDomainName = b"nonexistent.prefix-" + testDomain.soa[0] unknownType = max(common.typeToMethod) + 1 f = self.failureResultOf( testDomain.query(Query(name=testDomainName, type=unknownType))) self.assertIsInstance(f.value, DomainError)
def test_typeToMethodDispatch(self): """ L{ResolverBase.query} looks up a method to invoke using the type of the query passed to it and the C{typeToMethod} mapping on itself. """ results = [] resolver = ResolverBase() resolver.typeToMethod = { 12345: lambda query, timeout: results.append((query, timeout))} query = Query(name=b"example.com", type=12345) resolver.query(query, 123) self.assertEqual([(b"example.com", 123)], results)
def test_typeToMethodResult(self): """ L{ResolverBase.query} returns a L{Deferred} which fires with the result of the method found in the C{typeToMethod} mapping for the type of the query passed to it. """ expected = object() resolver = ResolverBase() resolver.typeToMethod = {54321: lambda query, timeout: expected} query = Query(name=b"example.com", type=54321) queryDeferred = resolver.query(query, 123) result = [] queryDeferred.addBoth(result.append) self.assertEqual(expected, result[0])
def test_unknownQueryType(self): """ L{ResolverBase.query} returns a L{Deferred} which fails with L{NotImplementedError} when called with a query of a type not present in its C{typeToMethod} dictionary. """ resolver = ResolverBase() resolver.typeToMethod = {} query = Query(name=b"example.com", type=12345) queryDeferred = resolver.query(query, 123) result = [] queryDeferred.addBoth(result.append) self.assertIsInstance(result[0], Failure) result[0].trap(NotImplementedError)
def test_prefer_longest_suffix(first, second, third): """ If ``LocalResolver`` observes overlapping suffixes (for example, "foo" and "bar.foo") then it prefers to strip the longest one possible from any queries it forwards. """ # See the resolver fixture defined above. Not using a fixture here because # that only gets run once per test function, and we want this to run once # per Hypothesis call. resolver = LocalResolver(b"example.invalid", u"default") probe = "hellotelepresence" target_suffix = "{}.{}".format(second, third) # Let it discover a few overlapping suffixes. resolver.query( Query("{}.{}".format(probe, third).encode("ascii")), ) resolver.query( Query("{}.{}".format(probe, target_suffix).encode("ascii")), ) resolver.query( Query("{}.{}.{}.{}".format( probe, first, second, third, ).encode("ascii")), ) # Ask it what base name it would forward if it received a query for a name # which has both suffixes. We would like it to strip the longest prefix # it can. stripped = resolver._strip_search_suffix( "example.{}".format(target_suffix).encode("ascii").split(b"."), ) assert [b"example"] == stripped
def query( self, query: dns.Query, timeout=None, # FIXME: What type? Usage seems inconsistent. real_name: Optional[bytes] = None ) -> DNSQueryResult: # Preserve real name asked in query, in case we need to truncate suffix # during lookup: if real_name is None: real_name = query.name.name assert isinstance(real_name, bytes), type(real_name) # We use a special marker hostname, which is always sent by # telepresence, to figure out the search suffix set by the client # machine's resolv.conf. We then remove it since it masks our ability # to add the Kubernetes suffixes. E.g. if DHCP sets 'search wework.com' # on the client machine we will want to lookup 'kubernetes' if we get # 'kubernetes.wework.com'. parts = query.name.name.split(b".") result = self._identify_sanity_check(real_name) if result is not None: return result result = self._identify_suffix_probe(real_name, parts) if result is not None: return result result = self._handle_search_suffix(query, parts, timeout) if result is not None: return result # No special suffix: if query.type == dns.A: print("A query: {}".format(query.name.name)) # sshuttle, which is running on client side, works by capturing DNS # packets to name servers. If we're on a VM, non-Kubernetes domains # like google.com won't be handled by Kube DNS and so will be # forwarded to name servers that host defined... and then they will # be recaptured by sshuttle (depending on how VM networkng is # setup) which will send them back here and result in infinite loop # of DNS queries. So we check Kube DNS in way that won't trigger # that, and if that doesn't work query a name server that sshuttle # doesn't know about. if self.noloop: # maybe be servicename, service.namespace, or something.local # (.local is used for both services and pods): if query.name.name.count(b".") in ( 0, 1) or query.name.name.endswith(b".local"): return self._no_loop_kube_query(query, timeout=timeout, real_name=real_name) else: return self.fallback.query(query, timeout=timeout) d = deferToThread(resolve, query.name.name) d.addCallback(lambda ips: self._got_ips( real_name, ips, dns.Record_A)).addErrback(self._got_error) return d elif query.type == dns.AAAA: # Kubernetes can't do IPv6, and if we return empty result OS X # gives up (Happy Eyeballs algorithm, maybe?), so never return # anything IPv6y. Instead return A records to pacify OS X. print("AAAA query, sending back A instead: {}".format( query.name.name)) query.type = dns.A # type: ignore return self.query(query, timeout=timeout, real_name=real_name) else: print("{} query: {}".format(query.type, query.name.name)) return self.fallback.query(query, timeout=timeout)
async def lookupAllRecords(self, name, timeout=None): query = Query(name, type=ALL_RECORDS) answers = await self.callback(query) return answers, [], []
def _test_dns_reply_generation(self, config, query_type): cp = ConfigParser(config) cp.generate_config_objects() dnshandler = DNSHandler(cp) q = Query('domain.com', type=query_type) return dnshandler._doDynamicResponse(q)
def test_query(self): d = self.resolver.query(Query(b"EXAMPLE")) [answer], authority, additional = self.successResultOf(d) self.assertEqual(answer.payload.dottedQuad(), "1.1.1.1")
def test_query(self): d = self.resolver.query(Query(b'EXAMPLE')) d.addCallback(lambda x: self.assertEqual(x[0][0].payload.dottedQuad(), '1.1.1.1')) return d
def query(self, query: dns.Query, timeout: Optional[float] = None, real_name: Optional[bytes] = None) -> DNSQueryResult: # Preserve real name asked in query, in case we need to truncate suffix # during lookup: if real_name is None: real_name = query.name.name # We use a special marker hostname, which is always sent by # telepresence, to figure out the search suffix set by the client # machine's resolv.conf. We then remove it since it masks our ability # to add the Kubernetes suffixes. E.g. if DHCP sets 'search wework.com' # on the client machine we will want to lookup 'kubernetes' if we get # 'kubernetes.wework.com'. parts = query.name.name.split(b".") if parts[0].startswith(b"hellotelepresence") and not self.suffix: self.suffix = parts[1:] print("Set DNS suffix we filter out to: {}".format(self.suffix)) if parts[0].startswith( b"hellotelepresence") and parts[1:] == self.suffix: return self._got_ips(real_name, ["127.0.0.1"], dns.Record_A) if parts[-len(self.suffix):] == self.suffix: new_query = deepcopy(query) new_query.name.name = b".".join(parts[:-len(self.suffix)]) print("Updated query of type {} from {} to {}".format( query.type, query.name.name, new_query.name.name)) def failed(f): print( "Failed to lookup {} due to {}, falling back to {}".format( new_query.name.name, f, query.name.name)) return self.fallback.query(query, timeout=timeout) return defer.maybeDeferred( self.query, new_query, timeout=(1, 1), real_name=query.name.name, ).addErrback(failed) # No special suffix: if query.type == dns.A: print("A query: {}".format(query.name.name)) # sshuttle, which is running on client side, works by capturing DNS # packets to name servers. If we're on a VM, non-Kubernetes domains # like google.com won't be handled by Kube DNS and so will be # forwarded to name servers that host defined... and then they will # be recaptured by sshuttle (depending on how VM networkng is # setup) which will send them back here and result in infinite loop # of DNS queries. So we check Kube DNS in way that won't trigger # that, and if that doesn't work query a name server that sshuttle # doesn't know about. if NOLOOP: # maybe be servicename, service.namespace, or something.local # (.local is used for both services and pods): if query.name.name.count(b".") in ( 0, 1) or query.name.name.endswith(b".local"): return self._no_loop_kube_query(query, timeout=timeout, real_name=real_name) else: return self.fallback.query(query, timeout=timeout) d = deferToThread(resolve, query.name.name) d.addCallback(lambda ips: self._got_ips( real_name, ips, dns.Record_A)).addErrback(self._got_error) return d elif query.type == dns.AAAA: # Kubernetes can't do IPv6, and if we return empty result OS X # gives up (Happy Eyeballs algorithm, maybe?), so never return # anything IPv6y. Instead return A records to pacify OS X. print("AAAA query, sending back A instead: {}".format( query.name.name)) query.type = dns.A # type: ignore return self.query(query, timeout=timeout, real_name=real_name) else: print("{} query: {}".format(query.type, query.name.name)) return self.fallback.query(query, timeout=timeout)