dnspython  1.16.0
About: dnspython is a DNS toolkit (for Python 2.x) that supports almost all record types.
  Fossies Dox: dnspython-1.16.0.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

name.py
Go to the documentation of this file.
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 
58  """A DNS label is empty."""
59 
60 
62  """An escaped code in a text format of DNS name is invalid."""
63 
64 
66  """A DNS compression pointer points forward instead of backward."""
67 
68 
70  """The label type in DNS name wire format is unknown."""
71 
72 
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 
79  """A DNS name is > 255 octets long."""
80 
81 
83  """A DNS label is > 63 octets long."""
84 
85 
87  """An attempt was made to append anything other than the
88  empty name to an absolute DNS name."""
89 
90 
92  """An attempt was made to get the parent of the root name
93  or the empty name."""
94 
96  """IDNA 2008 processing was requested but the idna module is not
97  available."""
98 
99 
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 
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 
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 
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)
dns.name.IDNA2008Codec.allow_pure_ascii
allow_pure_ascii
Definition: name.py:194
dns.name._maybe_convert_to_binary
def _maybe_convert_to_binary(label)
Definition: name.py:305
dns.name.Name
Definition: name.py:318
dns.exception.FormError
Definition: exception.py:109
dns.exception.SyntaxError
Definition: exception.py:113
dns.name.Name.derelativize
def derelativize(self, origin)
Definition: name.py:742
dns.name.Name.is_subdomain
def is_subdomain(self, other)
Definition: name.py:459
dns.name.NeedAbsoluteNameOrOrigin
Definition: name.py:73
dns.name.BadPointer
Definition: name.py:65
dns.name._validate_labels
def _validate_labels(labels)
Definition: name.py:275
dns.name.from_text
def from_text(text, origin=root, idna_codec=None)
Definition: name.py:873
dns.name.Name.__lt__
def __lt__(self, other)
Definition: name.py:506
dns.name.Name.is_superdomain
def is_superdomain(self, other)
Definition: name.py:473
dns.name.IDNA2003Codec.decode
def decode(self, label)
Definition: name.py:153
dns.name.Name.relativize
def relativize(self, origin)
Definition: name.py:726
dns.name.Name.__hash__
def __hash__(self)
Definition: name.py:371
dns.name.Name.__sub__
def __sub__(self, other)
Definition: name.py:687
dns.name.Name.is_wild
def is_wild(self)
Definition: name.py:363
dns.name.Name.__len__
def __len__(self)
Definition: name.py:673
dns.name.Name.to_text
def to_text(self, omit_final_dot=False)
Definition: name.py:536
dns.name.IDNA2008Codec
Definition: name.py:165
dns._compat.maybe_decode
def maybe_decode(x)
Definition: _compat.py:22
dns.name._escapify
def _escapify(label, unicode_mode=False)
Definition: name.py:243
dns.name.IDNACodec.decode
def decode(self, label)
Definition: name.py:116
dns.name.Name.fullcompare
def fullcompare(self, other)
Definition: name.py:383
dns.exception.DNSException
Definition: exception.py:24
dns.name.LabelTooLong
Definition: name.py:82
dns.name.Name.__getitem__
def __getitem__(self, index)
Definition: name.py:681
dns.name.IDNACodec
Definition: name.py:107
dns.name.Name.to_digestable
def to_digestable(self, origin=None)
Definition: name.py:587
dns.name.from_unicode
def from_unicode(text, origin=root, idna_codec=None)
Definition: name.py:798
dns.name.IDNA2003Codec.encode
def encode(self, label)
Definition: name.py:143
dns.name.Name.split
def split(self, depth)
Definition: name.py:690
dns.name.Name.__str__
def __str__(self)
Definition: name.py:533
dns.name.Name.concatenate
def concatenate(self, other)
Definition: name.py:711
dns.name.from_wire
def from_wire(message, current)
Definition: name.py:945
dns.name.IDNA2003Codec
Definition: name.py:129
dns.name.Name.__ne__
def __ne__(self, other)
Definition: name.py:500
dns.name.IDNA2008Codec.is_all_ascii
def is_all_ascii(self, label)
Definition: name.py:198
dns.name.Name.__add__
def __add__(self, other)
Definition: name.py:684
dns.name.BadLabelType
Definition: name.py:69
dns.name.AbsoluteConcatenation
Definition: name.py:86
dns.name.NoIDNA2008
Definition: name.py:95
dns.name.Name.canonicalize
def canonicalize(self)
Definition: name.py:487
dns.name.IDNACodec.encode
def encode(self, label)
Definition: name.py:113
dns.name.IDNACodec.__init__
def __init__(self)
Definition: name.py:110
dns.name.Name.__gt__
def __gt__(self, other)
Definition: name.py:524
dns.name.BadEscape
Definition: name.py:61
dns.name.Name.parent
def parent(self)
Definition: name.py:777
dns.wiredata
Definition: wiredata.py:1
dns.name.Name.__deepcopy__
def __deepcopy__(self, memo)
Definition: name.py:344
dns.name.IDNA2008Codec.decode
def decode(self, label)
Definition: name.py:218
dns.name.Name.choose_relativity
def choose_relativity(self, origin=None, relativize=True)
Definition: name.py:758
dns.name.Name.__eq__
def __eq__(self, other)
Definition: name.py:494
dns.name.IDNAException
Definition: name.py:100
dns.name.Name.to_wire
def to_wire(self, file=None, compress=None, origin=None)
Definition: name.py:615
dns.name.Name.__setstate__
def __setstate__(self, state)
Definition: name.py:351
dns.name.Name.__getstate__
def __getstate__(self)
Definition: name.py:347
dns.name.NoParent
Definition: name.py:91
dns.name.Name.__setattr__
def __setattr__(self, name, value)
Definition: name.py:337
dns.name.Name.__copy__
def __copy__(self)
Definition: name.py:341
dns.name.IDNA2008Codec.strict_decode
strict_decode
Definition: name.py:195
dns.name.NameTooLong
Definition: name.py:78
dns.name.IDNA2003Codec.strict_decode
strict_decode
Definition: name.py:141
dns.name.Name.to_unicode
def to_unicode(self, omit_final_dot=False, idna_codec=None)
Definition: name.py:557
dns.name.IDNA2008Codec.uts_46
uts_46
Definition: name.py:192
dns.name.IDNA2008Codec.encode
def encode(self, label)
Definition: name.py:204
dns._compat.unichr
unichr
Definition: _compat.py:21
dns.name.Name.__repr__
def __repr__(self)
Definition: name.py:530
dns.name.IDNA2008Codec.transitional
transitional
Definition: name.py:193
dns.name.EmptyLabel
Definition: name.py:57
dns.name.Name.__ge__
def __ge__(self, other)
Definition: name.py:518
dns.name.Name.__le__
def __le__(self, other)
Definition: name.py:512
dns.name.Name.is_absolute
def is_absolute(self)
Definition: name.py:355
dns._compat.long
long
Definition: _compat.py:10
dns.exception
Definition: exception.py:1
dns.name.Name.__init__
def __init__(self, labels)
Definition: name.py:329
dns.name.IDNA2003Codec.__init__
def __init__(self, strict_decode=False)
Definition: name.py:132
dns.name.IDNA2008Codec.__init__
def __init__(self, uts_46=False, transitional=False, allow_pure_ascii=False, strict_decode=False)
Definition: name.py:189
dns.wiredata.maybe_wrap
def maybe_wrap(wire)
Definition: wiredata.py:96