1 # -*- test-case-name: twisted.names.test.test_hosts -*-
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
9 from twisted.names import dns
10 from twisted.persisted import styles
11 from twisted.python import failure
12 from twisted.python.filepath import FilePath
13 from twisted.internet import defer
14 from twisted.internet.abstract import isIPAddress
16 from twisted.names import common
18 def searchFileForAll(hostsFile, name):
20 Search the given file, which is in hosts(5) standard format, for an address
21 entry with a given name.
23 @param hostsFile: The name of the hosts(5)-format file to search.
24 @type hostsFile: L{FilePath}
26 @param name: The name to search for.
29 @return: C{None} if the name is not found in the file, otherwise a
30 C{str} giving the address in the file associated with the name.
34 lines = hostsFile.getContent().splitlines()
47 if name.lower() in [s.lower() for s in parts[1:]]:
48 results.append(parts[0])
53 def searchFileFor(file, name):
55 Grep given file, which is in hosts(5) standard format, for an address
56 entry with a given name.
58 @param file: The name of the hosts(5)-format file to search.
60 @param name: The name to search for.
63 @return: C{None} if the name is not found in the file, otherwise a
64 C{str} giving the address in the file associated with the name.
66 addresses = searchFileForAll(FilePath(file), name)
73 class Resolver(common.ResolverBase, styles.Versioned):
75 A resolver that services hosts(5) format files.
78 persistenceVersion = 1
80 def upgradeToVersion1(self):
82 self.typeToMethod = {}
83 for (k, v) in common.typeToMethod.items():
84 self.typeToMethod[k] = getattr(self, v)
87 def __init__(self, file='/etc/hosts', ttl = 60 * 60):
88 common.ResolverBase.__init__(self)
93 def _aRecords(self, name):
95 Return a tuple of L{dns.RRHeader} instances for all of the IPv4
96 addresses in the hosts file.
99 dns.RRHeader(name, dns.A, dns.IN, self.ttl,
100 dns.Record_A(addr, self.ttl))
102 in searchFileForAll(FilePath(self.file), name)
103 if isIPAddress(addr)])
106 def _aaaaRecords(self, name):
108 Return a tuple of L{dns.RRHeader} instances for all of the IPv6
109 addresses in the hosts file.
112 dns.RRHeader(name, dns.AAAA, dns.IN, self.ttl,
113 dns.Record_AAAA(addr, self.ttl))
115 in searchFileForAll(FilePath(self.file), name)
116 if not isIPAddress(addr)])
119 def _respond(self, name, records):
121 Generate a response for the given name containing the given result
122 records, or a failure if there are no result records.
124 @param name: The DNS name the response is for.
127 @param records: A tuple of L{dns.RRHeader} instances giving the results
128 that will go into the response.
130 @return: A L{Deferred} which will fire with a three-tuple of result
131 records, authority records, and additional records, or which will
132 fail with L{dns.DomainError} if there are no result records.
135 return defer.succeed((records, (), ()))
136 return defer.fail(failure.Failure(dns.DomainError(name)))
139 def lookupAddress(self, name, timeout=None):
141 Read any IPv4 addresses from C{self.file} and return them as L{Record_A}
144 return self._respond(name, self._aRecords(name))
147 def lookupIPV6Address(self, name, timeout=None):
149 Read any IPv4 addresses from C{self.file} and return them as L{Record_A}
152 return self._respond(name, self._aaaaRecords(name))
154 # Someday this should include IPv6 addresses too, but that will cause
155 # problems if users of the API (mainly via getHostByName) aren't updated to
156 # know about IPv6 first.
157 lookupAllRecords = lookupAddress