Initial import to Tizen
[profile/ivi/python-twisted.git] / twisted / names / hosts.py
1 # -*- test-case-name: twisted.names.test.test_hosts -*-
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5 """
6 hosts(5) support.
7 """
8
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
15
16 from twisted.names import common
17
18 def searchFileForAll(hostsFile, name):
19     """
20     Search the given file, which is in hosts(5) standard format, for an address
21     entry with a given name.
22
23     @param hostsFile: The name of the hosts(5)-format file to search.
24     @type hostsFile: L{FilePath}
25
26     @param name: The name to search for.
27     @type name: C{str}
28
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.
31     """
32     results = []
33     try:
34         lines = hostsFile.getContent().splitlines()
35     except:
36         return results
37
38     name = name.lower()
39     for line in lines:
40         idx = line.find('#')
41         if idx != -1:
42             line = line[:idx]
43         if not line:
44             continue
45         parts = line.split()
46
47         if name.lower() in [s.lower() for s in parts[1:]]:
48             results.append(parts[0])
49     return results
50
51
52
53 def searchFileFor(file, name):
54     """
55     Grep given file, which is in hosts(5) standard format, for an address
56     entry with a given name.
57
58     @param file: The name of the hosts(5)-format file to search.
59
60     @param name: The name to search for.
61     @type name: C{str}
62
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.
65     """
66     addresses = searchFileForAll(FilePath(file), name)
67     if addresses:
68         return addresses[0]
69     return None
70
71
72
73 class Resolver(common.ResolverBase, styles.Versioned):
74     """
75     A resolver that services hosts(5) format files.
76     """
77
78     persistenceVersion = 1
79
80     def upgradeToVersion1(self):
81         # <3 exarkun
82         self.typeToMethod = {}
83         for (k, v) in common.typeToMethod.items():
84             self.typeToMethod[k] = getattr(self, v)
85
86
87     def __init__(self, file='/etc/hosts', ttl = 60 * 60):
88         common.ResolverBase.__init__(self)
89         self.file = file
90         self.ttl = ttl
91
92
93     def _aRecords(self, name):
94         """
95         Return a tuple of L{dns.RRHeader} instances for all of the IPv4
96         addresses in the hosts file.
97         """
98         return tuple([
99             dns.RRHeader(name, dns.A, dns.IN, self.ttl,
100                          dns.Record_A(addr, self.ttl))
101             for addr
102             in searchFileForAll(FilePath(self.file), name)
103             if isIPAddress(addr)])
104
105
106     def _aaaaRecords(self, name):
107         """
108         Return a tuple of L{dns.RRHeader} instances for all of the IPv6
109         addresses in the hosts file.
110         """
111         return tuple([
112             dns.RRHeader(name, dns.AAAA, dns.IN, self.ttl,
113                          dns.Record_AAAA(addr, self.ttl))
114             for addr
115             in searchFileForAll(FilePath(self.file), name)
116             if not isIPAddress(addr)])
117
118
119     def _respond(self, name, records):
120         """
121         Generate a response for the given name containing the given result
122         records, or a failure if there are no result records.
123
124         @param name: The DNS name the response is for.
125         @type name: C{str}
126
127         @param records: A tuple of L{dns.RRHeader} instances giving the results
128             that will go into the response.
129
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.
133         """
134         if records:
135             return defer.succeed((records, (), ()))
136         return defer.fail(failure.Failure(dns.DomainError(name)))
137
138
139     def lookupAddress(self, name, timeout=None):
140         """
141         Read any IPv4 addresses from C{self.file} and return them as L{Record_A}
142         instances.
143         """
144         return self._respond(name, self._aRecords(name))
145
146
147     def lookupIPV6Address(self, name, timeout=None):
148         """
149         Read any IPv4 addresses from C{self.file} and return them as L{Record_A}
150         instances.
151         """
152         return self._respond(name, self._aaaaRecords(name))
153
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