Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

hosts.py 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. # -*- test-case-name: twisted.names.test.test_hosts -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. hosts(5) support.
  6. """
  7. from twisted.internet import defer
  8. from twisted.internet.abstract import isIPAddress, isIPv6Address
  9. from twisted.names import common, dns
  10. from twisted.python import failure
  11. from twisted.python.compat import nativeString
  12. from twisted.python.filepath import FilePath
  13. def searchFileForAll(hostsFile, name):
  14. """
  15. Search the given file, which is in hosts(5) standard format, for addresses
  16. associated with a given name.
  17. @param hostsFile: The name of the hosts(5)-format file to search.
  18. @type hostsFile: L{FilePath}
  19. @param name: The name to search for.
  20. @type name: C{bytes}
  21. @return: L{None} if the name is not found in the file, otherwise a
  22. C{str} giving the address in the file associated with the name.
  23. """
  24. results = []
  25. try:
  26. lines = hostsFile.getContent().splitlines()
  27. except BaseException:
  28. return results
  29. name = name.lower()
  30. for line in lines:
  31. idx = line.find(b"#")
  32. if idx != -1:
  33. line = line[:idx]
  34. if not line:
  35. continue
  36. parts = line.split()
  37. if name.lower() in [s.lower() for s in parts[1:]]:
  38. try:
  39. maybeIP = nativeString(parts[0])
  40. except ValueError: # Not ASCII.
  41. continue
  42. if isIPAddress(maybeIP) or isIPv6Address(maybeIP):
  43. results.append(maybeIP)
  44. return results
  45. def searchFileFor(file, name):
  46. """
  47. Grep given file, which is in hosts(5) standard format, for an address
  48. entry with a given name.
  49. @param file: The name of the hosts(5)-format file to search.
  50. @type file: C{str} or C{bytes}
  51. @param name: The name to search for.
  52. @type name: C{bytes}
  53. @return: L{None} if the name is not found in the file, otherwise a
  54. C{str} giving the first address in the file associated with
  55. the name.
  56. """
  57. addresses = searchFileForAll(FilePath(file), name)
  58. if addresses:
  59. return addresses[0]
  60. return None
  61. class Resolver(common.ResolverBase):
  62. """
  63. A resolver that services hosts(5) format files.
  64. """
  65. def __init__(self, file=b"/etc/hosts", ttl=60 * 60):
  66. common.ResolverBase.__init__(self)
  67. self.file = file
  68. self.ttl = ttl
  69. def _aRecords(self, name):
  70. """
  71. Return a tuple of L{dns.RRHeader} instances for all of the IPv4
  72. addresses in the hosts file.
  73. """
  74. return tuple(
  75. dns.RRHeader(name, dns.A, dns.IN, self.ttl, dns.Record_A(addr, self.ttl))
  76. for addr in searchFileForAll(FilePath(self.file), name)
  77. if isIPAddress(addr)
  78. )
  79. def _aaaaRecords(self, name):
  80. """
  81. Return a tuple of L{dns.RRHeader} instances for all of the IPv6
  82. addresses in the hosts file.
  83. """
  84. return tuple(
  85. dns.RRHeader(
  86. name, dns.AAAA, dns.IN, self.ttl, dns.Record_AAAA(addr, self.ttl)
  87. )
  88. for addr in searchFileForAll(FilePath(self.file), name)
  89. if isIPv6Address(addr)
  90. )
  91. def _respond(self, name, records):
  92. """
  93. Generate a response for the given name containing the given result
  94. records, or a failure if there are no result records.
  95. @param name: The DNS name the response is for.
  96. @type name: C{str}
  97. @param records: A tuple of L{dns.RRHeader} instances giving the results
  98. that will go into the response.
  99. @return: A L{Deferred} which will fire with a three-tuple of result
  100. records, authority records, and additional records, or which will
  101. fail with L{dns.DomainError} if there are no result records.
  102. """
  103. if records:
  104. return defer.succeed((records, (), ()))
  105. return defer.fail(failure.Failure(dns.DomainError(name)))
  106. def lookupAddress(self, name, timeout=None):
  107. """
  108. Read any IPv4 addresses from C{self.file} and return them as
  109. L{Record_A} instances.
  110. """
  111. name = dns.domainString(name)
  112. return self._respond(name, self._aRecords(name))
  113. def lookupIPV6Address(self, name, timeout=None):
  114. """
  115. Read any IPv6 addresses from C{self.file} and return them as
  116. L{Record_AAAA} instances.
  117. """
  118. name = dns.domainString(name)
  119. return self._respond(name, self._aaaaRecords(name))
  120. # Someday this should include IPv6 addresses too, but that will cause
  121. # problems if users of the API (mainly via getHostByName) aren't updated to
  122. # know about IPv6 first.
  123. # FIXME - getHostByName knows about IPv6 now.
  124. lookupAllRecords = lookupAddress