MatterEx.MDNS.DNS (matter_ex v0.3.1)

Copy Markdown View Source

DNS wire format encoder/decoder per RFC 1035.

Pure functional module โ€” no side effects. Handles the subset of DNS needed for mDNS/DNS-SD service discovery.

Uses Erlang's :binary module for efficient parsing.

  • Name encoding with length-prefixed labels
  • Name decoding with pointer compression
  • Record types: A, AAAA, PTR, SRV, TXT
  • Complete message encode/decode

Example

# Encode a query
query = %{
  id: 0, qr: :query, aa: false,
  questions: [%{name: "_matterc._udp.local", type: :ptr, class: :in}],
  answers: [], authority: [], additional: []
}
binary = DNS.encode_message(query)

# Decode a message
{:ok, msg} = DNS.decode_message(binary)

Summary

Functions

Decode a binary DNS message.

Decode a domain name from a DNS message binary.

Decode TXT record data into a list of strings.

Encode a complete DNS message to binary.

Encode a domain name as length-prefixed labels.

Encode record-type-specific data (rdata).

Encode TXT record data from a list of strings.

Functions

decode_message(message)

@spec decode_message(binary()) :: {:ok, map()} | {:error, term()}

Decode a binary DNS message.

Returns {:ok, message_map} or {:error, reason}.

decode_name(message, offset)

@spec decode_name(binary(), non_neg_integer()) :: {String.t(), non_neg_integer()}

Decode a domain name from a DNS message binary.

Handles pointer compression (top 2 bits = 0b11 โ†’ offset pointer).

Returns {name, bytes_consumed} where bytes_consumed is the number of bytes read from the current position (not following pointers).

decode_txt(data)

@spec decode_txt(binary()) :: [String.t()]

Decode TXT record data into a list of strings.

encode_message(msg)

@spec encode_message(map()) :: binary()

Encode a complete DNS message to binary.

Message format

%{
  id: 0,
  qr: :query | :response,
  aa: boolean(),
  questions: [%{name: String.t(), type: atom(), class: :in}],
  answers: [record()],
  authority: [record()],
  additional: [record()]
}

Record format

%{
  name: String.t(),
  type: :a | :aaaa | :ptr | :srv | :txt,
  class: :in,
  cache_flush: boolean(),  # mDNS cache-flush bit (optional, default false)
  ttl: non_neg_integer(),
  data: term()             # type-specific
}

encode_name(name)

@spec encode_name(String.t()) :: binary()

Encode a domain name as length-prefixed labels.

Examples

iex> DNS.encode_name("local")
<<5, "local", 0>>

iex> DNS.encode_name("_matterc._udp.local")
<<9, "_matterc", 4, "_udp", 5, "local", 0>>

encode_rdata(atom, addr)

@spec encode_rdata(atom(), term()) :: binary()

Encode record-type-specific data (rdata).

encode_txt(entries)

@spec encode_txt([String.t()]) :: binary()

Encode TXT record data from a list of strings.

Each string is length-prefixed (1 byte length + string bytes). An empty list produces a single zero byte (RFC 6763 ยง6.1).

Examples

iex> DNS.encode_txt(["D=3840", "CM=1"])
<<6, "D=3840", 4, "CM=1">>