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 Name constructor requires a single argument, which is a tuple of bytes objects.

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 EmptyLabel exception will be raised.

If any of the labels is longer than 63 bytes long, a LabelTooLong exception will be raised.

If the name is more than 253 characters long, a NameTooLong exception 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, or bytes.

The suffix can also be a tuple of Name or things that can be converted to Name (str or bytes).

Parameters:
  • suffix (str, bytes, Name, or tuple) – Suffix to check the end of the name for.
  • start (int) – label to start checking at.
  • end (int) – label to stop checking at.
Returns:

Whether the name ends with the specified prefix.

Return type:

bool

Raises:

TypeError when 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:
  • val (bytes) – Value to use when creating the name.
  • canonicalize (bool) – Whether to canonicalize on creation.
Raises:

EmptyLabel

Raises:

LabelTooLong

Raises:

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:
  • val (str) – Value to use when creating the name.
  • canonicalize (bool) – Whether to canonicalize on creation.
Raises:

UnicodeError

Raises:

EmptyLabel

Raises:

LabelTooLong

Raises:

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
isroot() → bool[source]

Test if the name is the root (that is, has no labels).

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, or bytes.

The prefix can also be a tuple of Name or things that can be converted to Name (str or bytes).

Parameters:
  • prefix (str, bytes, Name or tuple) – Prefix to check the end of the name for.
  • start (int) – Label to start checking at.
  • end (int) – Label to stop checking at.
Returns:

Whether the name ends with the specified prefix.

Return type:

bool

Raises:

TypeError when prefix cannot be compared

to_presentation() → str[source]

Return a string of the name converted to the master zone file presentation format described in RFC 1035.

Returns:presentation format of the name
Return type:str
to_wire() → bytes[source]

Return a DNS wire-format version of the name, without any name compression.

Returns:wire format of the name
Return type:bytes

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:

Name

Raises:

UnicodeError

Raises:

EmptyLabel

Raises:

LabelTooLong

Raises:

NameTooLong

Raises:

TypeError