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