Index: tools/telemetry/third_party/webpagereplay/third_party/dns/name.py |
diff --git a/tools/telemetry/third_party/webpagereplay/third_party/dns/name.py b/tools/telemetry/third_party/webpagereplay/third_party/dns/name.py |
deleted file mode 100644 |
index b54aa1981ffcacc4dafadaf72b1f95fd2e641299..0000000000000000000000000000000000000000 |
--- a/tools/telemetry/third_party/webpagereplay/third_party/dns/name.py |
+++ /dev/null |
@@ -1,700 +0,0 @@ |
-# Copyright (C) 2001-2007, 2009, 2010 Nominum, Inc. |
-# |
-# Permission to use, copy, modify, and distribute this software and its |
-# documentation for any purpose with or without fee is hereby granted, |
-# provided that the above copyright notice and this permission notice |
-# appear in all copies. |
-# |
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES |
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR |
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT |
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
- |
-"""DNS Names. |
- |
-@var root: The DNS root name. |
-@type root: dns.name.Name object |
-@var empty: The empty DNS name. |
-@type empty: dns.name.Name object |
-""" |
- |
-import cStringIO |
-import struct |
-import sys |
- |
-if sys.hexversion >= 0x02030000: |
- import encodings.idna |
- |
-import dns.exception |
- |
-NAMERELN_NONE = 0 |
-NAMERELN_SUPERDOMAIN = 1 |
-NAMERELN_SUBDOMAIN = 2 |
-NAMERELN_EQUAL = 3 |
-NAMERELN_COMMONANCESTOR = 4 |
- |
-class EmptyLabel(dns.exception.SyntaxError): |
- """Raised if a label is empty.""" |
- pass |
- |
-class BadEscape(dns.exception.SyntaxError): |
- """Raised if an escaped code in a text format name is invalid.""" |
- pass |
- |
-class BadPointer(dns.exception.FormError): |
- """Raised if a compression pointer points forward instead of backward.""" |
- pass |
- |
-class BadLabelType(dns.exception.FormError): |
- """Raised if the label type of a wire format name is unknown.""" |
- pass |
- |
-class NeedAbsoluteNameOrOrigin(dns.exception.DNSException): |
- """Raised if an attempt is made to convert a non-absolute name to |
- wire when there is also a non-absolute (or missing) origin.""" |
- pass |
- |
-class NameTooLong(dns.exception.FormError): |
- """Raised if a name is > 255 octets long.""" |
- pass |
- |
-class LabelTooLong(dns.exception.SyntaxError): |
- """Raised if a label is > 63 octets long.""" |
- pass |
- |
-class AbsoluteConcatenation(dns.exception.DNSException): |
- """Raised if an attempt is made to append anything other than the |
- empty name to an absolute name.""" |
- pass |
- |
-class NoParent(dns.exception.DNSException): |
- """Raised if an attempt is made to get the parent of the root name |
- or the empty name.""" |
- pass |
- |
-_escaped = { |
- '"' : True, |
- '(' : True, |
- ')' : True, |
- '.' : True, |
- ';' : True, |
- '\\' : True, |
- '@' : True, |
- '$' : True |
- } |
- |
-def _escapify(label): |
- """Escape the characters in label which need it. |
- @returns: the escaped string |
- @rtype: string""" |
- text = '' |
- for c in label: |
- if c in _escaped: |
- text += '\\' + c |
- elif ord(c) > 0x20 and ord(c) < 0x7F: |
- text += c |
- else: |
- text += '\\%03d' % ord(c) |
- return text |
- |
-def _validate_labels(labels): |
- """Check for empty labels in the middle of a label sequence, |
- labels that are too long, and for too many labels. |
- @raises NameTooLong: the name as a whole is too long |
- @raises LabelTooLong: an individual label is too long |
- @raises EmptyLabel: a label is empty (i.e. the root label) and appears |
- in a position other than the end of the label sequence""" |
- |
- l = len(labels) |
- total = 0 |
- i = -1 |
- j = 0 |
- for label in labels: |
- ll = len(label) |
- total += ll + 1 |
- if ll > 63: |
- raise LabelTooLong |
- if i < 0 and label == '': |
- i = j |
- j += 1 |
- if total > 255: |
- raise NameTooLong |
- if i >= 0 and i != l - 1: |
- raise EmptyLabel |
- |
-class Name(object): |
- """A DNS name. |
- |
- The dns.name.Name class represents a DNS name as a tuple of labels. |
- Instances of the class are immutable. |
- |
- @ivar labels: The tuple of labels in the name. Each label is a string of |
- up to 63 octets.""" |
- |
- __slots__ = ['labels'] |
- |
- def __init__(self, labels): |
- """Initialize a domain name from a list of labels. |
- @param labels: the labels |
- @type labels: any iterable whose values are strings |
- """ |
- |
- super(Name, self).__setattr__('labels', tuple(labels)) |
- _validate_labels(self.labels) |
- |
- def __setattr__(self, name, value): |
- raise TypeError("object doesn't support attribute assignment") |
- |
- def is_absolute(self): |
- """Is the most significant label of this name the root label? |
- @rtype: bool |
- """ |
- |
- return len(self.labels) > 0 and self.labels[-1] == '' |
- |
- def is_wild(self): |
- """Is this name wild? (I.e. Is the least significant label '*'?) |
- @rtype: bool |
- """ |
- |
- return len(self.labels) > 0 and self.labels[0] == '*' |
- |
- def __hash__(self): |
- """Return a case-insensitive hash of the name. |
- @rtype: int |
- """ |
- |
- h = 0L |
- for label in self.labels: |
- for c in label: |
- h += ( h << 3 ) + ord(c.lower()) |
- return int(h % sys.maxint) |
- |
- def fullcompare(self, other): |
- """Compare two names, returning a 3-tuple (relation, order, nlabels). |
- |
- I{relation} describes the relation ship between the names, |
- and is one of: dns.name.NAMERELN_NONE, |
- dns.name.NAMERELN_SUPERDOMAIN, dns.name.NAMERELN_SUBDOMAIN, |
- dns.name.NAMERELN_EQUAL, or dns.name.NAMERELN_COMMONANCESTOR |
- |
- I{order} is < 0 if self < other, > 0 if self > other, and == |
- 0 if self == other. A relative name is always less than an |
- absolute name. If both names have the same relativity, then |
- the DNSSEC order relation is used to order them. |
- |
- I{nlabels} is the number of significant labels that the two names |
- have in common. |
- """ |
- |
- sabs = self.is_absolute() |
- oabs = other.is_absolute() |
- if sabs != oabs: |
- if sabs: |
- return (NAMERELN_NONE, 1, 0) |
- else: |
- return (NAMERELN_NONE, -1, 0) |
- l1 = len(self.labels) |
- l2 = len(other.labels) |
- ldiff = l1 - l2 |
- if ldiff < 0: |
- l = l1 |
- else: |
- l = l2 |
- |
- order = 0 |
- nlabels = 0 |
- namereln = NAMERELN_NONE |
- while l > 0: |
- l -= 1 |
- l1 -= 1 |
- l2 -= 1 |
- label1 = self.labels[l1].lower() |
- label2 = other.labels[l2].lower() |
- if label1 < label2: |
- order = -1 |
- if nlabels > 0: |
- namereln = NAMERELN_COMMONANCESTOR |
- return (namereln, order, nlabels) |
- elif label1 > label2: |
- order = 1 |
- if nlabels > 0: |
- namereln = NAMERELN_COMMONANCESTOR |
- return (namereln, order, nlabels) |
- nlabels += 1 |
- order = ldiff |
- if ldiff < 0: |
- namereln = NAMERELN_SUPERDOMAIN |
- elif ldiff > 0: |
- namereln = NAMERELN_SUBDOMAIN |
- else: |
- namereln = NAMERELN_EQUAL |
- return (namereln, order, nlabels) |
- |
- def is_subdomain(self, other): |
- """Is self a subdomain of other? |
- |
- The notion of subdomain includes equality. |
- @rtype: bool |
- """ |
- |
- (nr, o, nl) = self.fullcompare(other) |
- if nr == NAMERELN_SUBDOMAIN or nr == NAMERELN_EQUAL: |
- return True |
- return False |
- |
- def is_superdomain(self, other): |
- """Is self a superdomain of other? |
- |
- The notion of subdomain includes equality. |
- @rtype: bool |
- """ |
- |
- (nr, o, nl) = self.fullcompare(other) |
- if nr == NAMERELN_SUPERDOMAIN or nr == NAMERELN_EQUAL: |
- return True |
- return False |
- |
- def canonicalize(self): |
- """Return a name which is equal to the current name, but is in |
- DNSSEC canonical form. |
- @rtype: dns.name.Name object |
- """ |
- |
- return Name([x.lower() for x in self.labels]) |
- |
- def __eq__(self, other): |
- if isinstance(other, Name): |
- return self.fullcompare(other)[1] == 0 |
- else: |
- return False |
- |
- def __ne__(self, other): |
- if isinstance(other, Name): |
- return self.fullcompare(other)[1] != 0 |
- else: |
- return True |
- |
- def __lt__(self, other): |
- if isinstance(other, Name): |
- return self.fullcompare(other)[1] < 0 |
- else: |
- return NotImplemented |
- |
- def __le__(self, other): |
- if isinstance(other, Name): |
- return self.fullcompare(other)[1] <= 0 |
- else: |
- return NotImplemented |
- |
- def __ge__(self, other): |
- if isinstance(other, Name): |
- return self.fullcompare(other)[1] >= 0 |
- else: |
- return NotImplemented |
- |
- def __gt__(self, other): |
- if isinstance(other, Name): |
- return self.fullcompare(other)[1] > 0 |
- else: |
- return NotImplemented |
- |
- def __repr__(self): |
- return '<DNS name ' + self.__str__() + '>' |
- |
- def __str__(self): |
- return self.to_text(False) |
- |
- def to_text(self, omit_final_dot = False): |
- """Convert name to text format. |
- @param omit_final_dot: If True, don't emit the final dot (denoting the |
- root label) for absolute names. The default is False. |
- @rtype: string |
- """ |
- |
- if len(self.labels) == 0: |
- return '@' |
- if len(self.labels) == 1 and self.labels[0] == '': |
- return '.' |
- if omit_final_dot and self.is_absolute(): |
- l = self.labels[:-1] |
- else: |
- l = self.labels |
- s = '.'.join(map(_escapify, l)) |
- return s |
- |
- def to_unicode(self, omit_final_dot = False): |
- """Convert name to Unicode text format. |
- |
- IDN ACE lables are converted to Unicode. |
- |
- @param omit_final_dot: If True, don't emit the final dot (denoting the |
- root label) for absolute names. The default is False. |
- @rtype: string |
- """ |
- |
- if len(self.labels) == 0: |
- return u'@' |
- if len(self.labels) == 1 and self.labels[0] == '': |
- return u'.' |
- if omit_final_dot and self.is_absolute(): |
- l = self.labels[:-1] |
- else: |
- l = self.labels |
- s = u'.'.join([encodings.idna.ToUnicode(_escapify(x)) for x in l]) |
- return s |
- |
- def to_digestable(self, origin=None): |
- """Convert name to a format suitable for digesting in hashes. |
- |
- The name is canonicalized and converted to uncompressed wire format. |
- |
- @param origin: If the name is relative and origin is not None, then |
- origin will be appended to it. |
- @type origin: dns.name.Name object |
- @raises NeedAbsoluteNameOrOrigin: All names in wire format are |
- absolute. If self is a relative name, then an origin must be supplied; |
- if it is missing, then this exception is raised |
- @rtype: string |
- """ |
- |
- if not self.is_absolute(): |
- if origin is None or not origin.is_absolute(): |
- raise NeedAbsoluteNameOrOrigin |
- labels = list(self.labels) |
- labels.extend(list(origin.labels)) |
- else: |
- labels = self.labels |
- dlabels = ["%s%s" % (chr(len(x)), x.lower()) for x in labels] |
- return ''.join(dlabels) |
- |
- def to_wire(self, file = None, compress = None, origin = None): |
- """Convert name to wire format, possibly compressing it. |
- |
- @param file: the file where the name is emitted (typically |
- a cStringIO file). If None, a string containing the wire name |
- will be returned. |
- @type file: file or None |
- @param compress: The compression table. If None (the default) names |
- will not be compressed. |
- @type compress: dict |
- @param origin: If the name is relative and origin is not None, then |
- origin will be appended to it. |
- @type origin: dns.name.Name object |
- @raises NeedAbsoluteNameOrOrigin: All names in wire format are |
- absolute. If self is a relative name, then an origin must be supplied; |
- if it is missing, then this exception is raised |
- """ |
- |
- if file is None: |
- file = cStringIO.StringIO() |
- want_return = True |
- else: |
- want_return = False |
- |
- if not self.is_absolute(): |
- if origin is None or not origin.is_absolute(): |
- raise NeedAbsoluteNameOrOrigin |
- labels = list(self.labels) |
- labels.extend(list(origin.labels)) |
- else: |
- labels = self.labels |
- i = 0 |
- for label in labels: |
- n = Name(labels[i:]) |
- i += 1 |
- if not compress is None: |
- pos = compress.get(n) |
- else: |
- pos = None |
- if not pos is None: |
- value = 0xc000 + pos |
- s = struct.pack('!H', value) |
- file.write(s) |
- break |
- else: |
- if not compress is None and len(n) > 1: |
- pos = file.tell() |
- if pos < 0xc000: |
- compress[n] = pos |
- l = len(label) |
- file.write(chr(l)) |
- if l > 0: |
- file.write(label) |
- if want_return: |
- return file.getvalue() |
- |
- def __len__(self): |
- """The length of the name (in labels). |
- @rtype: int |
- """ |
- |
- return len(self.labels) |
- |
- def __getitem__(self, index): |
- return self.labels[index] |
- |
- def __getslice__(self, start, stop): |
- return self.labels[start:stop] |
- |
- def __add__(self, other): |
- return self.concatenate(other) |
- |
- def __sub__(self, other): |
- return self.relativize(other) |
- |
- def split(self, depth): |
- """Split a name into a prefix and suffix at depth. |
- |
- @param depth: the number of labels in the suffix |
- @type depth: int |
- @raises ValueError: the depth was not >= 0 and <= the length of the |
- name. |
- @returns: the tuple (prefix, suffix) |
- @rtype: tuple |
- """ |
- |
- l = len(self.labels) |
- if depth == 0: |
- return (self, dns.name.empty) |
- elif depth == l: |
- return (dns.name.empty, self) |
- elif depth < 0 or depth > l: |
- raise ValueError('depth must be >= 0 and <= the length of the name') |
- return (Name(self[: -depth]), Name(self[-depth :])) |
- |
- def concatenate(self, other): |
- """Return a new name which is the concatenation of self and other. |
- @rtype: dns.name.Name object |
- @raises AbsoluteConcatenation: self is absolute and other is |
- not the empty name |
- """ |
- |
- if self.is_absolute() and len(other) > 0: |
- raise AbsoluteConcatenation |
- labels = list(self.labels) |
- labels.extend(list(other.labels)) |
- return Name(labels) |
- |
- def relativize(self, origin): |
- """If self is a subdomain of origin, return a new name which is self |
- relative to origin. Otherwise return self. |
- @rtype: dns.name.Name object |
- """ |
- |
- if not origin is None and self.is_subdomain(origin): |
- return Name(self[: -len(origin)]) |
- else: |
- return self |
- |
- def derelativize(self, origin): |
- """If self is a relative name, return a new name which is the |
- concatenation of self and origin. Otherwise return self. |
- @rtype: dns.name.Name object |
- """ |
- |
- if not self.is_absolute(): |
- return self.concatenate(origin) |
- else: |
- return self |
- |
- def choose_relativity(self, origin=None, relativize=True): |
- """Return a name with the relativity desired by the caller. If |
- origin is None, then self is returned. Otherwise, if |
- relativize is true the name is relativized, and if relativize is |
- false the name is derelativized. |
- @rtype: dns.name.Name object |
- """ |
- |
- if origin: |
- if relativize: |
- return self.relativize(origin) |
- else: |
- return self.derelativize(origin) |
- else: |
- return self |
- |
- def parent(self): |
- """Return the parent of the name. |
- @rtype: dns.name.Name object |
- @raises NoParent: the name is either the root name or the empty name, |
- and thus has no parent. |
- """ |
- if self == root or self == empty: |
- raise NoParent |
- return Name(self.labels[1:]) |
- |
-root = Name(['']) |
-empty = Name([]) |
- |
-def from_unicode(text, origin = root): |
- """Convert unicode text into a Name object. |
- |
- Lables are encoded in IDN ACE form. |
- |
- @rtype: dns.name.Name object |
- """ |
- |
- if not isinstance(text, unicode): |
- raise ValueError("input to from_unicode() must be a unicode string") |
- if not (origin is None or isinstance(origin, Name)): |
- raise ValueError("origin must be a Name or None") |
- labels = [] |
- label = u'' |
- escaping = False |
- edigits = 0 |
- total = 0 |
- if text == u'@': |
- text = u'' |
- if text: |
- if text == u'.': |
- return Name(['']) # no Unicode "u" on this constant! |
- for c in text: |
- if escaping: |
- if edigits == 0: |
- if c.isdigit(): |
- total = int(c) |
- edigits += 1 |
- else: |
- label += c |
- escaping = False |
- else: |
- if not c.isdigit(): |
- raise BadEscape |
- total *= 10 |
- total += int(c) |
- edigits += 1 |
- if edigits == 3: |
- escaping = False |
- label += chr(total) |
- elif c == u'.' or c == u'\u3002' or \ |
- c == u'\uff0e' or c == u'\uff61': |
- if len(label) == 0: |
- raise EmptyLabel |
- labels.append(encodings.idna.ToASCII(label)) |
- label = u'' |
- elif c == u'\\': |
- escaping = True |
- edigits = 0 |
- total = 0 |
- else: |
- label += c |
- if escaping: |
- raise BadEscape |
- if len(label) > 0: |
- labels.append(encodings.idna.ToASCII(label)) |
- else: |
- labels.append('') |
- if (len(labels) == 0 or labels[-1] != '') and not origin is None: |
- labels.extend(list(origin.labels)) |
- return Name(labels) |
- |
-def from_text(text, origin = root): |
- """Convert text into a Name object. |
- @rtype: dns.name.Name object |
- """ |
- |
- if not isinstance(text, str): |
- if isinstance(text, unicode) and sys.hexversion >= 0x02030000: |
- return from_unicode(text, origin) |
- else: |
- raise ValueError("input to from_text() must be a string") |
- if not (origin is None or isinstance(origin, Name)): |
- raise ValueError("origin must be a Name or None") |
- labels = [] |
- label = '' |
- escaping = False |
- edigits = 0 |
- total = 0 |
- if text == '@': |
- text = '' |
- if text: |
- if text == '.': |
- return Name(['']) |
- for c in text: |
- if escaping: |
- if edigits == 0: |
- if c.isdigit(): |
- total = int(c) |
- edigits += 1 |
- else: |
- label += c |
- escaping = False |
- else: |
- if not c.isdigit(): |
- raise BadEscape |
- total *= 10 |
- total += int(c) |
- edigits += 1 |
- if edigits == 3: |
- escaping = False |
- label += chr(total) |
- elif c == '.': |
- if len(label) == 0: |
- raise EmptyLabel |
- labels.append(label) |
- label = '' |
- elif c == '\\': |
- escaping = True |
- edigits = 0 |
- total = 0 |
- else: |
- label += c |
- if escaping: |
- raise BadEscape |
- if len(label) > 0: |
- labels.append(label) |
- else: |
- labels.append('') |
- if (len(labels) == 0 or labels[-1] != '') and not origin is None: |
- labels.extend(list(origin.labels)) |
- return Name(labels) |
- |
-def from_wire(message, current): |
- """Convert possibly compressed wire format into a Name. |
- @param message: the entire DNS message |
- @type message: string |
- @param current: the offset of the beginning of the name from the start |
- of the message |
- @type current: int |
- @raises dns.name.BadPointer: a compression pointer did not point backwards |
- in the message |
- @raises dns.name.BadLabelType: an invalid label type was encountered. |
- @returns: a tuple consisting of the name that was read and the number |
- of bytes of the wire format message which were consumed reading it |
- @rtype: (dns.name.Name object, int) tuple |
- """ |
- |
- if not isinstance(message, str): |
- raise ValueError("input to from_wire() must be a byte string") |
- labels = [] |
- biggest_pointer = current |
- hops = 0 |
- count = ord(message[current]) |
- current += 1 |
- cused = 1 |
- while count != 0: |
- if count < 64: |
- labels.append(message[current : current + count]) |
- current += count |
- if hops == 0: |
- cused += count |
- elif count >= 192: |
- current = (count & 0x3f) * 256 + ord(message[current]) |
- if hops == 0: |
- cused += 1 |
- if current >= biggest_pointer: |
- raise BadPointer |
- biggest_pointer = current |
- hops += 1 |
- else: |
- raise BadLabelType |
- count = ord(message[current]) |
- current += 1 |
- if hops == 0: |
- cused += 1 |
- labels.append('') |
- return (Name(labels), cused) |