Spaces:
Paused
Paused
| # Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license | |
| # Copyright (C) 2003-2017 Nominum, Inc. | |
| # Copyright (C) 2016 Coresec Systems AB | |
| # | |
| # 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. | |
| # | |
| # THE SOFTWARE IS PROVIDED "AS IS" AND CORESEC SYSTEMS AB DISCLAIMS ALL | |
| # WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED | |
| # WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL CORESEC | |
| # SYSTEMS AB 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 name dictionary""" | |
| # pylint seems to be confused about this one! | |
| from collections.abc import MutableMapping # pylint: disable=no-name-in-module | |
| import dns.name | |
| class NameDict(MutableMapping): | |
| """A dictionary whose keys are dns.name.Name objects. | |
| In addition to being like a regular Python dictionary, this | |
| dictionary can also get the deepest match for a given key. | |
| """ | |
| __slots__ = ["max_depth", "max_depth_items", "__store"] | |
| def __init__(self, *args, **kwargs): | |
| super().__init__() | |
| self.__store = dict() | |
| #: the maximum depth of the keys that have ever been added | |
| self.max_depth = 0 | |
| #: the number of items of maximum depth | |
| self.max_depth_items = 0 | |
| self.update(dict(*args, **kwargs)) | |
| def __update_max_depth(self, key): | |
| if len(key) == self.max_depth: | |
| self.max_depth_items = self.max_depth_items + 1 | |
| elif len(key) > self.max_depth: | |
| self.max_depth = len(key) | |
| self.max_depth_items = 1 | |
| def __getitem__(self, key): | |
| return self.__store[key] | |
| def __setitem__(self, key, value): | |
| if not isinstance(key, dns.name.Name): | |
| raise ValueError("NameDict key must be a name") | |
| self.__store[key] = value | |
| self.__update_max_depth(key) | |
| def __delitem__(self, key): | |
| self.__store.pop(key) | |
| if len(key) == self.max_depth: | |
| self.max_depth_items = self.max_depth_items - 1 | |
| if self.max_depth_items == 0: | |
| self.max_depth = 0 | |
| for k in self.__store: | |
| self.__update_max_depth(k) | |
| def __iter__(self): | |
| return iter(self.__store) | |
| def __len__(self): | |
| return len(self.__store) | |
| def has_key(self, key): | |
| return key in self.__store | |
| def get_deepest_match(self, name): | |
| """Find the deepest match to *name* in the dictionary. | |
| The deepest match is the longest name in the dictionary which is | |
| a superdomain of *name*. Note that *superdomain* includes matching | |
| *name* itself. | |
| *name*, a ``dns.name.Name``, the name to find. | |
| Returns a ``(key, value)`` where *key* is the deepest | |
| ``dns.name.Name``, and *value* is the value associated with *key*. | |
| """ | |
| depth = len(name) | |
| if depth > self.max_depth: | |
| depth = self.max_depth | |
| for i in range(-depth, 0): | |
| n = dns.name.Name(name[i:]) | |
| if n in self: | |
| return (n, self[n]) | |
| v = self[dns.name.empty] | |
| return (dns.name.empty, v) | |