????JFIF??x?x????'
| Server IP : 104.21.30.238  /  Your IP : 216.73.216.145 Web Server : LiteSpeed System : Linux premium151.web-hosting.com 4.18.0-553.44.1.lve.el8.x86_64 #1 SMP Thu Mar 13 14:29:12 UTC 2025 x86_64 User : tempvsty ( 647) PHP Version : 8.0.30 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /././proc/self/root/proc/thread-self/root/opt/hc_python/lib64/python3.12/site-packages/dns/ | 
| Upload File : | 
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
# Copyright (C) 2001-2017 Nominum, Inc.
#
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose with or without fee is hereby granted,
# provided that the above copyright notice and this permission notice
# appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""DNS nodes.  A node is a set of rdatasets."""
import enum
import io
from typing import Any, Dict, Optional
import dns.immutable
import dns.name
import dns.rdataclass
import dns.rdataset
import dns.rdatatype
import dns.renderer
import dns.rrset
_cname_types = {
    dns.rdatatype.CNAME,
}
# "neutral" types can coexist with a CNAME and thus are not "other data"
_neutral_types = {
    dns.rdatatype.NSEC,  # RFC 4035 section 2.5
    dns.rdatatype.NSEC3,  # This is not likely to happen, but not impossible!
    dns.rdatatype.KEY,  # RFC 4035 section 2.5, RFC 3007
}
def _matches_type_or_its_signature(rdtypes, rdtype, covers):
    return rdtype in rdtypes or (rdtype == dns.rdatatype.RRSIG and covers in rdtypes)
@enum.unique
class NodeKind(enum.Enum):
    """Rdatasets in nodes"""
    REGULAR = 0  # a.k.a "other data"
    NEUTRAL = 1
    CNAME = 2
    @classmethod
    def classify(
        cls, rdtype: dns.rdatatype.RdataType, covers: dns.rdatatype.RdataType
    ) -> "NodeKind":
        if _matches_type_or_its_signature(_cname_types, rdtype, covers):
            return NodeKind.CNAME
        elif _matches_type_or_its_signature(_neutral_types, rdtype, covers):
            return NodeKind.NEUTRAL
        else:
            return NodeKind.REGULAR
    @classmethod
    def classify_rdataset(cls, rdataset: dns.rdataset.Rdataset) -> "NodeKind":
        return cls.classify(rdataset.rdtype, rdataset.covers)
class Node:
    """A Node is a set of rdatasets.
    A node is either a CNAME node or an "other data" node.  A CNAME
    node contains only CNAME, KEY, NSEC, and NSEC3 rdatasets along with their
    covering RRSIG rdatasets.  An "other data" node contains any
    rdataset other than a CNAME or RRSIG(CNAME) rdataset.  When
    changes are made to a node, the CNAME or "other data" state is
    always consistent with the update, i.e. the most recent change
    wins.  For example, if you have a node which contains a CNAME
    rdataset, and then add an MX rdataset to it, then the CNAME
    rdataset will be deleted.  Likewise if you have a node containing
    an MX rdataset and add a CNAME rdataset, the MX rdataset will be
    deleted.
    """
    __slots__ = ["rdatasets"]
    def __init__(self):
        # the set of rdatasets, represented as a list.
        self.rdatasets = []
    def to_text(self, name: dns.name.Name, **kw: Dict[str, Any]) -> str:
        """Convert a node to text format.
        Each rdataset at the node is printed.  Any keyword arguments
        to this method are passed on to the rdataset's to_text() method.
        *name*, a ``dns.name.Name``, the owner name of the
        rdatasets.
        Returns a ``str``.
        """
        s = io.StringIO()
        for rds in self.rdatasets:
            if len(rds) > 0:
                s.write(rds.to_text(name, **kw))  # type: ignore[arg-type]
                s.write("\n")
        return s.getvalue()[:-1]
    def __repr__(self):
        return "<DNS node " + str(id(self)) + ">"
    def __eq__(self, other):
        #
        # This is inefficient.  Good thing we don't need to do it much.
        #
        for rd in self.rdatasets:
            if rd not in other.rdatasets:
                return False
        for rd in other.rdatasets:
            if rd not in self.rdatasets:
                return False
        return True
    def __ne__(self, other):
        return not self.__eq__(other)
    def __len__(self):
        return len(self.rdatasets)
    def __iter__(self):
        return iter(self.rdatasets)
    def _append_rdataset(self, rdataset):
        """Append rdataset to the node with special handling for CNAME and
        other data conditions.
        Specifically, if the rdataset being appended has ``NodeKind.CNAME``,
        then all rdatasets other than KEY, NSEC, NSEC3, and their covering
        RRSIGs are deleted.  If the rdataset being appended has
        ``NodeKind.REGULAR`` then CNAME and RRSIG(CNAME) are deleted.
        """
        # Make having just one rdataset at the node fast.
        if len(self.rdatasets) > 0:
            kind = NodeKind.classify_rdataset(rdataset)
            if kind == NodeKind.CNAME:
                self.rdatasets = [
                    rds
                    for rds in self.rdatasets
                    if NodeKind.classify_rdataset(rds) != NodeKind.REGULAR
                ]
            elif kind == NodeKind.REGULAR:
                self.rdatasets = [
                    rds
                    for rds in self.rdatasets
                    if NodeKind.classify_rdataset(rds) != NodeKind.CNAME
                ]
            # Otherwise the rdataset is NodeKind.NEUTRAL and we do not need to
            # edit self.rdatasets.
        self.rdatasets.append(rdataset)
    def find_rdataset(
        self,
        rdclass: dns.rdataclass.RdataClass,
        rdtype: dns.rdatatype.RdataType,
        covers: dns.rdatatype.RdataType = dns.rdatatype.NONE,
        create: bool = False,
    ) -> dns.rdataset.Rdataset:
        """Find an rdataset matching the specified properties in the
        current node.
        *rdclass*, a ``dns.rdataclass.RdataClass``, the class of the rdataset.
        *rdtype*, a ``dns.rdatatype.RdataType``, the type of the rdataset.
        *covers*, a ``dns.rdatatype.RdataType``, the covered type.
        Usually this value is ``dns.rdatatype.NONE``, but if the
        rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``,
        then the covers value will be the rdata type the SIG/RRSIG
        covers.  The library treats the SIG and RRSIG types as if they
        were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA).
        This makes RRSIGs much easier to work with than if RRSIGs
        covering different rdata types were aggregated into a single
        RRSIG rdataset.
        *create*, a ``bool``.  If True, create the rdataset if it is not found.
        Raises ``KeyError`` if an rdataset of the desired type and class does
        not exist and *create* is not ``True``.
        Returns a ``dns.rdataset.Rdataset``.
        """
        for rds in self.rdatasets:
            if rds.match(rdclass, rdtype, covers):
                return rds
        if not create:
            raise KeyError
        rds = dns.rdataset.Rdataset(rdclass, rdtype, covers)
        self._append_rdataset(rds)
        return rds
    def get_rdataset(
        self,
        rdclass: dns.rdataclass.RdataClass,
        rdtype: dns.rdatatype.RdataType,
        covers: dns.rdatatype.RdataType = dns.rdatatype.NONE,
        create: bool = False,
    ) -> Optional[dns.rdataset.Rdataset]:
        """Get an rdataset matching the specified properties in the
        current node.
        None is returned if an rdataset of the specified type and
        class does not exist and *create* is not ``True``.
        *rdclass*, an ``int``, the class of the rdataset.
        *rdtype*, an ``int``, the type of the rdataset.
        *covers*, an ``int``, the covered type.  Usually this value is
        dns.rdatatype.NONE, but if the rdtype is dns.rdatatype.SIG or
        dns.rdatatype.RRSIG, then the covers value will be the rdata
        type the SIG/RRSIG covers.  The library treats the SIG and RRSIG
        types as if they were a family of
        types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA).  This makes RRSIGs much
        easier to work with than if RRSIGs covering different rdata
        types were aggregated into a single RRSIG rdataset.
        *create*, a ``bool``.  If True, create the rdataset if it is not found.
        Returns a ``dns.rdataset.Rdataset`` or ``None``.
        """
        try:
            rds = self.find_rdataset(rdclass, rdtype, covers, create)
        except KeyError:
            rds = None
        return rds
    def delete_rdataset(
        self,
        rdclass: dns.rdataclass.RdataClass,
        rdtype: dns.rdatatype.RdataType,
        covers: dns.rdatatype.RdataType = dns.rdatatype.NONE,
    ) -> None:
        """Delete the rdataset matching the specified properties in the
        current node.
        If a matching rdataset does not exist, it is not an error.
        *rdclass*, an ``int``, the class of the rdataset.
        *rdtype*, an ``int``, the type of the rdataset.
        *covers*, an ``int``, the covered type.
        """
        rds = self.get_rdataset(rdclass, rdtype, covers)
        if rds is not None:
            self.rdatasets.remove(rds)
    def replace_rdataset(self, replacement: dns.rdataset.Rdataset) -> None:
        """Replace an rdataset.
        It is not an error if there is no rdataset matching *replacement*.
        Ownership of the *replacement* object is transferred to the node;
        in other words, this method does not store a copy of *replacement*
        at the node, it stores *replacement* itself.
        *replacement*, a ``dns.rdataset.Rdataset``.
        Raises ``ValueError`` if *replacement* is not a
        ``dns.rdataset.Rdataset``.
        """
        if not isinstance(replacement, dns.rdataset.Rdataset):
            raise ValueError("replacement is not an rdataset")
        if isinstance(replacement, dns.rrset.RRset):
            # RRsets are not good replacements as the match() method
            # is not compatible.
            replacement = replacement.to_rdataset()
        self.delete_rdataset(
            replacement.rdclass, replacement.rdtype, replacement.covers
        )
        self._append_rdataset(replacement)
    def classify(self) -> NodeKind:
        """Classify a node.
        A node which contains a CNAME or RRSIG(CNAME) is a
        ``NodeKind.CNAME`` node.
        A node which contains only "neutral" types, i.e. types allowed to
        co-exist with a CNAME, is a ``NodeKind.NEUTRAL`` node.  The neutral
        types are NSEC, NSEC3, KEY, and their associated RRSIGS.  An empty node
        is also considered neutral.
        A node which contains some rdataset which is not a CNAME, RRSIG(CNAME),
        or a neutral type is a a ``NodeKind.REGULAR`` node.  Regular nodes are
        also commonly referred to as "other data".
        """
        for rdataset in self.rdatasets:
            kind = NodeKind.classify(rdataset.rdtype, rdataset.covers)
            if kind != NodeKind.NEUTRAL:
                return kind
        return NodeKind.NEUTRAL
    def is_immutable(self) -> bool:
        return False
@dns.immutable.immutable
class ImmutableNode(Node):
    def __init__(self, node):
        super().__init__()
        self.rdatasets = tuple(
            [dns.rdataset.ImmutableRdataset(rds) for rds in node.rdatasets]
        )
    def find_rdataset(
        self,
        rdclass: dns.rdataclass.RdataClass,
        rdtype: dns.rdatatype.RdataType,
        covers: dns.rdatatype.RdataType = dns.rdatatype.NONE,
        create: bool = False,
    ) -> dns.rdataset.Rdataset:
        if create:
            raise TypeError("immutable")
        return super().find_rdataset(rdclass, rdtype, covers, False)
    def get_rdataset(
        self,
        rdclass: dns.rdataclass.RdataClass,
        rdtype: dns.rdatatype.RdataType,
        covers: dns.rdatatype.RdataType = dns.rdatatype.NONE,
        create: bool = False,
    ) -> Optional[dns.rdataset.Rdataset]:
        if create:
            raise TypeError("immutable")
        return super().get_rdataset(rdclass, rdtype, covers, False)
    def delete_rdataset(
        self,
        rdclass: dns.rdataclass.RdataClass,
        rdtype: dns.rdatatype.RdataType,
        covers: dns.rdatatype.RdataType = dns.rdatatype.NONE,
    ) -> None:
        raise TypeError("immutable")
    def replace_rdataset(self, replacement: dns.rdataset.Rdataset) -> None:
        raise TypeError("immutable")
    def is_immutable(self) -> bool:
        return True