1# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
2
3# Copyright (C) 2001-2017 Nominum, Inc.
4#
5# Permission to use, copy, modify, and distribute this software and its
6# documentation for any purpose with or without fee is hereby granted,
7# provided that the above copyright notice and this permission notice
8# appear in all copies.
9#
10# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
11# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
13# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18"""DNS Names.
19"""
20
21from io import BytesIO
22import struct
23import sys
24import copy
25import encodings.idna
26try:
27    import idna
28    have_idna_2008 = True
29except ImportError:
30    have_idna_2008 = False
31
32import dns.exception
33import dns.wiredata
34
35from ._compat import long, binary_type, text_type, unichr, maybe_decode
36
37try:
38    maxint = sys.maxint  # pylint: disable=sys-max-int
39except AttributeError:
40    maxint = (1 << (8 * struct.calcsize("P"))) // 2 - 1
41
42
43# fullcompare() result values
44
45#: The compared names have no relationship to each other.
46NAMERELN_NONE = 0
47#: the first name is a superdomain of the second.
48NAMERELN_SUPERDOMAIN = 1
49#: The first name is a subdomain of the second.
50NAMERELN_SUBDOMAIN = 2
51#: The compared names are equal.
52NAMERELN_EQUAL = 3
53#: The compared names have a common ancestor.
54NAMERELN_COMMONANCESTOR = 4
55
56
57class EmptyLabel(dns.exception.SyntaxError):
58    """A DNS label is empty."""
59
60
61class BadEscape(dns.exception.SyntaxError):
62    """An escaped code in a text format of DNS name is invalid."""
63
64
65class BadPointer(dns.exception.FormError):
66    """A DNS compression pointer points forward instead of backward."""
67
68
69class BadLabelType(dns.exception.FormError):
70    """The label type in DNS name wire format is unknown."""
71
72
73class NeedAbsoluteNameOrOrigin(dns.exception.DNSException):
74    """An attempt was made to convert a non-absolute name to
75    wire when there was also a non-absolute (or missing) origin."""
76
77
78class NameTooLong(dns.exception.FormError):
79    """A DNS name is > 255 octets long."""
80
81
82class LabelTooLong(dns.exception.SyntaxError):
83    """A DNS label is > 63 octets long."""
84
85
86class AbsoluteConcatenation(dns.exception.DNSException):
87    """An attempt was made to append anything other than the
88    empty name to an absolute DNS name."""
89
90
91class NoParent(dns.exception.DNSException):
92    """An attempt was made to get the parent of the root name
93    or the empty name."""
94
95class NoIDNA2008(dns.exception.DNSException):
96    """IDNA 2008 processing was requested but the idna module is not
97    available."""
98
99
100class IDNAException(dns.exception.DNSException):
101    """IDNA processing raised an exception."""
102
103    supp_kwargs = {'idna_exception'}
104    fmt = "IDNA processing exception: {idna_exception}"
105
106
107class IDNACodec(object):
108    """Abstract base class for IDNA encoder/decoders."""
109
110    def __init__(self):
111        pass
112
113    def encode(self, label):
114        raise NotImplementedError
115
116    def decode(self, label):
117        # We do not apply any IDNA policy on decode; we just
118        downcased = label.lower()
119        if downcased.startswith(b'xn--'):
120            try:
121                label = downcased[4:].decode('punycode')
122            except Exception as e:
123                raise IDNAException(idna_exception=e)
124        else:
125            label = maybe_decode(label)
126        return _escapify(label, True)
127
128
129class IDNA2003Codec(IDNACodec):
130    """IDNA 2003 encoder/decoder."""
131
132    def __init__(self, strict_decode=False):
133        """Initialize the IDNA 2003 encoder/decoder.
134
135        *strict_decode* is a ``bool``. If `True`, then IDNA2003 checking
136        is done when decoding.  This can cause failures if the name
137        was encoded with IDNA2008.  The default is `False`.
138        """
139
140        super(IDNA2003Codec, self).__init__()
141        self.strict_decode = strict_decode
142
143    def encode(self, label):
144        """Encode *label*."""
145
146        if label == '':
147            return b''
148        try:
149            return encodings.idna.ToASCII(label)
150        except UnicodeError:
151            raise LabelTooLong
152
153    def decode(self, label):
154        """Decode *label*."""
155        if not self.strict_decode:
156            return super(IDNA2003Codec, self).decode(label)
157        if label == b'':
158            return u''
159        try:
160            return _escapify(encodings.idna.ToUnicode(label), True)
161        except Exception as e:
162            raise IDNAException(idna_exception=e)
163
164
165class IDNA2008Codec(IDNACodec):
166    """IDNA 2008 encoder/decoder.
167
168        *uts_46* is a ``bool``.  If True, apply Unicode IDNA
169        compatibility processing as described in Unicode Technical
170        Standard #46 (http://unicode.org/reports/tr46/).
171        If False, do not apply the mapping.  The default is False.
172
173        *transitional* is a ``bool``: If True, use the
174        "transitional" mode described in Unicode Technical Standard
175        #46.  The default is False.
176
177        *allow_pure_ascii* is a ``bool``.  If True, then a label which
178        consists of only ASCII characters is allowed.  This is less
179        strict than regular IDNA 2008, but is also necessary for mixed
180        names, e.g. a name with starting with "_sip._tcp." and ending
181        in an IDN suffix which would otherwise be disallowed.  The
182        default is False.
183
184        *strict_decode* is a ``bool``: If True, then IDNA2008 checking
185        is done when decoding.  This can cause failures if the name
186        was encoded with IDNA2003.  The default is False.
187        """
188
189    def __init__(self, uts_46=False, transitional=False,
190                 allow_pure_ascii=False, strict_decode=False):
191        """Initialize the IDNA 2008 encoder/decoder."""
192        super(IDNA2008Codec, self).__init__()
193        self.uts_46 = uts_46
194        self.transitional = transitional
195        self.allow_pure_ascii = allow_pure_ascii
196        self.strict_decode = strict_decode
197
198    def is_all_ascii(self, label):
199        for c in label:
200            if ord(c) > 0x7f:
201                return False
202        return True
203
204    def encode(self, label):
205        if label == '':
206            return b''
207        if self.allow_pure_ascii and self.is_all_ascii(label):
208            return label.encode('ascii')
209        if not have_idna_2008:
210            raise NoIDNA2008
211        try:
212            if self.uts_46:
213                label = idna.uts46_remap(label, False, self.transitional)
214            return idna.alabel(label)
215        except idna.IDNAError as e:
216            raise IDNAException(idna_exception=e)
217
218    def decode(self, label):
219        if not self.strict_decode:
220            return super(IDNA2008Codec, self).decode(label)
221        if label == b'':
222            return u''
223        if not have_idna_2008:
224            raise NoIDNA2008
225        try:
226            if self.uts_46:
227                label = idna.uts46_remap(label, False, False)
228            return _escapify(idna.ulabel(label), True)
229        except idna.IDNAError as e:
230            raise IDNAException(idna_exception=e)
231
232_escaped = bytearray(b'"().;\\@$')
233
234IDNA_2003_Practical = IDNA2003Codec(False)
235IDNA_2003_Strict = IDNA2003Codec(True)
236IDNA_2003 = IDNA_2003_Practical
237IDNA_2008_Practical = IDNA2008Codec(True, False, True, False)
238IDNA_2008_UTS_46 = IDNA2008Codec(True, False, False, False)
239IDNA_2008_Strict = IDNA2008Codec(False, False, False, True)
240IDNA_2008_Transitional = IDNA2008Codec(True, True, False, False)
241IDNA_2008 = IDNA_2008_Practical
242
243def _escapify(label, unicode_mode=False):
244    """Escape the characters in label which need it.
245    @param unicode_mode: escapify only special and whitespace (<= 0x20)
246    characters
247    @returns: the escaped string
248    @rtype: string"""
249    if not unicode_mode:
250        text = ''
251        if isinstance(label, text_type):
252            label = label.encode()
253        for c in bytearray(label):
254            if c in _escaped:
255                text += '\\' + chr(c)
256            elif c > 0x20 and c < 0x7F:
257                text += chr(c)
258            else:
259                text += '\\%03d' % c
260        return text.encode()
261
262    text = u''
263    if isinstance(label, binary_type):
264        label = label.decode()
265    for c in label:
266        if c > u'\x20' and c < u'\x7f':
267            text += c
268        else:
269            if c >= u'\x7f':
270                text += c
271            else:
272                text += u'\\%03d' % ord(c)
273    return text
274
275def _validate_labels(labels):
276    """Check for empty labels in the middle of a label sequence,
277    labels that are too long, and for too many labels.
278
279    Raises ``dns.name.NameTooLong`` if the name as a whole is too long.
280
281    Raises ``dns.name.EmptyLabel`` if a label is empty (i.e. the root
282    label) and appears in a position other than the end of the label
283    sequence
284
285    """
286
287    l = len(labels)
288    total = 0
289    i = -1
290    j = 0
291    for label in labels:
292        ll = len(label)
293        total += ll + 1
294        if ll > 63:
295            raise LabelTooLong
296        if i < 0 and label == b'':
297            i = j
298        j += 1
299    if total > 255:
300        raise NameTooLong
301    if i >= 0 and i != l - 1:
302        raise EmptyLabel
303
304
305def _maybe_convert_to_binary(label):
306    """If label is ``text``, convert it to ``binary``.  If it is already
307    ``binary`` just return it.
308
309    """
310
311    if isinstance(label, binary_type):
312        return label
313    if isinstance(label, text_type):
314        return label.encode()
315    raise ValueError
316
317
318class Name(object):
319
320    """A DNS name.
321
322    The dns.name.Name class represents a DNS name as a tuple of
323    labels.  Each label is a `binary` in DNS wire format.  Instances
324    of the class are immutable.
325    """
326
327    __slots__ = ['labels']
328
329    def __init__(self, labels):
330        """*labels* is any iterable whose values are ``text`` or ``binary``.
331        """
332
333        labels = [_maybe_convert_to_binary(x) for x in labels]
334        super(Name, self).__setattr__('labels', tuple(labels))
335        _validate_labels(self.labels)
336
337    def __setattr__(self, name, value):
338        # Names are immutable
339        raise TypeError("object doesn't support attribute assignment")
340
341    def __copy__(self):
342        return Name(self.labels)
343
344    def __deepcopy__(self, memo):
345        return Name(copy.deepcopy(self.labels, memo))
346
347    def __getstate__(self):
348        # Names can be pickled
349        return {'labels': self.labels}
350
351    def __setstate__(self, state):
352        super(Name, self).__setattr__('labels', state['labels'])
353        _validate_labels(self.labels)
354
355    def is_absolute(self):
356        """Is the most significant label of this name the root label?
357
358        Returns a ``bool``.
359        """
360
361        return len(self.labels) > 0 and self.labels[-1] == b''
362
363    def is_wild(self):
364        """Is this name wild?  (I.e. Is the least significant label '*'?)
365
366        Returns a ``bool``.
367        """
368
369        return len(self.labels) > 0 and self.labels[0] == b'*'
370
371    def __hash__(self):
372        """Return a case-insensitive hash of the name.
373
374        Returns an ``int``.
375        """
376
377        h = long(0)
378        for label in self.labels:
379            for c in bytearray(label.lower()):
380                h += (h << 3) + c
381        return int(h % maxint)
382
383    def fullcompare(self, other):
384        """Compare two names, returning a 3-tuple
385        ``(relation, order, nlabels)``.
386
387        *relation* describes the relation ship between the names,
388        and is one of: ``dns.name.NAMERELN_NONE``,
389        ``dns.name.NAMERELN_SUPERDOMAIN``, ``dns.name.NAMERELN_SUBDOMAIN``,
390        ``dns.name.NAMERELN_EQUAL``, or ``dns.name.NAMERELN_COMMONANCESTOR``.
391
392        *order* is < 0 if *self* < *other*, > 0 if *self* > *other*, and ==
393        0 if *self* == *other*.  A relative name is always less than an
394        absolute name.  If both names have the same relativity, then
395        the DNSSEC order relation is used to order them.
396
397        *nlabels* is the number of significant labels that the two names
398        have in common.
399
400        Here are some examples.  Names ending in "." are absolute names,
401        those not ending in "." are relative names.
402
403        =============  =============  ===========  =====  =======
404        self           other          relation     order  nlabels
405        =============  =============  ===========  =====  =======
406        www.example.   www.example.   equal        0      3
407        www.example.   example.       subdomain    > 0    2
408        example.       www.example.   superdomain  < 0    2
409        example1.com.  example2.com.  common anc.  < 0    2
410        example1       example2.      none         < 0    0
411        example1.      example2       none         > 0    0
412        =============  =============  ===========  =====  =======
413        """
414
415        sabs = self.is_absolute()
416        oabs = other.is_absolute()
417        if sabs != oabs:
418            if sabs:
419                return (NAMERELN_NONE, 1, 0)
420            else:
421                return (NAMERELN_NONE, -1, 0)
422        l1 = len(self.labels)
423        l2 = len(other.labels)
424        ldiff = l1 - l2
425        if ldiff < 0:
426            l = l1
427        else:
428            l = l2
429
430        order = 0
431        nlabels = 0
432        namereln = NAMERELN_NONE
433        while l > 0:
434            l -= 1
435            l1 -= 1
436            l2 -= 1
437            label1 = self.labels[l1].lower()
438            label2 = other.labels[l2].lower()
439            if label1 < label2:
440                order = -1
441                if nlabels > 0:
442                    namereln = NAMERELN_COMMONANCESTOR
443                return (namereln, order, nlabels)
444            elif label1 > label2:
445                order = 1
446                if nlabels > 0:
447                    namereln = NAMERELN_COMMONANCESTOR
448                return (namereln, order, nlabels)
449            nlabels += 1
450        order = ldiff
451        if ldiff < 0:
452            namereln = NAMERELN_SUPERDOMAIN
453        elif ldiff > 0:
454            namereln = NAMERELN_SUBDOMAIN
455        else:
456            namereln = NAMERELN_EQUAL
457        return (namereln, order, nlabels)
458
459    def is_subdomain(self, other):
460        """Is self a subdomain of other?
461
462        Note that the notion of subdomain includes equality, e.g.
463        "dnpython.org" is a subdomain of itself.
464
465        Returns a ``bool``.
466        """
467
468        (nr, o, nl) = self.fullcompare(other)
469        if nr == NAMERELN_SUBDOMAIN or nr == NAMERELN_EQUAL:
470            return True
471        return False
472
473    def is_superdomain(self, other):
474        """Is self a superdomain of other?
475
476        Note that the notion of superdomain includes equality, e.g.
477        "dnpython.org" is a superdomain of itself.
478
479        Returns a ``bool``.
480        """
481
482        (nr, o, nl) = self.fullcompare(other)
483        if nr == NAMERELN_SUPERDOMAIN or nr == NAMERELN_EQUAL:
484            return True
485        return False
486
487    def canonicalize(self):
488        """Return a name which is equal to the current name, but is in
489        DNSSEC canonical form.
490        """
491
492        return Name([x.lower() for x in self.labels])
493
494    def __eq__(self, other):
495        if isinstance(other, Name):
496            return self.fullcompare(other)[1] == 0
497        else:
498            return False
499
500    def __ne__(self, other):
501        if isinstance(other, Name):
502            return self.fullcompare(other)[1] != 0
503        else:
504            return True
505
506    def __lt__(self, other):
507        if isinstance(other, Name):
508            return self.fullcompare(other)[1] < 0
509        else:
510            return NotImplemented
511
512    def __le__(self, other):
513        if isinstance(other, Name):
514            return self.fullcompare(other)[1] <= 0
515        else:
516            return NotImplemented
517
518    def __ge__(self, other):
519        if isinstance(other, Name):
520            return self.fullcompare(other)[1] >= 0
521        else:
522            return NotImplemented
523
524    def __gt__(self, other):
525        if isinstance(other, Name):
526            return self.fullcompare(other)[1] > 0
527        else:
528            return NotImplemented
529
530    def __repr__(self):
531        return '<DNS name ' + self.__str__() + '>'
532
533    def __str__(self):
534        return self.to_text(False)
535
536    def to_text(self, omit_final_dot=False):
537        """Convert name to DNS text format.
538
539        *omit_final_dot* is a ``bool``.  If True, don't emit the final
540        dot (denoting the root label) for absolute names.  The default
541        is False.
542
543        Returns a ``text``.
544        """
545
546        if len(self.labels) == 0:
547            return maybe_decode(b'@')
548        if len(self.labels) == 1 and self.labels[0] == b'':
549            return maybe_decode(b'.')
550        if omit_final_dot and self.is_absolute():
551            l = self.labels[:-1]
552        else:
553            l = self.labels
554        s = b'.'.join(map(_escapify, l))
555        return maybe_decode(s)
556
557    def to_unicode(self, omit_final_dot=False, idna_codec=None):
558        """Convert name to Unicode text format.
559
560        IDN ACE labels are converted to Unicode.
561
562        *omit_final_dot* is a ``bool``.  If True, don't emit the final
563        dot (denoting the root label) for absolute names.  The default
564        is False.
565        *idna_codec* specifies the IDNA encoder/decoder.  If None, the
566        dns.name.IDNA_2003_Practical encoder/decoder is used.
567        The IDNA_2003_Practical decoder does
568        not impose any policy, it just decodes punycode, so if you
569        don't want checking for compliance, you can use this decoder
570        for IDNA2008 as well.
571
572        Returns a ``text``.
573        """
574
575        if len(self.labels) == 0:
576            return u'@'
577        if len(self.labels) == 1 and self.labels[0] == b'':
578            return u'.'
579        if omit_final_dot and self.is_absolute():
580            l = self.labels[:-1]
581        else:
582            l = self.labels
583        if idna_codec is None:
584            idna_codec = IDNA_2003_Practical
585        return u'.'.join([idna_codec.decode(x) for x in l])
586
587    def to_digestable(self, origin=None):
588        """Convert name to a format suitable for digesting in hashes.
589
590        The name is canonicalized and converted to uncompressed wire
591        format.  All names in wire format are absolute.  If the name
592        is a relative name, then an origin must be supplied.
593
594        *origin* is a ``dns.name.Name`` or ``None``.  If the name is
595        relative and origin is not ``None``, then origin will be appended
596        to the name.
597
598        Raises ``dns.name.NeedAbsoluteNameOrOrigin`` if the name is
599        relative and no origin was provided.
600
601        Returns a ``binary``.
602        """
603
604        if not self.is_absolute():
605            if origin is None or not origin.is_absolute():
606                raise NeedAbsoluteNameOrOrigin
607            labels = list(self.labels)
608            labels.extend(list(origin.labels))
609        else:
610            labels = self.labels
611        dlabels = [struct.pack('!B%ds' % len(x), len(x), x.lower())
612                   for x in labels]
613        return b''.join(dlabels)
614
615    def to_wire(self, file=None, compress=None, origin=None):
616        """Convert name to wire format, possibly compressing it.
617
618        *file* is the file where the name is emitted (typically a
619        BytesIO file).  If ``None`` (the default), a ``binary``
620        containing the wire name will be returned.
621
622        *compress*, a ``dict``, is the compression table to use.  If
623        ``None`` (the default), names will not be compressed.
624
625        *origin* is a ``dns.name.Name`` or ``None``.  If the name is
626        relative and origin is not ``None``, then *origin* will be appended
627        to it.
628
629        Raises ``dns.name.NeedAbsoluteNameOrOrigin`` if the name is
630        relative and no origin was provided.
631
632        Returns a ``binary`` or ``None``.
633        """
634
635        if file is None:
636            file = BytesIO()
637            want_return = True
638        else:
639            want_return = False
640
641        if not self.is_absolute():
642            if origin is None or not origin.is_absolute():
643                raise NeedAbsoluteNameOrOrigin
644            labels = list(self.labels)
645            labels.extend(list(origin.labels))
646        else:
647            labels = self.labels
648        i = 0
649        for label in labels:
650            n = Name(labels[i:])
651            i += 1
652            if compress is not None:
653                pos = compress.get(n)
654            else:
655                pos = None
656            if pos is not None:
657                value = 0xc000 + pos
658                s = struct.pack('!H', value)
659                file.write(s)
660                break
661            else:
662                if compress is not None and len(n) > 1:
663                    pos = file.tell()
664                    if pos <= 0x3fff:
665                        compress[n] = pos
666                l = len(label)
667                file.write(struct.pack('!B', l))
668                if l > 0:
669                    file.write(label)
670        if want_return:
671            return file.getvalue()
672
673    def __len__(self):
674        """The length of the name (in labels).
675
676        Returns an ``int``.
677        """
678
679        return len(self.labels)
680
681    def __getitem__(self, index):
682        return self.labels[index]
683
684    def __add__(self, other):
685        return self.concatenate(other)
686
687    def __sub__(self, other):
688        return self.relativize(other)
689
690    def split(self, depth):
691        """Split a name into a prefix and suffix names at the specified depth.
692
693        *depth* is an ``int`` specifying the number of labels in the suffix
694
695        Raises ``ValueError`` if *depth* was not >= 0 and <= the length of the
696        name.
697
698        Returns the tuple ``(prefix, suffix)``.
699        """
700
701        l = len(self.labels)
702        if depth == 0:
703            return (self, dns.name.empty)
704        elif depth == l:
705            return (dns.name.empty, self)
706        elif depth < 0 or depth > l:
707            raise ValueError(
708                'depth must be >= 0 and <= the length of the name')
709        return (Name(self[: -depth]), Name(self[-depth:]))
710
711    def concatenate(self, other):
712        """Return a new name which is the concatenation of self and other.
713
714        Raises ``dns.name.AbsoluteConcatenation`` if the name is
715        absolute and *other* is not the empty name.
716
717        Returns a ``dns.name.Name``.
718        """
719
720        if self.is_absolute() and len(other) > 0:
721            raise AbsoluteConcatenation
722        labels = list(self.labels)
723        labels.extend(list(other.labels))
724        return Name(labels)
725
726    def relativize(self, origin):
727        """If the name is a subdomain of *origin*, return a new name which is
728        the name relative to origin.  Otherwise return the name.
729
730        For example, relativizing ``www.dnspython.org.`` to origin
731        ``dnspython.org.`` returns the name ``www``.  Relativizing ``example.``
732        to origin ``dnspython.org.`` returns ``example.``.
733
734        Returns a ``dns.name.Name``.
735        """
736
737        if origin is not None and self.is_subdomain(origin):
738            return Name(self[: -len(origin)])
739        else:
740            return self
741
742    def derelativize(self, origin):
743        """If the name is a relative name, return a new name which is the
744        concatenation of the name and origin.  Otherwise return the name.
745
746        For example, derelativizing ``www`` to origin ``dnspython.org.``
747        returns the name ``www.dnspython.org.``.  Derelativizing ``example.``
748        to origin ``dnspython.org.`` returns ``example.``.
749
750        Returns a ``dns.name.Name``.
751        """
752
753        if not self.is_absolute():
754            return self.concatenate(origin)
755        else:
756            return self
757
758    def choose_relativity(self, origin=None, relativize=True):
759        """Return a name with the relativity desired by the caller.
760
761        If *origin* is ``None``, then the name is returned.
762        Otherwise, if *relativize* is ``True`` the name is
763        relativized, and if *relativize* is ``False`` the name is
764        derelativized.
765
766        Returns a ``dns.name.Name``.
767        """
768
769        if origin:
770            if relativize:
771                return self.relativize(origin)
772            else:
773                return self.derelativize(origin)
774        else:
775            return self
776
777    def parent(self):
778        """Return the parent of the name.
779
780        For example, the parent of ``www.dnspython.org.`` is ``dnspython.org``.
781
782        Raises ``dns.name.NoParent`` if the name is either the root name or the
783        empty name, and thus has no parent.
784
785        Returns a ``dns.name.Name``.
786        """
787
788        if self == root or self == empty:
789            raise NoParent
790        return Name(self.labels[1:])
791
792#: The root name, '.'
793root = Name([b''])
794
795#: The empty name.
796empty = Name([])
797
798def from_unicode(text, origin=root, idna_codec=None):
799    """Convert unicode text into a Name object.
800
801    Labels are encoded in IDN ACE form according to rules specified by
802    the IDNA codec.
803
804    *text*, a ``text``, is the text to convert into a name.
805
806    *origin*, a ``dns.name.Name``, specifies the origin to
807    append to non-absolute names.  The default is the root name.
808
809    *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
810    encoder/decoder.  If ``None``, the default IDNA 2003 encoder/decoder
811    is used.
812
813    Returns a ``dns.name.Name``.
814    """
815
816    if not isinstance(text, text_type):
817        raise ValueError("input to from_unicode() must be a unicode string")
818    if not (origin is None or isinstance(origin, Name)):
819        raise ValueError("origin must be a Name or None")
820    labels = []
821    label = u''
822    escaping = False
823    edigits = 0
824    total = 0
825    if idna_codec is None:
826        idna_codec = IDNA_2003
827    if text == u'@':
828        text = u''
829    if text:
830        if text == u'.':
831            return Name([b''])        # no Unicode "u" on this constant!
832        for c in text:
833            if escaping:
834                if edigits == 0:
835                    if c.isdigit():
836                        total = int(c)
837                        edigits += 1
838                    else:
839                        label += c
840                        escaping = False
841                else:
842                    if not c.isdigit():
843                        raise BadEscape
844                    total *= 10
845                    total += int(c)
846                    edigits += 1
847                    if edigits == 3:
848                        escaping = False
849                        label += unichr(total)
850            elif c in [u'.', u'\u3002', u'\uff0e', u'\uff61']:
851                if len(label) == 0:
852                    raise EmptyLabel
853                labels.append(idna_codec.encode(label))
854                label = u''
855            elif c == u'\\':
856                escaping = True
857                edigits = 0
858                total = 0
859            else:
860                label += c
861        if escaping:
862            raise BadEscape
863        if len(label) > 0:
864            labels.append(idna_codec.encode(label))
865        else:
866            labels.append(b'')
867
868    if (len(labels) == 0 or labels[-1] != b'') and origin is not None:
869        labels.extend(list(origin.labels))
870    return Name(labels)
871
872
873def from_text(text, origin=root, idna_codec=None):
874    """Convert text into a Name object.
875
876    *text*, a ``text``, is the text to convert into a name.
877
878    *origin*, a ``dns.name.Name``, specifies the origin to
879    append to non-absolute names.  The default is the root name.
880
881    *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
882    encoder/decoder.  If ``None``, the default IDNA 2003 encoder/decoder
883    is used.
884
885    Returns a ``dns.name.Name``.
886    """
887
888    if isinstance(text, text_type):
889        return from_unicode(text, origin, idna_codec)
890    if not isinstance(text, binary_type):
891        raise ValueError("input to from_text() must be a string")
892    if not (origin is None or isinstance(origin, Name)):
893        raise ValueError("origin must be a Name or None")
894    labels = []
895    label = b''
896    escaping = False
897    edigits = 0
898    total = 0
899    if text == b'@':
900        text = b''
901    if text:
902        if text == b'.':
903            return Name([b''])
904        for c in bytearray(text):
905            byte_ = struct.pack('!B', c)
906            if escaping:
907                if edigits == 0:
908                    if byte_.isdigit():
909                        total = int(byte_)
910                        edigits += 1
911                    else:
912                        label += byte_
913                        escaping = False
914                else:
915                    if not byte_.isdigit():
916                        raise BadEscape
917                    total *= 10
918                    total += int(byte_)
919                    edigits += 1
920                    if edigits == 3:
921                        escaping = False
922                        label += struct.pack('!B', total)
923            elif byte_ == b'.':
924                if len(label) == 0:
925                    raise EmptyLabel
926                labels.append(label)
927                label = b''
928            elif byte_ == b'\\':
929                escaping = True
930                edigits = 0
931                total = 0
932            else:
933                label += byte_
934        if escaping:
935            raise BadEscape
936        if len(label) > 0:
937            labels.append(label)
938        else:
939            labels.append(b'')
940    if (len(labels) == 0 or labels[-1] != b'') and origin is not None:
941        labels.extend(list(origin.labels))
942    return Name(labels)
943
944
945def from_wire(message, current):
946    """Convert possibly compressed wire format into a Name.
947
948    *message* is a ``binary`` containing an entire DNS message in DNS
949    wire form.
950
951    *current*, an ``int``, is the offset of the beginning of the name
952    from the start of the message
953
954    Raises ``dns.name.BadPointer`` if a compression pointer did not
955    point backwards in the message.
956
957    Raises ``dns.name.BadLabelType`` if an invalid label type was encountered.
958
959    Returns a ``(dns.name.Name, int)`` tuple consisting of the name
960    that was read and the number of bytes of the wire format message
961    which were consumed reading it.
962    """
963
964    if not isinstance(message, binary_type):
965        raise ValueError("input to from_wire() must be a byte string")
966    message = dns.wiredata.maybe_wrap(message)
967    labels = []
968    biggest_pointer = current
969    hops = 0
970    count = message[current]
971    current += 1
972    cused = 1
973    while count != 0:
974        if count < 64:
975            labels.append(message[current: current + count].unwrap())
976            current += count
977            if hops == 0:
978                cused += count
979        elif count >= 192:
980            current = (count & 0x3f) * 256 + message[current]
981            if hops == 0:
982                cused += 1
983            if current >= biggest_pointer:
984                raise BadPointer
985            biggest_pointer = current
986            hops += 1
987        else:
988            raise BadLabelType
989        count = message[current]
990        current += 1
991        if hops == 0:
992            cused += 1
993    labels.append('')
994    return (Name(labels), cused)
995