Package dns :: Module name
[hide private]
[frames] | no frames]

Source Code for Module dns.name

  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   
 21  from io import BytesIO 
 22  import struct 
 23  import sys 
 24  import copy 
 25  import encodings.idna 
 26  try: 
 27      import idna 
 28      have_idna_2008 = True 
 29  except ImportError: 
 30      have_idna_2008 = False 
 31   
 32  import dns.exception 
 33  import dns.wiredata 
 34   
 35  from ._compat import long, binary_type, text_type, unichr, maybe_decode 
 36   
 37  try: 
 38      maxint = sys.maxint  # pylint: disable=sys-max-int 
 39  except 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. 
 46  NAMERELN_NONE = 0 
 47  #: the first name is a superdomain of the second. 
 48  NAMERELN_SUPERDOMAIN = 1 
 49  #: The first name is a subdomain of the second. 
 50  NAMERELN_SUBDOMAIN = 2 
 51  #: The compared names are equal. 
 52  NAMERELN_EQUAL = 3 
 53  #: The compared names have a common ancestor. 
 54  NAMERELN_COMMONANCESTOR = 4 
 55   
 56   
57 -class EmptyLabel(dns.exception.SyntaxError):
58 """A DNS label is empty."""
59 60
61 -class BadEscape(dns.exception.SyntaxError):
62 """An escaped code in a text format of DNS name is invalid."""
63 64
65 -class BadPointer(dns.exception.FormError):
66 """A DNS compression pointer points forward instead of backward."""
67 68
69 -class BadLabelType(dns.exception.FormError):
70 """The label type in DNS name wire format is unknown."""
71 72
73 -class 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
78 -class NameTooLong(dns.exception.FormError):
79 """A DNS name is > 255 octets long."""
80 81
82 -class LabelTooLong(dns.exception.SyntaxError):
83 """A DNS label is > 63 octets long."""
84 85
86 -class 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
91 -class NoParent(dns.exception.DNSException):
92 """An attempt was made to get the parent of the root name 93 or the empty name."""
94
95 -class NoIDNA2008(dns.exception.DNSException):
96 """IDNA 2008 processing was requested but the idna module is not 97 available."""
98 99
100 -class 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
107 -class 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
129 -class 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
165 -class 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 234 IDNA_2003_Practical = IDNA2003Codec(False) 235 IDNA_2003_Strict = IDNA2003Codec(True) 236 IDNA_2003 = IDNA_2003_Practical 237 IDNA_2008_Practical = IDNA2008Codec(True, False, True, False) 238 IDNA_2008_UTS_46 = IDNA2008Codec(True, False, False, False) 239 IDNA_2008_Strict = IDNA2008Codec(False, False, False, True) 240 IDNA_2008_Transitional = IDNA2008Codec(True, True, False, False) 241 IDNA_2008 = IDNA_2008_Practical 242
243 -def _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
275 -def _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
305 -def _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
318 -class 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, '.' 793 root = Name([b'']) 794 795 #: The empty name. 796 empty = Name([]) 797
798 -def 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
873 -def 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
945 -def 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