dns_domain (dns_erlang v5.0.5)
View SourceDomain name processing module providing operations for converting between text representation, label lists, and DNS wire format.
This module provides strictly reversible domain name operations for use in DNS message encoding and decoding.
Summary
Types
Compression map: maps label sequences to positions.
Decode error types.
Text representation of domain name: "www.example.com".
Encode error types.
Single label: "www".
List of labels.
Wire format binary.
Functions
Compare two domain names case-insensitively.
Compare two label lists case-insensitively.
Escape special characters in a label.
Convert wire format to domain name.
Convert wire format to domain name with compression support.
Equivalent to join(Labels, subdomain).
Join labels into domain name.
Split domain name into labels.
Returns provided name with case-insensitive characters in lowercase.
Returns provided name with case-insensitive characters in uppercase.
Convert domain name to wire format.
Convert domain name to wire format with compression.
Unescape a label by removing escape sequences.
Types
-type compmap() :: #{labels() => non_neg_integer()}.
Compression map: maps label sequences to positions.
-type decode_error() :: {error, truncated} | {error, invalid_label_length, non_neg_integer()} | {error, bad_pointer, non_neg_integer()}.
Decode error types.
-type dname() :: binary().
Text representation of domain name: "www.example.com".
Encode error types.
-type label() :: binary().
Single label: "www".
-type labels() :: [label()].
List of labels.
-type wire() :: binary().
Wire format binary.
Functions
Compare two domain names case-insensitively.
Returns true if the names are equal, false otherwise.
Compare two label lists case-insensitively.
Returns true if the label lists are equal, false otherwise.
Escape special characters in a label.
Escapes dots (.) and backslashes (\) in a label by prefixing them with
backslashes. Returns the original label unchanged if no escaping is needed.
Use this when you need to include literal dots or backslashes in a label that will be joined with other labels.
Examples:
1> dns_domain:escape_label(~"test").
~"test"
2> dns_domain:escape_label(~"test.label").
~"test\\.label"
3> dns_domain:escape_label(~"test\\label").
~"test\\\\label"
4> dns_domain:escape_label(~"test\\.label").
~"test\\\\.label"
Convert wire format to domain name.
Decodes a DNS wire format binary into a domain name string. Handles escaped characters in labels automatically.
Returns {Dname, Rest} where Dname is the decoded domain name and Rest
is any remaining binary data after the name.
Raises truncated if the wire format is incomplete or malformed.
Raises {invalid_label_length, Len} if a label length byte exceeds 63.
Raises {name_too_long, Size} if the decoded name exceeds 255 bytes.
Raises {too_many_labels, Count} if the name contains more than 127 labels.
Examples:
1> Wire = <<3,119,119,119,7,101,120,97,109,112,108,101,3,99,111,109,0>>.
2> {Dname, Rest} = dns_domain:from_wire(Wire).
{~"www.example.com", <<>>}
3> Wire2 = <<7,101,120,97,109,112,108,101,3,99,111,109,0,1,2,3>>.
4> {Dname2, Rest2} = dns_domain:from_wire(Wire2).
{~"example.com", <<1,2,3>>}
5> Wire3 = <<0>>.
6> {Dname3, Rest3} = dns_domain:from_wire(Wire3).
{<<>>, <<>>}
Convert wire format to domain name with compression support.
Decodes a DNS wire format binary that may contain compression pointers. Compression pointers allow names to reference earlier parts of the message to reduce size.
MsgBin is the complete message binary needed to resolve compression pointers.
DataBin is the binary data starting at the name to decode.
Returns {Dname, Rest} where Dname is the decoded domain name and Rest
is any remaining binary data after the name.
Raises the same errors as from_wire/1, plus {bad_pointer, Pos} if a
compression pointer is invalid or points outside the message.
Examples:
1> MsgBin = <<7,101,120,97,109,112,108,101,3,99,111,109,0,3,119,119,119,192,0>>.
%% First name at position 0: "example.com"
%% Second name at position 13: "www.example.com" (uses compression pointer)
2> {Dname1, Rest1} = dns_domain:from_wire(MsgBin, MsgBin).
{~"example.com", <<3,119,119,119,192,0>>}
3> {Dname2, Rest2} = dns_domain:from_wire(MsgBin, Rest1).
{~"www.example.com", <<>>}
%% Resolved compression pointer to decode "www.example.com"
Equivalent to join(Labels, subdomain).
Join labels into domain name.
Converts a list of labels into a domain name string. Automatically escapes dots and backslashes in labels as needed.
Returns an empty binary for an empty list.
Note that it does not automatically append a trailing dot at the end of the domain.
Examples:
1> dns_domain:join([~"www", ~"example", ~"com"], subdomain).
~"www.example.com"
2> dns_domain:join([~"test.label", ~"com"], subdomain).
~"test\\.label.com"
3> dns_domain:join([~"test\\label", ~"com"], subdomain).
~"test\\\\label.com"
4> dns_domain:join([], subdomain).
<<>>
5> dns_domain:join([], fqdn).
~"."
5> dns_domain:join([~"example"], fqdn).
~"example."
Split domain name into labels.
Converts a domain name string into a list of labels. Handles escaped dots and backslashes, removing escape sequences from the resulting labels.
Returns an empty list for empty names or root (single dot).
Raises {invalid_dname, empty_label} if the name contains contiguous dots.
Examples:
1> dns_domain:split(~"www.example.com").
[~"www", ~"example", ~"com"]
2> dns_domain:split(~"example.com.").
[~"example", ~"com"]
3> dns_domain:split(~"test\.label.com").
[~"test.label", ~"com"]
4> dns_domain:split(<<>>).
[]
5> dns_domain:split(~"example..com").
** exception error: {invalid_dname, empty_label}
Returns provided name with case-insensitive characters in lowercase.
Returns provided name with case-insensitive characters in uppercase.
Convert domain name to wire format.
Converts a domain name string to DNS wire format binary. The wire format consists of length-prefixed labels followed by a null byte terminator.
Raises {label_too_long, Label} if any label exceeds 63 bytes.
Raises name_too_long if the total encoded name exceeds 255 bytes.
Raises {invalid_dname, empty_label} if the name contains empty labels
(contiguous dots).
Returns <<0>> for empty names or root.
Examples:
1> dns_domain:to_wire(~"www.example.com").
<<3,119,119,119,7,101,120,97,109,112,108,101,3,99,111,109,0>>
2> dns_domain:to_wire(~"example.com").
<<7,101,120,97,109,112,108,101,3,99,111,109,0>>
3> dns_domain:to_wire(<<>>).
<<0>>
4> dns_domain:to_wire(~"example..com").
** exception error: {invalid_dname, empty_label}
-spec to_wire(compmap(), non_neg_integer(), dname()) -> {wire(), compmap()}.
Convert domain name to wire format with compression.
Converts a domain name to wire format, using DNS name compression to reduce message size. Maintains a compression map tracking previously encoded names and emits compression pointers when a name (or suffix) has been seen before.
CompMap is the compression map mapping label sequences to their positions.
Pos is the current position in the message where encoding starts.
Returns {Wire, NewCompMap} where Wire is the encoded name and NewCompMap
is the updated compression map.
Use this when encoding DNS messages where multiple names may share suffixes
(e.g., example.com and www.example.com).
Examples:
1> CompMap = #{}, Pos = 0.
2> {Wire1, CompMap1} = dns_domain:to_wire(CompMap, Pos, ~"example.com").
{<<7,101,120,97,109,112,108,101,3,99,111,109,0>>, #{...}}
3> Pos2 = byte_size(Wire1).
4> {Wire2, _} = dns_domain:to_wire(CompMap1, Pos2, ~"www.example.com").
{<<3,119,119,119,192,0>>, #{...}}
%% Wire2 uses compression pointer (192,0) pointing to position 0
5> {Wire3, _} = dns_domain:to_wire(CompMap1, Pos2, ~"example.com").
{<<192,0>>, #{...}}
%% Wire3 is just a compression pointer since the name was seen before
Unescape a label by removing escape sequences.
Reverses the escaping performed by escape_label/1. Converts \\. back to .
and \\\\ back to \\. Returns the original label unchanged if no unescaping
is needed.
Use this when parsing labels that may contain escaped characters.
Examples:
1> dns_domain:unescape_label(~"test").
~"test"
2> dns_domain:unescape_label(~"test\\.label").
~"test.label"
3> dns_domain:unescape_label(~"test\\\\label").
~"test\\label"
4> dns_domain:unescape_label(~"test\\\\.label").
~"test\\.label"