mdns

package
v0.331.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 21, 2026 License: AGPL-3.0 Imports: 5 Imported by: 0

Documentation

Overview

Package mdns decodes Multicast DNS (mDNS) messages per RFC 6762 + the DNS-SD (DNS-Based Service Discovery) layer per RFC 6763. mDNS runs over UDP/5353 to multicast 224.0.0.251 (IPv4) or FF02::FB (IPv6 link-local) and is the **discovery layer of every Bonjour / Avahi / Linux Avahi / Windows-Service-Discovery IoT and macOS / iOS device stack**.

Operationally, mDNS is the canonical signal for enumerating consumer + prosumer IoT on a LAN:

  • **Apple ecosystem** — AirDrop (`_airdrop._tcp.local`), AirPrint (`_ipp._tcp.local` / `_printer._tcp.local`), AirPlay (`_airplay._tcp.local`), HomeKit (`_hap._tcp.local`), Apple TV (`_appletv-v2._tcp.local`), macOS file sharing (`_smb._tcp.local`, `_afpovertcp._tcp.local`).
  • **Streaming** — Chromecast (`_googlecast._tcp.local`), Spotify Connect (`_spotify-connect._tcp.local`), Sonos (`_sonos._tcp.local`), Roku (`_roku-rcp._tcp.local`).
  • **Smart home** — Philips Hue (`_hue._tcp.local`), HomeKit accessories, Plex (`_plexmediasvr._tcp.local`).
  • **Linux / Unix LAN discovery** — Avahi `_workstation._tcp.local` (every Avahi-enabled Linux box advertises here), `_sftp-ssh._tcp.local`, `_ssh._tcp.local`, `_http._tcp.local`.
  • **Developer tooling** — Docker swarm gossip, Kubernetes headless services in mDNS-augmented deployments, IDE remote-debug session brokers.

Wrap-vs-native judgement

Native. RFC 6762 + RFC 6763 are publicly available; mDNS
re-uses the RFC 1035 DNS wire format with two crucial
extensions: the **QU bit** (top bit of QCLASS in
questions — set when the questioner prefers a unicast
response) and the **Cache-Flush bit** (top bit of CLASS
in resource records — set when the answer should flush
previously-cached entries for the same name+type). The
DNS-SD layer is a naming convention on top — service
types follow `_<service>._<proto>.local` where `<proto>`
is `_tcp` or `_udp`. No crypto at the parse layer.

What this package covers

  • **DNS-style header** (RFC 1035 §4.1.1 / RFC 6762 §18, 12 bytes, big-endian): TransactionID + Flags + QD/AN/NS/AR counts. mDNS senders typically set TransactionID = 0 (replies do echo the ID for the rare unicast case).

  • **Flags field** (16 bits BE): bit 15 `QR` (0 = query, 1 = response); bits 11-14 `Opcode` (0 = QUERY — only value used in mDNS); bit 10 `AA` (Authoritative Answer — set in mDNS responses); bit 9 `TC` (Truncated); bits 0-3 `RCODE` (must be 0 in mDNS).

  • **DNS label-encoded name walker** (RFC 1035 §3.1 + §4.1.4 compression pointers): standard length-prefixed labels terminated by a 0x00 root. Compression pointers (high bits 11 in the first byte → bottom 14 bits = offset from message start) are followed up to 5 hops deep.

  • **Question record** with **QU bit** (RFC 6762 §5.4): encoded name + 2-byte Type + 2-byte QCLASS where the top bit (`0x8000`) is the QU flag (Question Unicast response preferred) and the bottom 15 bits are the normal class (typically 1 = IN). The decoder surfaces `qu_unicast` and the trimmed class as separate fields.

  • **Answer record** with **Cache-Flush bit** (RFC 6762 §10.2): encoded name + Type + CLASS (top bit `0x8000` = Cache-Flush; bottom 15 bits = normal class) + 4-byte TTL + 2-byte RDLength + RDLength bytes of RDATA.

  • **9+ entry resource-record Type name table**: 1 `A` (IPv4 host address) / 5 `CNAME` (Canonical Name) / 12 `PTR` (Pointer — DNS-SD service-type → instance-name mapping) / 16 `TXT` (Text — DNS-SD key=value capability metadata) / 28 `AAAA` (IPv6 host address) / 33 `SRV` (Service — DNS-SD instance → host:port + priority + weight) / 41 `OPT` (EDNS0; OPT pseudo-record carrying DNS-SD-extension data) / 47 `NSEC` (Next Secure — re-purposed in mDNS to mean "I have these record types for this name and only these").

  • **Per-RR-type RDATA decoders**:

  • `A` (Type 1) → 4-byte IPv4 address.

  • `AAAA` (Type 28) → 16-byte IPv6 address.

  • `PTR` (Type 12) / `CNAME` (Type 5) → DNS-encoded name (with compression-pointer traversal).

  • `SRV` (Type 33) → 2-byte Priority + 2-byte Weight

  • 2-byte Port + DNS-encoded Target. The classic `_<service>._<proto>.local` service entry; reveals the listening port + target hostname.

  • `TXT` (Type 16) → list of length-prefixed strings. Each string is typically `key=value` (DNS-SD §6); the decoder splits on the first `=` and surfaces `key`/`value` pairs alongside the raw strings.

  • Other types → RDATA bytes surfaced as raw hex.

What this package does NOT cover (deliberately out of scope)

  • **Network framing** — feed mDNS bytes after the UDP- datagram header strip (default UDP port 5353).
  • **NBNS / LLMNR** — the parallel Windows name-resolution protocols on UDP/137 and UDP/5355; the `nbns_decode` + `llmnr_decode` Specs handle those.
  • **Generic DNS** — UDP/53 traffic re-uses the same RFC 1035 wire format; the existing `dns_packet_decode` Spec covers it.
  • **DNS-SD service-type semantics beyond name detection** — the per-service-type schema (what TXT keys to expect for `_homekit._tcp.local` vs `_airplay._tcp.local`) is vendor-specific and out of scope; this decoder surfaces the TXT key=value pairs but does not interpret them.
  • **NSEC bitmap decode** — the NSEC RDATA carries a compressed type-bitmap indicating which RR types exist for the name; the decoder surfaces the next-name portion but leaves the type-bitmap as opaque hex.
  • **DNSSEC validation** — out of scope (mDNS rarely uses DNSSEC anyway).
  • **Multi-fragment reassembly** — mDNS responses can span multiple UDP packets when the answer set exceeds the MTU (RFC 6762 §11); the `TC` flag surfaces but the decoder does not reassemble across input messages.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Answer

type Answer struct {
	Name       string `json:"name"`
	Type       int    `json:"type"`
	TypeName   string `json:"type_name"`
	Class      int    `json:"class"`
	CacheFlush bool   `json:"cache_flush,omitempty"`
	TTL        uint32 `json:"ttl"`
	RDLength   int    `json:"rd_length"`

	// Per-type decoded RDATA (only the relevant subset
	// populated).
	IPv4         string            `json:"ipv4,omitempty"`
	IPv6         string            `json:"ipv6,omitempty"`
	NameData     string            `json:"name_data,omitempty"`
	SRVPriority  int               `json:"srv_priority,omitempty"`
	SRVWeight    int               `json:"srv_weight,omitempty"`
	SRVPort      int               `json:"srv_port,omitempty"`
	SRVTarget    string            `json:"srv_target,omitempty"`
	TXTStrings   []string          `json:"txt_strings,omitempty"`
	TXTKeyValues map[string]string `json:"txt_key_values,omitempty"`
	RDataHex     string            `json:"rdata_hex,omitempty"`
}

Answer is one entry in the answer / authority / additional section.

type Question

type Question struct {
	Name      string `json:"name"`
	Type      int    `json:"type"`
	TypeName  string `json:"type_name"`
	Class     int    `json:"class"`
	QUUnicast bool   `json:"qu_unicast,omitempty"`
}

Question is one entry in the mDNS question section.

type Result

type Result struct {
	TotalBytes int `json:"total_bytes"`

	// Header
	TransactionID uint16 `json:"transaction_id"`
	FlagsHex      string `json:"flags_hex"`
	QR            bool   `json:"qr_response"`
	Opcode        int    `json:"opcode"`
	AA            bool   `json:"aa_authoritative,omitempty"`
	TC            bool   `json:"tc_truncated,omitempty"`
	RCODE         int    `json:"rcode"`

	QDCount int `json:"qd_count"`
	ANCount int `json:"an_count"`
	NSCount int `json:"ns_count"`
	ARCount int `json:"ar_count"`

	Questions []Question `json:"questions,omitempty"`
	Answers   []Answer   `json:"answers,omitempty"`
}

Result is the structured decode of an mDNS message.

func Decode

func Decode(hexStr string) (*Result, error)

Decode parses an mDNS message from a hex string. Separators (':' '-' '_' whitespace) tolerated; '0x' prefix tolerated.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL