codekingpro/portable-devtools
114k
1# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license2 3# Copyright (C) 2003-2017 Nominum, Inc.4#5# Permission to use, copy, modify, and distribute this software and its6# documentation for any purpose with or without fee is hereby granted,7# provided that the above copyright notice and this permission notice8# appear in all copies.9#10# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES11# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF12# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR13# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES14# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN15# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT16# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.17 18"""DNS RRsets (an RRset is a named rdataset)"""19 20from typing import Any, Collection, Dict, Optional, Union, cast21 22import dns.name23import dns.rdataclass24import dns.rdataset25import dns.renderer26 27 28class RRset(dns.rdataset.Rdataset):29 """A DNS RRset (named rdataset).30 31 RRset inherits from Rdataset, and RRsets can be treated as32 Rdatasets in most cases. There are, however, a few notable33 exceptions. RRsets have different to_wire() and to_text() method34 arguments, reflecting the fact that RRsets always have an owner35 name.36 """37 38 __slots__ = ["name", "deleting"]39 40 def __init__(41 self,42 name: dns.name.Name,43 rdclass: dns.rdataclass.RdataClass,44 rdtype: dns.rdatatype.RdataType,45 covers: dns.rdatatype.RdataType = dns.rdatatype.NONE,46 deleting: Optional[dns.rdataclass.RdataClass] = None,47 ):48 """Create a new RRset."""49 50 super().__init__(rdclass, rdtype, covers)51 self.name = name52 self.deleting = deleting53 54 def _clone(self):55 obj = super()._clone()56 obj.name = self.name57 obj.deleting = self.deleting58 return obj59 60 def __repr__(self):61 if self.covers == 0:62 ctext = ""63 else:64 ctext = "(" + dns.rdatatype.to_text(self.covers) + ")"65 if self.deleting is not None:66 dtext = " delete=" + dns.rdataclass.to_text(self.deleting)67 else:68 dtext = ""69 return (70 "<DNS "71 + str(self.name)72 + " "73 + dns.rdataclass.to_text(self.rdclass)74 + " "75 + dns.rdatatype.to_text(self.rdtype)76 + ctext77 + dtext78 + " RRset: "79 + self._rdata_repr()80 + ">"81 )82 83 def __str__(self):84 return self.to_text()85 86 def __eq__(self, other):87 if isinstance(other, RRset):88 if self.name != other.name:89 return False90 elif not isinstance(other, dns.rdataset.Rdataset):91 return False92 return super().__eq__(other)93 94 def match(self, *args: Any, **kwargs: Any) -> bool: # type: ignore[override]95 """Does this rrset match the specified attributes?96 97 Behaves as :py:func:`full_match()` if the first argument is a98 ``dns.name.Name``, and as :py:func:`dns.rdataset.Rdataset.match()`99 otherwise.100 101 (This behavior fixes a design mistake where the signature of this102 method became incompatible with that of its superclass. The fix103 makes RRsets matchable as Rdatasets while preserving backwards104 compatibility.)105 """106 if isinstance(args[0], dns.name.Name):107 return self.full_match(*args, **kwargs) # type: ignore[arg-type]108 else:109 return super().match(*args, **kwargs) # type: ignore[arg-type]110 111 def full_match(112 self,113 name: dns.name.Name,114 rdclass: dns.rdataclass.RdataClass,115 rdtype: dns.rdatatype.RdataType,116 covers: dns.rdatatype.RdataType,117 deleting: Optional[dns.rdataclass.RdataClass] = None,118 ) -> bool:119 """Returns ``True`` if this rrset matches the specified name, class,120 type, covers, and deletion state.121 """122 if not super().match(rdclass, rdtype, covers):123 return False124 if self.name != name or self.deleting != deleting:125 return False126 return True127 128 # pylint: disable=arguments-differ129 130 def to_text( # type: ignore[override]131 self,132 origin: Optional[dns.name.Name] = None,133 relativize: bool = True,134 **kw: Dict[str, Any],135 ) -> str:136 """Convert the RRset into DNS zone file format.137 138 See ``dns.name.Name.choose_relativity`` for more information139 on how *origin* and *relativize* determine the way names140 are emitted.141 142 Any additional keyword arguments are passed on to the rdata143 ``to_text()`` method.144 145 *origin*, a ``dns.name.Name`` or ``None``, the origin for relative146 names.147 148 *relativize*, a ``bool``. If ``True``, names will be relativized149 to *origin*.150 """151 152 return super().to_text(153 self.name, origin, relativize, self.deleting, **kw # type: ignore154 )155 156 def to_wire( # type: ignore[override]157 self,158 file: Any,159 compress: Optional[dns.name.CompressType] = None, # type: ignore160 origin: Optional[dns.name.Name] = None,161 **kw: Dict[str, Any],162 ) -> int:163 """Convert the RRset to wire format.164 165 All keyword arguments are passed to ``dns.rdataset.to_wire()``; see166 that function for details.167 168 Returns an ``int``, the number of records emitted.169 """170 171 return super().to_wire(172 self.name, file, compress, origin, self.deleting, **kw # type:ignore173 )174 175 # pylint: enable=arguments-differ176 177 def to_rdataset(self) -> dns.rdataset.Rdataset:178 """Convert an RRset into an Rdataset.179 180 Returns a ``dns.rdataset.Rdataset``.181 """182 return dns.rdataset.from_rdata_list(self.ttl, list(self))183 184 185def from_text_list(186 name: Union[dns.name.Name, str],187 ttl: int,188 rdclass: Union[dns.rdataclass.RdataClass, str],189 rdtype: Union[dns.rdatatype.RdataType, str],190 text_rdatas: Collection[str],191 idna_codec: Optional[dns.name.IDNACodec] = None,192 origin: Optional[dns.name.Name] = None,193 relativize: bool = True,194 relativize_to: Optional[dns.name.Name] = None,195) -> RRset:196 """Create an RRset with the specified name, TTL, class, and type, and with197 the specified list of rdatas in text format.198 199 *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA200 encoder/decoder to use; if ``None``, the default IDNA 2003201 encoder/decoder is used.202 203 *origin*, a ``dns.name.Name`` (or ``None``), the204 origin to use for relative names.205 206 *relativize*, a ``bool``. If true, name will be relativized.207 208 *relativize_to*, a ``dns.name.Name`` (or ``None``), the origin to use209 when relativizing names. If not set, the *origin* value will be used.210 211 Returns a ``dns.rrset.RRset`` object.212 """213 214 if isinstance(name, str):215 name = dns.name.from_text(name, None, idna_codec=idna_codec)216 rdclass = dns.rdataclass.RdataClass.make(rdclass)217 rdtype = dns.rdatatype.RdataType.make(rdtype)218 r = RRset(name, rdclass, rdtype)219 r.update_ttl(ttl)220 for t in text_rdatas:221 rd = dns.rdata.from_text(222 r.rdclass, r.rdtype, t, origin, relativize, relativize_to, idna_codec223 )224 r.add(rd)225 return r226 227 228def from_text(229 name: Union[dns.name.Name, str],230 ttl: int,231 rdclass: Union[dns.rdataclass.RdataClass, str],232 rdtype: Union[dns.rdatatype.RdataType, str],233 *text_rdatas: Any,234) -> RRset:235 """Create an RRset with the specified name, TTL, class, and type and with236 the specified rdatas in text format.237 238 Returns a ``dns.rrset.RRset`` object.239 """240 241 return from_text_list(242 name, ttl, rdclass, rdtype, cast(Collection[str], text_rdatas)243 )244 245 246def from_rdata_list(247 name: Union[dns.name.Name, str],248 ttl: int,249 rdatas: Collection[dns.rdata.Rdata],250 idna_codec: Optional[dns.name.IDNACodec] = None,251) -> RRset:252 """Create an RRset with the specified name and TTL, and with253 the specified list of rdata objects.254 255 *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA256 encoder/decoder to use; if ``None``, the default IDNA 2003257 encoder/decoder is used.258 259 Returns a ``dns.rrset.RRset`` object.260 261 """262 263 if isinstance(name, str):264 name = dns.name.from_text(name, None, idna_codec=idna_codec)265 266 if len(rdatas) == 0:267 raise ValueError("rdata list must not be empty")268 r = None269 for rd in rdatas:270 if r is None:271 r = RRset(name, rd.rdclass, rd.rdtype)272 r.update_ttl(ttl)273 r.add(rd)274 assert r is not None275 return r276 277 278def from_rdata(name: Union[dns.name.Name, str], ttl: int, *rdatas: Any) -> RRset:279 """Create an RRset with the specified name and TTL, and with280 the specified rdata objects.281 282 Returns a ``dns.rrset.RRset`` object.283 """284 285 return from_rdata_list(name, ttl, cast(Collection[dns.rdata.Rdata], rdatas))286 