rrset.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. # Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
  2. #
  3. # Permission to use, copy, modify, and distribute this software and its
  4. # documentation for any purpose with or without fee is hereby granted,
  5. # provided that the above copyright notice and this permission notice
  6. # appear in all copies.
  7. #
  8. # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
  9. # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
  11. # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  14. # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. """DNS RRsets (an RRset is a named rdataset)"""
  16. import dns.name
  17. import dns.rdataset
  18. import dns.rdataclass
  19. import dns.renderer
  20. from ._compat import string_types
  21. class RRset(dns.rdataset.Rdataset):
  22. """A DNS RRset (named rdataset).
  23. RRset inherits from Rdataset, and RRsets can be treated as
  24. Rdatasets in most cases. There are, however, a few notable
  25. exceptions. RRsets have different to_wire() and to_text() method
  26. arguments, reflecting the fact that RRsets always have an owner
  27. name.
  28. """
  29. __slots__ = ['name', 'deleting']
  30. def __init__(self, name, rdclass, rdtype, covers=dns.rdatatype.NONE,
  31. deleting=None):
  32. """Create a new RRset."""
  33. super(RRset, self).__init__(rdclass, rdtype, covers)
  34. self.name = name
  35. self.deleting = deleting
  36. def _clone(self):
  37. obj = super(RRset, self)._clone()
  38. obj.name = self.name
  39. obj.deleting = self.deleting
  40. return obj
  41. def __repr__(self):
  42. if self.covers == 0:
  43. ctext = ''
  44. else:
  45. ctext = '(' + dns.rdatatype.to_text(self.covers) + ')'
  46. if self.deleting is not None:
  47. dtext = ' delete=' + dns.rdataclass.to_text(self.deleting)
  48. else:
  49. dtext = ''
  50. return '<DNS ' + str(self.name) + ' ' + \
  51. dns.rdataclass.to_text(self.rdclass) + ' ' + \
  52. dns.rdatatype.to_text(self.rdtype) + ctext + dtext + ' RRset>'
  53. def __str__(self):
  54. return self.to_text()
  55. def __eq__(self, other):
  56. """Two RRsets are equal if they have the same name and the same
  57. rdataset
  58. @rtype: bool"""
  59. if not isinstance(other, RRset):
  60. return False
  61. if self.name != other.name:
  62. return False
  63. return super(RRset, self).__eq__(other)
  64. def match(self, name, rdclass, rdtype, covers, deleting=None):
  65. """Returns True if this rrset matches the specified class, type,
  66. covers, and deletion state."""
  67. if not super(RRset, self).match(rdclass, rdtype, covers):
  68. return False
  69. if self.name != name or self.deleting != deleting:
  70. return False
  71. return True
  72. def to_text(self, origin=None, relativize=True, **kw):
  73. """Convert the RRset into DNS master file format.
  74. @see: L{dns.name.Name.choose_relativity} for more information
  75. on how I{origin} and I{relativize} determine the way names
  76. are emitted.
  77. Any additional keyword arguments are passed on to the rdata
  78. to_text() method.
  79. @param origin: The origin for relative names, or None.
  80. @type origin: dns.name.Name object
  81. @param relativize: True if names should names be relativized
  82. @type relativize: bool"""
  83. return super(RRset, self).to_text(self.name, origin, relativize,
  84. self.deleting, **kw)
  85. def to_wire(self, file, compress=None, origin=None, **kw):
  86. """Convert the RRset to wire format."""
  87. return super(RRset, self).to_wire(self.name, file, compress, origin,
  88. self.deleting, **kw)
  89. def to_rdataset(self):
  90. """Convert an RRset into an Rdataset.
  91. @rtype: dns.rdataset.Rdataset object
  92. """
  93. return dns.rdataset.from_rdata_list(self.ttl, list(self))
  94. def from_text_list(name, ttl, rdclass, rdtype, text_rdatas,
  95. idna_codec=None):
  96. """Create an RRset with the specified name, TTL, class, and type, and with
  97. the specified list of rdatas in text format.
  98. @rtype: dns.rrset.RRset object
  99. """
  100. if isinstance(name, string_types):
  101. name = dns.name.from_text(name, None, idna_codec=idna_codec)
  102. if isinstance(rdclass, string_types):
  103. rdclass = dns.rdataclass.from_text(rdclass)
  104. if isinstance(rdtype, string_types):
  105. rdtype = dns.rdatatype.from_text(rdtype)
  106. r = RRset(name, rdclass, rdtype)
  107. r.update_ttl(ttl)
  108. for t in text_rdatas:
  109. rd = dns.rdata.from_text(r.rdclass, r.rdtype, t)
  110. r.add(rd)
  111. return r
  112. def from_text(name, ttl, rdclass, rdtype, *text_rdatas):
  113. """Create an RRset with the specified name, TTL, class, and type and with
  114. the specified rdatas in text format.
  115. @rtype: dns.rrset.RRset object
  116. """
  117. return from_text_list(name, ttl, rdclass, rdtype, text_rdatas)
  118. def from_rdata_list(name, ttl, rdatas, idna_codec=None):
  119. """Create an RRset with the specified name and TTL, and with
  120. the specified list of rdata objects.
  121. @rtype: dns.rrset.RRset object
  122. """
  123. if isinstance(name, string_types):
  124. name = dns.name.from_text(name, None, idna_codec=idna_codec)
  125. if len(rdatas) == 0:
  126. raise ValueError("rdata list must not be empty")
  127. r = None
  128. for rd in rdatas:
  129. if r is None:
  130. r = RRset(name, rd.rdclass, rd.rdtype)
  131. r.update_ttl(ttl)
  132. r.add(rd)
  133. return r
  134. def from_rdata(name, ttl, *rdatas):
  135. """Create an RRset with the specified name and TTL, and with
  136. the specified rdata objects.
  137. @rtype: dns.rrset.RRset object
  138. """
  139. return from_rdata_list(name, ttl, rdatas)