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