133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# Copyright (C) 2001-2007, 2009, 2010 Nominum, Inc.
233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck#
333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# Permission to use, copy, modify, and distribute this software and its
433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# documentation for any purpose with or without fee is hereby granted,
533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# provided that the above copyright notice and this permission notice
633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# appear in all copies.
733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck#
833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
1133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
1433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
1633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck"""DNS Names.
1733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
1833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck@var root: The DNS root name.
1933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck@type root: dns.name.Name object
2033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck@var empty: The empty DNS name.
2133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck@type empty: dns.name.Name object
2233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck"""
2333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
2433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport cStringIO
2533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport struct
2633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport sys
2733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
2833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckif sys.hexversion >= 0x02030000:
2933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    import encodings.idna
3033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
3133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport dns.exception
3233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
3333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John ReckNAMERELN_NONE = 0
3433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John ReckNAMERELN_SUPERDOMAIN = 1
3533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John ReckNAMERELN_SUBDOMAIN = 2
3633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John ReckNAMERELN_EQUAL = 3
3733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John ReckNAMERELN_COMMONANCESTOR = 4
3833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
3933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass EmptyLabel(dns.exception.SyntaxError):
4033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """Raised if a label is empty."""
4133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    pass
4233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
4333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass BadEscape(dns.exception.SyntaxError):
4433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """Raised if an escaped code in a text format name is invalid."""
4533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    pass
4633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
4733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass BadPointer(dns.exception.FormError):
4833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """Raised if a compression pointer points forward instead of backward."""
4933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    pass
5033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
5133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass BadLabelType(dns.exception.FormError):
5233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """Raised if the label type of a wire format name is unknown."""
5333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    pass
5433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
5533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass NeedAbsoluteNameOrOrigin(dns.exception.DNSException):
5633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """Raised if an attempt is made to convert a non-absolute name to
5733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    wire when there is also a non-absolute (or missing) origin."""
5833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    pass
5933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
6033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass NameTooLong(dns.exception.FormError):
6133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """Raised if a name is > 255 octets long."""
6233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    pass
6333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
6433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass LabelTooLong(dns.exception.SyntaxError):
6533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """Raised if a label is > 63 octets long."""
6633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    pass
6733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
6833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass AbsoluteConcatenation(dns.exception.DNSException):
6933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """Raised if an attempt is made to append anything other than the
7033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    empty name to an absolute name."""
7133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    pass
7233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
7333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass NoParent(dns.exception.DNSException):
7433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """Raised if an attempt is made to get the parent of the root name
7533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    or the empty name."""
7633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    pass
7733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
7833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck_escaped = {
7933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    '"' : True,
8033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    '(' : True,
8133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    ')' : True,
8233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    '.' : True,
8333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    ';' : True,
8433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    '\\' : True,
8533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    '@' : True,
8633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    '$' : True
8733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    }
8833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
8933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef _escapify(label):
9033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """Escape the characters in label which need it.
9133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @returns: the escaped string
9233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @rtype: string"""
9333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    text = ''
9433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    for c in label:
9533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if c in _escaped:
9633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            text += '\\' + c
9733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        elif ord(c) > 0x20 and ord(c) < 0x7F:
9833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            text += c
9933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
10033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            text += '\\%03d' % ord(c)
10133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    return text
10233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
10333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef _validate_labels(labels):
10433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """Check for empty labels in the middle of a label sequence,
10533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    labels that are too long, and for too many labels.
10633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @raises NameTooLong: the name as a whole is too long
10733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @raises LabelTooLong: an individual label is too long
10833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @raises EmptyLabel: a label is empty (i.e. the root label) and appears
10933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    in a position other than the end of the label sequence"""
11033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
11133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    l = len(labels)
11233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    total = 0
11333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    i = -1
11433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    j = 0
11533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    for label in labels:
11633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        ll = len(label)
11733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        total += ll + 1
11833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if ll > 63:
11933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            raise LabelTooLong
12033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if i < 0 and label == '':
12133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            i = j
12233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        j += 1
12333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if total > 255:
12433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        raise NameTooLong
12533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if i >= 0 and i != l - 1:
12633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        raise EmptyLabel
12733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
12833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass Name(object):
12933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """A DNS name.
13033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
13133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    The dns.name.Name class represents a DNS name as a tuple of labels.
13233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    Instances of the class are immutable.
13333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
13433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @ivar labels: The tuple of labels in the name. Each label is a string of
13533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    up to 63 octets."""
13633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
13733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    __slots__ = ['labels']
13833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
13933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __init__(self, labels):
14033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Initialize a domain name from a list of labels.
14133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @param labels: the labels
14233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @type labels: any iterable whose values are strings
14333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """
14433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
14533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        super(Name, self).__setattr__('labels', tuple(labels))
14633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        _validate_labels(self.labels)
14733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
14833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __setattr__(self, name, value):
14933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        raise TypeError("object doesn't support attribute assignment")
15033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
15133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def is_absolute(self):
15233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Is the most significant label of this name the root label?
15333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @rtype: bool
15433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """
15533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
15633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return len(self.labels) > 0 and self.labels[-1] == ''
15733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
15833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def is_wild(self):
15933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Is this name wild?  (I.e. Is the least significant label '*'?)
16033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @rtype: bool
16133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """
16233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
16333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return len(self.labels) > 0 and self.labels[0] == '*'
16433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
16533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __hash__(self):
16633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Return a case-insensitive hash of the name.
16733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @rtype: int
16833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """
16933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
17033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        h = 0L
17133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        for label in self.labels:
17233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            for c in label:
17333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                h += ( h << 3 ) + ord(c.lower())
17433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return int(h % sys.maxint)
17533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
17633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def fullcompare(self, other):
17733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Compare two names, returning a 3-tuple (relation, order, nlabels).
17833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
17933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        I{relation} describes the relation ship between the names,
18033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        and is one of: dns.name.NAMERELN_NONE,
18133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        dns.name.NAMERELN_SUPERDOMAIN, dns.name.NAMERELN_SUBDOMAIN,
18233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        dns.name.NAMERELN_EQUAL, or dns.name.NAMERELN_COMMONANCESTOR
18333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
18433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        I{order} is < 0 if self < other, > 0 if self > other, and ==
18533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        0 if self == other.  A relative name is always less than an
18633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        absolute name.  If both names have the same relativity, then
18733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        the DNSSEC order relation is used to order them.
18833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
18933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        I{nlabels} is the number of significant labels that the two names
19033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        have in common.
19133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """
19233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
19333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        sabs = self.is_absolute()
19433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        oabs = other.is_absolute()
19533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if sabs != oabs:
19633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if sabs:
19733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                return (NAMERELN_NONE, 1, 0)
19833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            else:
19933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                return (NAMERELN_NONE, -1, 0)
20033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        l1 = len(self.labels)
20133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        l2 = len(other.labels)
20233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        ldiff = l1 - l2
20333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if ldiff < 0:
20433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            l = l1
20533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
20633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            l = l2
20733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
20833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        order = 0
20933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        nlabels = 0
21033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        namereln = NAMERELN_NONE
21133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        while l > 0:
21233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            l -= 1
21333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            l1 -= 1
21433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            l2 -= 1
21533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            label1 = self.labels[l1].lower()
21633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            label2 = other.labels[l2].lower()
21733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if label1 < label2:
21833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                order = -1
21933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                if nlabels > 0:
22033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    namereln = NAMERELN_COMMONANCESTOR
22133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                return (namereln, order, nlabels)
22233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            elif label1 > label2:
22333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                order = 1
22433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                if nlabels > 0:
22533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    namereln = NAMERELN_COMMONANCESTOR
22633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                return (namereln, order, nlabels)
22733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            nlabels += 1
22833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        order = ldiff
22933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if ldiff < 0:
23033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            namereln = NAMERELN_SUPERDOMAIN
23133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        elif ldiff > 0:
23233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            namereln = NAMERELN_SUBDOMAIN
23333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
23433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            namereln = NAMERELN_EQUAL
23533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return (namereln, order, nlabels)
23633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
23733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def is_subdomain(self, other):
23833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Is self a subdomain of other?
23933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
24033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        The notion of subdomain includes equality.
24133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @rtype: bool
24233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """
24333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
24433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        (nr, o, nl) = self.fullcompare(other)
24533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if nr == NAMERELN_SUBDOMAIN or nr == NAMERELN_EQUAL:
24633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return True
24733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return False
24833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
24933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def is_superdomain(self, other):
25033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Is self a superdomain of other?
25133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
25233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        The notion of subdomain includes equality.
25333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @rtype: bool
25433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """
25533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
25633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        (nr, o, nl) = self.fullcompare(other)
25733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if nr == NAMERELN_SUPERDOMAIN or nr == NAMERELN_EQUAL:
25833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return True
25933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return False
26033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
26133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def canonicalize(self):
26233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Return a name which is equal to the current name, but is in
26333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        DNSSEC canonical form.
26433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @rtype: dns.name.Name object
26533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """
26633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
26733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return Name([x.lower() for x in self.labels])
26833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
26933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __eq__(self, other):
27033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if isinstance(other, Name):
27133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return self.fullcompare(other)[1] == 0
27233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
27333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return False
27433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
27533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __ne__(self, other):
27633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if isinstance(other, Name):
27733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return self.fullcompare(other)[1] != 0
27833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
27933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return True
28033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
28133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __lt__(self, other):
28233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if isinstance(other, Name):
28333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return self.fullcompare(other)[1] < 0
28433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
28533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return NotImplemented
28633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
28733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __le__(self, other):
28833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if isinstance(other, Name):
28933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return self.fullcompare(other)[1] <= 0
29033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
29133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return NotImplemented
29233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
29333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __ge__(self, other):
29433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if isinstance(other, Name):
29533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return self.fullcompare(other)[1] >= 0
29633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
29733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return NotImplemented
29833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
29933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __gt__(self, other):
30033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if isinstance(other, Name):
30133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return self.fullcompare(other)[1] > 0
30233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
30333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return NotImplemented
30433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
30533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __repr__(self):
30633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return '<DNS name ' + self.__str__() + '>'
30733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
30833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __str__(self):
30933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return self.to_text(False)
31033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
31133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def to_text(self, omit_final_dot = False):
31233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Convert name to text format.
31333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @param omit_final_dot: If True, don't emit the final dot (denoting the
31433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        root label) for absolute names.  The default is False.
31533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @rtype: string
31633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """
31733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
31833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if len(self.labels) == 0:
31933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return '@'
32033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if len(self.labels) == 1 and self.labels[0] == '':
32133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return '.'
32233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if omit_final_dot and self.is_absolute():
32333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            l = self.labels[:-1]
32433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
32533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            l = self.labels
32633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        s = '.'.join(map(_escapify, l))
32733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return s
32833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
32933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def to_unicode(self, omit_final_dot = False):
33033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Convert name to Unicode text format.
33133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
33233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        IDN ACE lables are converted to Unicode.
33333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
33433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @param omit_final_dot: If True, don't emit the final dot (denoting the
33533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        root label) for absolute names.  The default is False.
33633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @rtype: string
33733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """
33833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
33933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if len(self.labels) == 0:
34033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return u'@'
34133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if len(self.labels) == 1 and self.labels[0] == '':
34233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return u'.'
34333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if omit_final_dot and self.is_absolute():
34433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            l = self.labels[:-1]
34533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
34633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            l = self.labels
34733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        s = u'.'.join([encodings.idna.ToUnicode(_escapify(x)) for x in l])
34833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return s
34933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
35033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def to_digestable(self, origin=None):
35133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Convert name to a format suitable for digesting in hashes.
35233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
35333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        The name is canonicalized and converted to uncompressed wire format.
35433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
35533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @param origin: If the name is relative and origin is not None, then
35633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        origin will be appended to it.
35733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @type origin: dns.name.Name object
35833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @raises NeedAbsoluteNameOrOrigin: All names in wire format are
35933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        absolute.  If self is a relative name, then an origin must be supplied;
36033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if it is missing, then this exception is raised
36133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @rtype: string
36233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """
36333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
36433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if not self.is_absolute():
36533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if origin is None or not origin.is_absolute():
36633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                raise NeedAbsoluteNameOrOrigin
36733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            labels = list(self.labels)
36833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            labels.extend(list(origin.labels))
36933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
37033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            labels = self.labels
37133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        dlabels = ["%s%s" % (chr(len(x)), x.lower()) for x in labels]
37233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return ''.join(dlabels)
37333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
37433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def to_wire(self, file = None, compress = None, origin = None):
37533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Convert name to wire format, possibly compressing it.
37633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
37733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @param file: the file where the name is emitted (typically
37833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        a cStringIO file).  If None, a string containing the wire name
37933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        will be returned.
38033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @type file: file or None
38133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @param compress: The compression table.  If None (the default) names
38233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        will not be compressed.
38333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @type compress: dict
38433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @param origin: If the name is relative and origin is not None, then
38533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        origin will be appended to it.
38633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @type origin: dns.name.Name object
38733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @raises NeedAbsoluteNameOrOrigin: All names in wire format are
38833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        absolute.  If self is a relative name, then an origin must be supplied;
38933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if it is missing, then this exception is raised
39033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """
39133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
39233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if file is None:
39333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            file = cStringIO.StringIO()
39433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            want_return = True
39533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
39633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            want_return = False
39733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
39833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if not self.is_absolute():
39933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if origin is None or not origin.is_absolute():
40033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                raise NeedAbsoluteNameOrOrigin
40133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            labels = list(self.labels)
40233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            labels.extend(list(origin.labels))
40333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
40433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            labels = self.labels
40533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        i = 0
40633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        for label in labels:
40733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            n = Name(labels[i:])
40833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            i += 1
40933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if not compress is None:
41033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                pos = compress.get(n)
41133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            else:
41233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                pos = None
41333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if not pos is None:
41433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                value = 0xc000 + pos
41533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                s = struct.pack('!H', value)
41633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                file.write(s)
41733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                break
41833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            else:
41933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                if not compress is None and len(n) > 1:
42033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    pos = file.tell()
42133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    if pos < 0xc000:
42233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                        compress[n] = pos
42333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                l = len(label)
42433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                file.write(chr(l))
42533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                if l > 0:
42633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    file.write(label)
42733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if want_return:
42833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return file.getvalue()
42933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
43033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __len__(self):
43133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """The length of the name (in labels).
43233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @rtype: int
43333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """
43433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
43533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return len(self.labels)
43633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
43733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __getitem__(self, index):
43833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return self.labels[index]
43933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
44033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __getslice__(self, start, stop):
44133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return self.labels[start:stop]
44233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
44333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __add__(self, other):
44433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return self.concatenate(other)
44533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
44633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __sub__(self, other):
44733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return self.relativize(other)
44833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
44933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def split(self, depth):
45033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Split a name into a prefix and suffix at depth.
45133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
45233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @param depth: the number of labels in the suffix
45333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @type depth: int
45433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @raises ValueError: the depth was not >= 0 and <= the length of the
45533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        name.
45633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @returns: the tuple (prefix, suffix)
45733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @rtype: tuple
45833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """
45933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
46033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        l = len(self.labels)
46133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if depth == 0:
46233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return (self, dns.name.empty)
46333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        elif depth == l:
46433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return (dns.name.empty, self)
46533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        elif depth < 0 or depth > l:
46633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            raise ValueError('depth must be >= 0 and <= the length of the name')
46733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return (Name(self[: -depth]), Name(self[-depth :]))
46833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
46933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def concatenate(self, other):
47033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Return a new name which is the concatenation of self and other.
47133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @rtype: dns.name.Name object
47233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @raises AbsoluteConcatenation: self is absolute and other is
47333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        not the empty name
47433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """
47533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
47633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if self.is_absolute() and len(other) > 0:
47733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            raise AbsoluteConcatenation
47833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        labels = list(self.labels)
47933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        labels.extend(list(other.labels))
48033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return Name(labels)
48133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
48233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def relativize(self, origin):
48333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """If self is a subdomain of origin, return a new name which is self
48433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        relative to origin.  Otherwise return self.
48533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @rtype: dns.name.Name object
48633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """
48733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
48833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if not origin is None and self.is_subdomain(origin):
48933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return Name(self[: -len(origin)])
49033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
49133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return self
49233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
49333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def derelativize(self, origin):
49433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """If self is a relative name, return a new name which is the
49533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        concatenation of self and origin.  Otherwise return self.
49633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @rtype: dns.name.Name object
49733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """
49833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
49933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if not self.is_absolute():
50033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return self.concatenate(origin)
50133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
50233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return self
50333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
50433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def choose_relativity(self, origin=None, relativize=True):
50533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Return a name with the relativity desired by the caller.  If
50633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        origin is None, then self is returned.  Otherwise, if
50733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        relativize is true the name is relativized, and if relativize is
50833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        false the name is derelativized.
50933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @rtype: dns.name.Name object
51033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """
51133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
51233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if origin:
51333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if relativize:
51433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                return self.relativize(origin)
51533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            else:
51633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                return self.derelativize(origin)
51733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
51833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return self
51933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
52033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def parent(self):
52133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """Return the parent of the name.
52233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @rtype: dns.name.Name object
52333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        @raises NoParent: the name is either the root name or the empty name,
52433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        and thus has no parent.
52533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        """
52633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if self == root or self == empty:
52733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            raise NoParent
52833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return Name(self.labels[1:])
52933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
53033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckroot = Name([''])
53133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckempty = Name([])
53233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
53333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef from_unicode(text, origin = root):
53433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """Convert unicode text into a Name object.
53533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
53633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    Lables are encoded in IDN ACE form.
53733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
53833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @rtype: dns.name.Name object
53933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """
54033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
54133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if not isinstance(text, unicode):
54233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        raise ValueError("input to from_unicode() must be a unicode string")
54333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if not (origin is None or isinstance(origin, Name)):
54433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        raise ValueError("origin must be a Name or None")
54533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    labels = []
54633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    label = u''
54733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    escaping = False
54833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    edigits = 0
54933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    total = 0
55033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if text == u'@':
55133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        text = u''
55233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if text:
55333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if text == u'.':
55433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return Name([''])	# no Unicode "u" on this constant!
55533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        for c in text:
55633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if escaping:
55733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                if edigits == 0:
55833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    if c.isdigit():
55933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                        total = int(c)
56033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                        edigits += 1
56133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    else:
56233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                        label += c
56333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                        escaping = False
56433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                else:
56533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    if not c.isdigit():
56633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                        raise BadEscape
56733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    total *= 10
56833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    total += int(c)
56933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    edigits += 1
57033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    if edigits == 3:
57133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                        escaping = False
57233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                        label += chr(total)
57333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            elif c == u'.' or c == u'\u3002' or \
57433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                 c == u'\uff0e' or c == u'\uff61':
57533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                if len(label) == 0:
57633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    raise EmptyLabel
57733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                labels.append(encodings.idna.ToASCII(label))
57833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                label = u''
57933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            elif c == u'\\':
58033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                escaping = True
58133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                edigits = 0
58233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                total = 0
58333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            else:
58433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                label += c
58533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if escaping:
58633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            raise BadEscape
58733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if len(label) > 0:
58833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            labels.append(encodings.idna.ToASCII(label))
58933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
59033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            labels.append('')
59133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if (len(labels) == 0 or labels[-1] != '') and not origin is None:
59233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        labels.extend(list(origin.labels))
59333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    return Name(labels)
59433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
59533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef from_text(text, origin = root):
59633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """Convert text into a Name object.
59733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @rtype: dns.name.Name object
59833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """
59933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
60033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if not isinstance(text, str):
60133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if isinstance(text, unicode) and sys.hexversion >= 0x02030000:
60233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return from_unicode(text, origin)
60333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
60433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            raise ValueError("input to from_text() must be a string")
60533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if not (origin is None or isinstance(origin, Name)):
60633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        raise ValueError("origin must be a Name or None")
60733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    labels = []
60833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    label = ''
60933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    escaping = False
61033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    edigits = 0
61133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    total = 0
61233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if text == '@':
61333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        text = ''
61433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if text:
61533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if text == '.':
61633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            return Name([''])
61733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        for c in text:
61833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if escaping:
61933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                if edigits == 0:
62033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    if c.isdigit():
62133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                        total = int(c)
62233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                        edigits += 1
62333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    else:
62433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                        label += c
62533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                        escaping = False
62633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                else:
62733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    if not c.isdigit():
62833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                        raise BadEscape
62933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    total *= 10
63033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    total += int(c)
63133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    edigits += 1
63233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    if edigits == 3:
63333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                        escaping = False
63433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                        label += chr(total)
63533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            elif c == '.':
63633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                if len(label) == 0:
63733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                    raise EmptyLabel
63833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                labels.append(label)
63933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                label = ''
64033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            elif c == '\\':
64133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                escaping = True
64233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                edigits = 0
64333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                total = 0
64433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            else:
64533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                label += c
64633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if escaping:
64733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            raise BadEscape
64833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if len(label) > 0:
64933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            labels.append(label)
65033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
65133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            labels.append('')
65233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if (len(labels) == 0 or labels[-1] != '') and not origin is None:
65333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        labels.extend(list(origin.labels))
65433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    return Name(labels)
65533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
65633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef from_wire(message, current):
65733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """Convert possibly compressed wire format into a Name.
65833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @param message: the entire DNS message
65933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @type message: string
66033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @param current: the offset of the beginning of the name from the start
66133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    of the message
66233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @type current: int
66333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @raises dns.name.BadPointer: a compression pointer did not point backwards
66433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    in the message
66533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @raises dns.name.BadLabelType: an invalid label type was encountered.
66633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @returns: a tuple consisting of the name that was read and the number
66733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    of bytes of the wire format message which were consumed reading it
66833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    @rtype: (dns.name.Name object, int) tuple
66933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    """
67033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
67133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if not isinstance(message, str):
67233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        raise ValueError("input to from_wire() must be a byte string")
67333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    labels = []
67433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    biggest_pointer = current
67533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    hops = 0
67633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    count = ord(message[current])
67733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    current += 1
67833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    cused = 1
67933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    while count != 0:
68033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if count < 64:
68133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            labels.append(message[current : current + count])
68233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            current += count
68333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if hops == 0:
68433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                cused += count
68533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        elif count >= 192:
68633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            current = (count & 0x3f) * 256 + ord(message[current])
68733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if hops == 0:
68833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                cused += 1
68933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            if current >= biggest_pointer:
69033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                raise BadPointer
69133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            biggest_pointer = current
69233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            hops += 1
69333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        else:
69433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            raise BadLabelType
69533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        count = ord(message[current])
69633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        current += 1
69733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if hops == 0:
69833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            cused += 1
69933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    labels.append('')
70033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    return (Name(labels), cused)
701