Name Module¶
The Name module provides a class for DNS names.
The Name class¶
A name is initialized from a tuple of bytes:
from dike import Name
python_sitename = Name((b'www', b'python', b'org'))
We can also create a name from a string using
Name.fromstr(), which makes a label for each dot-separated
piece. Each label is converted to
Punycode <https://tools.ietf.org/html/rfc3492>`_:
linux_sitename = Name.fromstr('www.kernel.org')
idn_city = Name.fromstr('Gießen.de')
idn_country = Name.fromstr('België.be')
A bytes value can also be used via
Name.frombytes(), which make a label for each dot-separated
piece. It does no further conversion:
bytes_name = Name.frombytes(b'non_unicode.name\0x80')
If you are uncertain of which type you will be using to initialize, or
just want to make life easy, the make_name() function will
create a name from any supported type:
from dike import make_name
example_name = make_name('a.good.example')
Note
All names are treated as Fully-Qualified Domain Names (FQDN), also called
absolute names. Names are parsed the same if they end with a
dot, ".", whether they do or not. For example,
"foo.example." is the same as "foo.example" when used to
initialize a Name instance.
Name instances are immutable - once initialized the value
never changes. This has the advantage of allowing names to be used as
keys in dict and various other places, but does mean that
updating a name is not possible.
Name comparisons use the canonical ordering defined in RFC 4034. This sorts the names by the right-most label:
assert Name.fromstr('example') < Name.fromstr('Z.a.example')
assert Name.fromstr('Z.a.example') > Name.fromstr('a.example')
assert Name.fromstr('Z.a.eXaMPLe') == Name.fromstr('z.A.ExAmplE')
In general, names can be treated as sequences:
k_root = Name.fromstr('k.root-servers.net')
for label_val in k_root:
print(label_val)
assert 'net.root-servers.k' == str(Name(tuple(reversed(k_root))))
assert 'f.root-servers.net' == 'f' + k_root[1:]
You can use the in operator to check for the presence of a given label in a name. Note that this searches for labels, not substrings:
foo = Name.fromstr('foo.example')
assert "example" in "foo.example" # we end with "example"
assert "exam" not in "foo.example" # "exam" is not a label
assert "exam" in str("foo.example") # "exam" is a substring
Similarly the built-in len() function will return the number of labels in a name, rather than the length of the name as a string. You can get the length of a name either as a str or bytes value by explicitly converting first:
assert len(foo) == 2
assert len(str(foo)) == 11
Converting to bytes works as expected, except in the case where
there is a dot . character in one of the labels. In that case, a
LabelHasDot exception will be raised. Converting to str
also works as expected, except when there is a dot . character in
one of the labels (when a LabelHasDot exception will be
raised) or a non-Unicode byte sequence (when a
UnicodeError will be raised). To convert to a printable
format in a safe way, use the Name.to_presentation()
method:
bar = Name((b'www',b'K\x80T',b'd.t'))
assert bar.to_presentation() == 'www.K\\128T.d\\.t.''
To check for parent/child relationships you can use the
Name.startswith() or Name.endswith() methods, or
slicing:
child = Name.fromstr('child.parent.zone')
parent = child[1:]
assert str(parent) == 'parent.zone'
assert child.endswith(parent)
assert child.endswith('zone')
These methods work very similar to the built-in
str.startswith() or str.endswith() methods,
including the ability to specify start & end values, as well as
comparing with multiple targets by passing a tuple:
zone_to_check = Name.fromstr('lots-o.info')
assert zone_to_check.endswith(('com', 'net', 'org', 'info'))
A couple of utility functions are also available to check for common types of names:
host_name = Name.fromstr('valid.hostname)
not_host_name = Name.fromstr('in_valid.hostname')
assert hostname.ishost() == True
assert not_host_name.ishost() == False
assert Name().isroot() == True
assert Name('any-other-name').isroot() == False
Name Objects¶
-
class
name.Name(labels: Tuple[bytes, ...] = (), *, canonicalize: bool = False)[source]¶ The
Nameconstructor requires a single argument, which is a tuple ofbytesobjects.Optionally canonicalize can be set to True, in which case the name will be set to the canonical (that is, lowercase) version.
If any of the labels is length 0, an
EmptyLabelexception will be raised.If any of the labels is longer than 63 bytes long, a
LabelTooLongexception will be raised.If the name is more than 253 characters long, a
NameTooLongexception will be raised.Parameters: - val (tuple of Label) – Value to use when creating the name.
- canonicalize (bool) – Whether to canonicalize on creation.
Raises: NameTooLong-
endswith(suffix: Union[Name, str, bytes, Tuple[Union[Name, str, bytes], ...]], start: int = 0, end: Optional[int] = None) → bool[source]¶ Return True if the name ends with the specified suffix. With optional start, test the name beginning at that label. With optional end, stop comparing the name at that label.
The suffix can be a
Name,str, orbytes.The suffix can also be a
tupleofNameor things that can be converted toName(strorbytes).Parameters: Returns: Whether the name ends with the specified prefix.
Return type: Raises: TypeErrorwhen suffix cannot be compared
-
classmethod
frombytes(val: bytes, *, canonicalize: bool = False) → name.Name[source]¶ Convert the specified value to a Name object, by splitting it into labels first.
Optionally canonicalize can be set to True, in which case the name will be set to the canonical (that is, lowercase) version.
A number of issues will cause an exception to be raised. Note that whitespace is not treated specially in any way, so if you want to trim it do so before passing to this method.
Parameters: Raises: EmptyLabelRaises: LabelTooLongRaises: NameTooLong
-
classmethod
fromstr(val: str, *, canonicalize: bool = False) → name.Name[source]¶ Convert the specified value to a Name object, by splitting it into labels first. It is converted to Punycode as necessary.
Optionally canonicalize can be set to True, in which case the name will be set to the canonical (that is, lowercase) version.
A number of issues will cause an exception to be raised. Note that whitespace is not treated specially in any way, so if you want to trim it do so before passing to this method.
Parameters: Raises: Raises: EmptyLabelRaises: LabelTooLongRaises: NameTooLong
-
ishost() → bool[source]¶ Test if the name is valid as a host name. The rules for host names are defined in:
Return type: bool
-
startswith(prefix: Union[Name, str, bytes, Tuple[Union[Name, str, bytes], ...]], start: int = 0, end: Optional[int] = None) → bool[source]¶ Return True if the name starts with the specified prefix. With optional start, test the name beginning at that label. With optional end, stop comparing the name at that label.
The prefix can be a
Name,str, orbytes.The prefix can also be a
tupleofNameor things that can be converted toName(strorbytes).Parameters: Returns: Whether the name ends with the specified prefix.
Return type: Raises: TypeErrorwhen prefix cannot be compared
Utility Functions¶
-
name.make_name(name_val: Union[name.Name, str, bytes, Sequence[Union[str, bytes]]], *, canonicalize: bool = False) → name.Name[source]¶ Initialize a name from a string, bytes, or a sequence containing these (such as a list or tuple). It can also be initialized from another name.
Optionally canonicalize can be set to True, in which case the name will be set to the canonical (that is, lowercase) version.
Parameters: - name_val – Value to create a new name from.
- canonicalize (bool) – Whether to canonicalize on creation.
Returns: an initialized name
Return type: Raises: Raises: EmptyLabelRaises: LabelTooLongRaises: NameTooLongRaises: