mdns

package module
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Jul 16, 2026 License: MIT Imports: 14 Imported by: 0

README

mdns — Go Multicast DNS (RFC 6762)

Go Reference Go Version Platforms License Created by

A complete from-scratch implementation of Multicast DNS (RFC 6762) in Go. No third-party mDNS libraries — only the Go standard library.

Install

go get github.com/topcheer/mdns

Quick Start

Register a service
package main

import (
    "fmt"
    "github.com/topcheer/mdns"
)

func main() {
    srv, _ := mdns.NewServer(mdns.DefaultConfig())
    srv.Start()
    defer srv.Close()

    srv.RegisterService(&mdns.ServiceInstance{
        Name: "My Web Server",
        Type: "_http._tcp",
        Port: 8080,
        Text: []string{"path=/", "version=1.0"},
    })

    fmt.Println("Service registered. Press Ctrl-C to stop.")
    select {}
}
Browse for services
srv, _ := mdns.NewServer(mdns.DefaultConfig())
srv.Start()
defer srv.Close()

browser, _ := srv.Browse("_http._tcp")
events, _ := browser.Start()
defer browser.Stop()

for ev := range events {
    switch ev.Action {
    case mdns.EventAdd:
        fmt.Printf("Found: %s at %s:%d\n",
            ev.Instance.Name, ev.Instance.Host, ev.Instance.Port)
    case mdns.EventRemove:
        fmt.Printf("Lost: %s\n", ev.Instance.Name)
    }
}
Resolve a hostname
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

ips, _ := srv.ResolveHost(ctx, "myhost.local.")
for _, ip := range ips {
    fmt.Println(ip)
}
One-shot lookup (no persistent server)
// Resolve a hostname without managing a Server
ips, _ := mdns.LookupHost(ctx, "myhost.local.", 0)

// Discover services without managing a Server
instances, _ := mdns.LookupService(ctx, "_http._tcp", 0)

Configuration

config := mdns.Config{
    Port:       mdns.DefaultPort,  // 53533 (configurable)
    Domain:     "local.",          // mDNS domain suffix
    EnableIPv6: false,             // enable IPv6 multicast
    HostName:   "myhost",          // empty = system hostname
    LogFunc:    func(f string, a ...any) { log.Printf(f, a...) },
}

Logging and Warnings

The library never writes to the terminal directly. All output is delivered through two optional callbacks in Config:

LogFunc — debug logging
cfg := mdns.DefaultConfig()
cfg.LogFunc = func(format string, args ...any) {
    log.Printf("[mdns] "+format, args...)
}
WarningFunc — health alerts

WarningFunc is called when the library detects a non-fatal issue that may affect functionality. The most common warning is multicast_route_broken, fired when the system's multicast route is corrupted (typically by a VPN).

cfg := mdns.DefaultConfig()
cfg.WarningFunc = func(w mdns.Warning) {
    switch w.Code {
    case "multicast_route_broken":
        log.Printf("[mdns] WARNING: %s (%s)", w.Message, w.Hint)
    }
}

If WarningFunc is nil, warnings fall back to LogFunc. If both are nil, the library is completely silent.

// slog (Go 1.21+)
cfg.LogFunc = func(format string, args ...any) {
    slog.Debug(fmt.Sprintf(format, args...))
}
cfg.WarningFunc = func(w mdns.Warning) {
    slog.Warn(w.Message, "code", w.Code, "hint", w.Hint)
}

// zap
cfg.LogFunc = func(format string, args ...any) {
    logger.Debug(fmt.Sprintf(format, args...))
}
cfg.WarningFunc = func(w mdns.Warning) {
    logger.Warn(w.Message, zap.String("code", w.Code), zap.String("hint", w.Hint))
}

// logrus
cfg.LogFunc = func(format string, args ...any) {
    logrus.Debugf(format, args...)
}
cfg.WarningFunc = func(w mdns.Warning) {
    logrus.WithField("code", w.Code).Warn(w.Message)
}
Manual health check

You can also check multicast route health before starting a server:

if err := mdns.CheckMulticastRoute(); err != nil {
    log.Printf("mDNS will not work: %v", err)
}

API Reference

Core Types
Type Description
Server Core mDNS engine. Create with NewServer().
Config Server configuration. Use DefaultConfig() for defaults.
ServiceInstance Service to register via Server.RegisterService().
Browser Service discovery via Server.Browse().
ServiceInstanceInfo Resolved service details (name, host, port, IPs, TXT).
ServiceEvent Event delivered to Browser subscribers.
Key Methods
Method Description
NewServer(Config) Create a new mDNS server
Server.Start() Begin listening and background tasks
Server.RegisterService(*ServiceInstance) Register + probe + announce a service
Server.UnregisterService(*ServiceInstance) Unregister + send goodbye
Server.Browse(serviceType) Create a service browser
Server.ResolveHost(ctx, host) Resolve hostname to IP addresses
Browser.Start() Begin browsing, returns event channel
Browser.Stop() Stop browsing
Browser.Instances() Get all currently known instances
Server.Cache() Access the record cache
Server.HostIPs() Get this host's IP addresses
LookupHost(ctx, host, port) One-shot hostname resolution
LookupService(ctx, type, port) One-shot service discovery

RFC 6762 Compliance

Feature Section Status
.local. domain, multicast addresses 224.0.0.251 / FF02::FB §3
One-Shot query with QU bit (unicast response) §5.1, §5.4
Exponential backoff browsing (1s → 2s → ... → 1h) §5.2
Cache maintenance queries at 80% TTL §5.2
Reverse address mapping (IPv4 .in-addr.arpa. + IPv6 .ip6.arpa.) §4
Unique record immediate response (<10ms) §6
Shared record random response delay (20–120ms) §6
NSEC negative responses §6.1
Additional records in PTR responses (SRV/TXT/A) §6.2
Multicast rate limiting (1s per record) §6
Legacy unicast query support §6.7
Known-Answer Suppression with TTL ≥50% check §7.1
TC bit multipacket known-answer §7.2
Probing (3 × 250ms + random delay) §8.1
Simultaneous probe tiebreaking (lexicographic rdata) §8.2
Hostname A/AAAA probing §8.1
Announcing (double-announce) §8.3
Conflict resolution with auto-rename §9
Goodbye (TTL=0) §10.1
Cache-flush bit §10.2
Passive observation of failures §10.5
Source address verification (local subnet) §11
Packet validation (opcode=0, rcode=0) §18.14
DNS-SD service enumeration (_services._dns-sd._udp) RFC 6763
Design Choices
  • IPv4 priority: Service advertisement always puts IPv4 addresses first.
  • Same-machine multi-instance: Each instance auto-generates a unique hostname.
  • Configurable port: Default 53533 (standard mDNS uses 5353).

Demo Application

The cmd/mdns-demo binary is a zero-config tool that registers a service and discovers peers:

# Build
go build -o mdns-demo ./cmd/mdns-demo

# Run (just works — registers + browses automatically)
./mdns-demo

# Custom service
./mdns-demo -service _http._tcp -port 8080 -name "My Server"

# Verbose logging
./mdns-demo -log

Run on multiple terminals or machines — they discover each other automatically.

Pre-built binaries for all platforms are in Releases.

Troubleshooting

sendto: no route to host on multicast send

mDNS sends UDP packets to 224.0.0.251 (IPv4 multicast). If the OS multicast route is missing or corrupted, all sends fail with this error.

Quick diagnosis:

# Check for the 224.0.0.0/4 multicast route
netstat -rn | grep 224

# Healthy output looks like:
#   224.0.0/4          link#12            UmCS                  en1
#   224.0.0.251        1:0:5e:0:0:fb      UHmLWI                en1

# If you see a "!" flag, the route is REJECT (broken):
#   224.0.0/4          link#12            UmCS                  en1      !

Common causes and fixes:

Cause How to fix
VPN / network extension (sing-box, Tailscale, Clash, WireGuard, etc.) installed a RTF_REJECT route over 224.0.0.0/4 Disconnect or quit the VPN client. If the route persists after disconnect, reboot.
Missing multicast route (some minimal Linux setups, Docker-only hosts) sudo route add -net 224.0.0.0/4 dev eth0 (Linux) or sudo route add -net 224.0.0.0/4 -interface en0 (macOS)
Firewall blocking multicast (pf, iptables, Windows Firewall, Little Snitch) Allow outbound UDP to 224.0.0.0/4 on port 5353. On macOS: sudo pfctl -d temporarily to test.
Wrong interface selected (machine has Docker / VM bridge adapters) Pass Config{Interfaces: []string{"en0"}} to use a specific interface.
No active network interface (Wi-Fi off, cable unplugged) Connect to a network first. mDNS only works on active local links.

macOS-specific: VPN network extensions corrupting multicast routes

VPN clients that use the NetworkExtension framework (sing-box, Tailscale, Clash with TUN mode, etc.) can install a reject route on 224.0.0.0/4 that persists even after the VPN is disconnected. This is a known macOS issue.

# Verify the reject flag
netstat -rn | grep "224.0.0/4"
# If you see "!" at the end, the route is rejected

# Fix option 1: Reboot (cleanest)
sudo reboot

# Fix option 2: Manually delete and re-add the route
sudo route delete 224.0.0.0/4
sudo route add -net 224.0.0.0/4 -interface en0

Linux-specific: missing multicast route on headless / container hosts

# Add persistent multicast route
sudo ip route add 224.0.0.0/4 dev eth0

# Verify
ip route show | grep 224
Service not discovered by peers
  • Ensure both machines are on the same L2 network (same switch / Wi-Fi). mDNS multicast does not cross subnets without an mDNS reflector (e.g. Avahi reflector).
  • Check that port 5353 UDP is not blocked by a firewall on either machine.
  • If using a custom port via Config.Port, all peers must use the same port.
  • Run with -log flag (./mdns-demo -log) to see debug output.
Multiple instances on the same machine

Each instance automatically generates a unique hostname (hostname-<PID>), so running multiple mdns-demo processes in different terminals works out of the box. They will discover each other via multicast loopback.

Architecture

mdns/
├── doc.go                  # Package documentation
├── config.go               # Config, ServiceInstance, ServiceInstanceInfo
├── dns_name.go             # DNS name encoding/decoding (RFC 1035 compression)
├── dns_rr.go               # Resource records: A, AAAA, PTR, SRV, TXT, NSEC
├── dns_message.go          # DNS message pack/unpack
├── multicast.go            # Cross-platform multicast connection
├── multicast_unix.go       # macOS/Linux socket setup
├── multicast_windows.go    # Windows socket setup
├── sockopts_{darwin,linux,windows}.go  # Platform SO_REUSEPORT
├── cache.go                # Record cache with TTL + cache-flush
├── server.go               # Core engine: query/response/probe/conflict
├── service.go              # Registration: probing, announcing, goodbye
├── browser.go              # Discovery: browse, backoff, known-answer, maintenance
├── mdns.go                 # Public API: NewServer, LookupHost, LookupService
├── *_test.go               # Unit + integration tests (24 tests)
└── cmd/mdns-demo/          # Zero-config demo application

Testing

# Unit + integration tests with race detector
go test -race ./...

# Run with verbose output
go test -v -race ./...

All 24 tests pass with the -race flag enabled.

Cross-Platform Compilation

GOOS=darwin  GOARCH=arm64 go build -o mdns-demo-darwin-arm64  ./cmd/mdns-demo
GOOS=darwin  GOARCH=amd64 go build -o mdns-demo-darwin-amd64  ./cmd/mdns-demo
GOOS=linux   GOARCH=amd64 go build -o mdns-demo-linux-amd64   ./cmd/mdns-demo
GOOS=linux   GOARCH=arm64 go build -o mdns-demo-linux-arm64   ./cmd/mdns-demo
GOOS=windows GOARCH=amd64 go build -o mdns-demo-windows-amd64 ./cmd/mdns-demo
GOOS=windows GOARCH=arm64 go build -o mdns-demo-windows-arm64 ./cmd/mdns-demo

License

MIT

Documentation

Overview

Package mdns implements Multicast DNS (mDNS) as specified in RFC 6762, providing zero-configuration service discovery on local networks.

This is a from-scratch implementation with no third-party dependencies — only the Go standard library is used.

Quick Start

Register a service and discover peers:

srv, _ := mdns.NewServer(mdns.DefaultConfig())
srv.Start()
defer srv.Close()

// Advertise a service
srv.RegisterService(&mdns.ServiceInstance{
    Name: "My Printer",
    Type: "_ipp._tcp",
    Port: 631,
})

// Browse for services
browser, _ := srv.Browse("_ipp._tcp")
events, _ := browser.Start()
defer browser.Stop()

for ev := range events {
    if ev.Action == mdns.EventAdd {
        fmt.Printf("Found: %s on %s:%d\n",
            ev.Instance.Name, ev.Instance.Host, ev.Instance.Port)
    }
}

Key Types

RFC 6762 Compliance RFC 6762 Compliance" aria-label="Go to RFC 6762 Compliance">¶

This implementation covers all core sections of RFC 6762:

  • Probing (§8.1) with simultaneous probe tiebreaking (§8.2)
  • Conflict resolution with auto-rename (§9)
  • Announcing — double-announce after probe (§8.3)
  • Goodbye — TTL=0 on shutdown (§10.1)
  • Cache-flush bit semantics (§10.2)
  • Known-Answer Suppression with TTL check (§7.1)
  • TC bit multipacket queries (§7.2)
  • Exponential backoff browsing (§5.2)
  • Cache maintenance queries at 80% TTL (§5.2)
  • One-shot queries with QU bit (§5.1, §5.4)
  • NSEC negative responses (§6.1)
  • Reverse address mapping IPv4+IPv6 (§4)
  • Passive observation of failures (§10.5)
  • Source address verification (§11)
  • Legacy unicast query support (§6.7)
  • Multicast rate limiting (§6)
  • Packet validation opcode/rcode (§18.14)
  • DNS-SD service enumeration (RFC 6763)

IPv4 addresses are prioritized for service advertisement. Multiple instances on the same machine are fully supported.

Cross-Platform Support

Builds for macOS (amd64/arm64), Linux (amd64/arm64), and Windows (amd64/arm64).

Index

Constants

View Source
const (
	EventAdd    = 1
	EventRemove = 2
)

EventAdd and EventRemove indicate whether a service appeared or disappeared.

View Source
const (
	DefaultHostTTL     = 120 * time.Second // A/AAAA/SRV records
	DefaultOtherTTL    = 75 * time.Second  // PTR/TXT records
	DefaultProbeWait   = 250 * time.Millisecond
	DefaultProbeCount  = 3
	DefaultAnnounceTTL = time.Second
)

DefaultTTL values from RFC 6762 §10.

View Source
const (
	TypeA     uint16 = 1   // IPv4 address
	TypeNS    uint16 = 2   // Name Server
	TypeCNAME uint16 = 5   // Canonical Name
	TypeSOA   uint16 = 6   // Start of Authority
	TypePTR   uint16 = 12  // Domain Name Pointer
	TypeTXT   uint16 = 16  // Text
	TypeAAAA  uint16 = 28  // IPv6 address
	TypeSRV   uint16 = 33  // Service
	TypeOPT   uint16 = 41  // EDNS0 option
	TypeNSEC  uint16 = 47  // Next Secure (Negative cache)
	TypeAny   uint16 = 255 // Any / all records
)

RR type constants (DNS record types).

View Source
const (
	ClassIN   uint16 = 1   // Internet
	ClassNone uint16 = 254 // None (RFC 4034)
	ClassAny  uint16 = 255 // Any
)

RR class constants.

View Source
const DefaultDomain = "local."

DefaultDomain is the default mDNS domain.

View Source
const DefaultPort = 53533

DefaultPort is the default mDNS port (RFC 6762 §6.1 uses 5353; configurable — the user requested 53533 as the default).

View Source
const PacketBufferSize = 9000

PacketBufferSize is the max mDNS packet size (RFC 6762 §17 allows up to 9000, but the classic MTU-safe limit is 9000 for jumbo frames; we use 9000).

Variables

View Source
var (
	ErrNameTooLong    = errors.New("mdns: domain name too long (>255 bytes)")
	ErrLabelTooLong   = errors.New("mdns: label too long (>63 bytes)")
	ErrInvalidPointer = errors.New("mdns: invalid compression pointer")
	ErrPointerLoop    = errors.New("mdns: compression pointer loop detected")
	ErrTruncatedName  = errors.New("mdns: domain name is truncated")
)

Errors.

View Source
var (
	IPv4MulticastAddr = net.IPv4(224, 0, 0, 251)
	IPv6MulticastAddr = net.ParseIP("ff02::fb")
)

Default IPv4 and IPv6 mDNS multicast addresses (RFC 6762 §3).

Functions

func CheckMulticastRoute added in v1.3.0

func CheckMulticastRoute() error

CheckMulticastRoute tests whether the system can send multicast packets to the standard mDNS IPv4 multicast address (224.0.0.251).

It creates a temporary UDP socket, sets IP_MULTICAST_IF to the best detected LAN interface, and attempts to write a single byte. If the send fails — most commonly with "no route to host" — the multicast route is broken.

Common causes:

  • VPN network extensions (sing-box, Tailscale, Clash TUN mode) installing an RTF_REJECT route on 224.0.0.0/4 (macOS)
  • Missing multicast route on headless / container hosts (Linux)
  • Firewall blocking outbound multicast

Returns nil if the send succeeds, or an error describing the failure.

This function is safe to call before starting a Server. It is also called automatically during Server.Start().

func LookupHost

func LookupHost(ctx context.Context, host string, port int) ([]net.IP, error)

LookupHost resolves a hostname (e.g. "myhost.local.") to IP addresses using a one-shot mDNS query. It blocks until at least one address is found or the context is cancelled.

This is a convenience method that creates a temporary Server if needed. For repeated queries, use a persistent Server instance.

func RRType

func RRType(t uint16) string

RRType returns a human-readable string for common record types.

Types

type Browser

type Browser struct {
	// contains filtered or unexported fields
}

Browser discovers service instances of a given type on the network. It sends periodic multicast queries and collects responses.

func (*Browser) Instances

func (b *Browser) Instances() []*ServiceInstanceInfo

Instances returns all currently known service instances.

func (*Browser) Start

func (b *Browser) Start() (<-chan ServiceEvent, error)

Start begins the browsing loop.

func (*Browser) Stop

func (b *Browser) Stop()

Stop stops browsing and unregisters from the server.

type Cache

type Cache struct {
	// contains filtered or unexported fields
}

Cache is a thread-safe DNS record cache with TTL-based expiry. It implements the caching behaviour described in RFC 6762 §5.2 and §10.

func NewCache

func NewCache() *Cache

NewCache creates a new empty cache.

func (*Cache) AllRecords

func (c *Cache) AllRecords() []*ResourceRecord

AllRecords returns all non-expired records in the cache (for debugging).

func (*Cache) Expire

func (c *Cache) Expire() int

Expire purges all expired records from the cache.

func (*Cache) HasValidRecord

func (c *Cache) HasValidRecord(key CacheKey) bool

HasValidRecord returns true if the cache has a non-expired record for the key.

func (*Cache) KnownAnswers

func (c *Cache) KnownAnswers(name string, rrType uint16) []*ResourceRecord

KnownAnswers returns all cached records matching name+type whose remaining TTL is more than half of their original TTL. Used for Known-Answer Suppression (RFC 6762 §7.1).

func (*Cache) Lookup

func (c *Cache) Lookup(key CacheKey) []*ResourceRecord

Lookup returns all non-expired records matching the key.

func (*Cache) LookupName

func (c *Cache) LookupName(name string) []*ResourceRecord

LookupName returns all non-expired records for a given name (any type).

func (*Cache) RecordOriginalTTL

func (c *Cache) RecordOriginalTTL(key CacheKey) uint32

RecordOriginalTTL returns the original TTL of the first non-expired record matching the key.

func (*Cache) RecordRemainingTTL

func (c *Cache) RecordRemainingTTL(key CacheKey) uint32

RecordRemainingTTL returns the remaining TTL (in seconds) for the first non-expired record matching the key, or 0 if no record exists. Used by Browser to determine if a cached record needs refresh (RFC 6762 §5.2).

func (*Cache) Remove

func (c *Cache) Remove(key CacheKey)

Remove deletes all records matching the key.

func (*Cache) RemoveName

func (c *Cache) RemoveName(name string)

RemoveName removes all records for a given name.

func (*Cache) Upsert

func (c *Cache) Upsert(rr *ResourceRecord, from net.IP) bool

Upsert adds or updates a record in the cache. If cacheFlush is set (mDNS cache-flush bit), all existing records for the same name/type from a different source are removed (RFC 6762 §10.2). Returns true if the cache was modified.

type CacheKey

type CacheKey struct {
	Name string // lowercase
	Type uint16
}

CacheKey uniquely identifies a cached record by name + type.

type Config

type Config struct {
	// Port is the UDP port to listen on. Default: 53533.
	Port int

	// Domain is the mDNS domain suffix. Default: "local.".
	Domain string

	// EnableIPv6 enables IPv6 multicast. Default: false.
	EnableIPv6 bool

	// HostName is the host name to advertise (e.g. "myhost").
	// If empty, the system hostname is used.
	HostName string

	// LogFunc is called for debug logging. If nil, no logging is done.
	LogFunc func(format string, args ...any)

	// WarningFunc is called when the server detects a non-fatal issue
	// that may affect functionality (e.g. broken multicast route caused
	// by a VPN). If nil, warnings are logged via LogFunc (if set).
	WarningFunc WarningFunc

	// Interfaces restricts which network interfaces to use.
	// If empty, all active multicast interfaces are used.
	Interfaces []string
}

Config holds mDNS server configuration.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns a Config with sensible defaults.

type Header struct {
	ID      uint16
	Flags   uint16
	QDCount uint16 // number of questions
	ANCount uint16 // number of answer records
	NSCount uint16 // number of authority records
	ARCount uint16 // number of additional records
}

Header is the 12-byte DNS message header (RFC 1035 §4.1.1).

type Message

type Message struct {
	Header
	Questions   []*Question
	Answers     []*ResourceRecord
	Authorities []*ResourceRecord
	Additionals []*ResourceRecord
}

Message is a complete DNS message (header + sections).

func UnpackMessage

func UnpackMessage(data []byte) (*Message, error)

UnpackMessage parses a DNS message from wire format.

func (*Message) IsProbe

func (m *Message) IsProbe() bool

IsProbe returns true if this query is a probe (has authority section records). Per RFC 6762 §8.2, a probe query contains proposed records in the Authority Section that answer the question in the Question Section.

func (*Message) IsQuery

func (m *Message) IsQuery() bool

IsQuery returns true if the message is a query (QR=0).

func (*Message) IsResponse

func (m *Message) IsResponse() bool

IsResponse returns true if the message is a response (QR=1).

func (*Message) IsTruncated

func (m *Message) IsTruncated() bool

IsTruncated returns true if the TC bit is set (RFC 6762 §7.2).

func (*Message) IsValidmDNS

func (m *Message) IsValidmDNS() bool

IsValidmDNS checks basic mDNS compliance (RFC 6762 §18):

  • opcode MUST be 0 (QUERY)
  • RCode MUST be 0 (NOERROR)
  • responses MUST NOT have a non-zero RCode

func (*Message) Opcode

func (m *Message) Opcode() uint16

Opcode returns the 4-bit opcode field from the flags.

func (*Message) Pack

func (m *Message) Pack() ([]byte, error)

Pack serializes the message to wire format.

func (*Message) RCode

func (m *Message) RCode() uint16

RCode returns the 4-bit response code from the flags.

type MulticastConn

type MulticastConn struct {
	// contains filtered or unexported fields
}

MulticastConn wraps a pair of UDP sockets (IPv4 and optionally IPv6) for sending and receiving mDNS multicast traffic.

func NewMulticastConn

func NewMulticastConn(port int, enableIPv6 bool, interfaces []string) (*MulticastConn, error)

NewMulticastConn creates a multicast connection listening on the given port. It creates an IPv4 socket and optionally an IPv6 socket.

If interfaces is non-empty, only the named interfaces are used for multicast group membership and outgoing traffic; otherwise all active multicast interfaces are used.

func (*MulticastConn) Close

func (mc *MulticastConn) Close() error

Close shuts down all sockets and goroutines.

func (*MulticastConn) Packets

func (mc *MulticastConn) Packets() <-chan ReceivedPacket

Packets returns the channel for received packets.

func (*MulticastConn) Port

func (mc *MulticastConn) Port() int

Port returns the configured mDNS port.

func (*MulticastConn) SetWarningFunc added in v1.3.0

func (mc *MulticastConn) SetWarningFunc(fn WarningFunc)

SetWarningFunc registers a callback for runtime warnings (e.g. send failures). Called by Server.Start() after creating the MulticastConn.

func (*MulticastConn) WriteMulticast

func (mc *MulticastConn) WriteMulticast(data []byte) error

func (*MulticastConn) WriteMulticastV4

func (mc *MulticastConn) WriteMulticastV4(data []byte) (int, error)

WriteMulticastV4 sends data to the IPv4 multicast group.

func (*MulticastConn) WriteMulticastV6

func (mc *MulticastConn) WriteMulticastV6(data []byte) (int, error)

WriteMulticastV6 sends data to the IPv6 multicast group.

func (*MulticastConn) WriteTo

func (mc *MulticastConn) WriteTo(data []byte, addr *net.UDPAddr) (int, error)

WriteTo sends data to a specific unicast address.

type Question

type Question struct {
	Name  string // e.g. "_http._tcp.local."
	Type  uint16
	Class uint16 // without cache-flush bit (always 0 in questions)
}

Question is a DNS question entry.

type ReceivedPacket

type ReceivedPacket struct {
	Data []byte
	From *net.UDPAddr
}

ReceivedPacket holds a received UDP packet with its source address.

type ResourceRecord

type ResourceRecord struct {
	Name       string
	Type       uint16
	Class      uint16 // stored without cache-flush bit
	TTL        uint32
	CacheFlush bool // whether the cache-flush bit is set (for mDNS)

	// Type-specific data — only the relevant fields are populated.
	IP          net.IP   // A / AAAA
	Target      string   // PTR / CNAME / NS  (target domain name)
	Priority    uint16   // SRV
	Weight      uint16   // SRV
	Port        uint16   // SRV
	Text        []string // TXT
	NextDomain  string   // NSEC
	TypeBitMaps []uint16 // NSEC
	RawData     []byte   // for unrecognised types
}

ResourceRecord is a DNS resource record with type-specific RDATA.

func (*ResourceRecord) String

func (rr *ResourceRecord) String() string

String returns a human-readable representation of the RR.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is the core mDNS engine. It handles receiving and sending mDNS packets, responding to queries, probing for unique names, announcing services, and maintaining a record cache.

func NewServer

func NewServer(config Config) (*Server, error)

NewServer creates a new mDNS server with the given configuration.

func (*Server) Browse

func (s *Server) Browse(serviceType string) (*Browser, error)

Browse creates and starts a browser for the given service type. serviceType should be like "_http._tcp" or "_http._tcp.local.". The returned channel receives service events (add/remove). Call browser.Stop() to stop browsing.

func (*Server) Cache

func (s *Server) Cache() *Cache

Cache returns the server's record cache (for debugging/inspection).

func (*Server) Close

func (s *Server) Close() error

Close shuts down the server, sending goodbye packets for all registered services.

func (*Server) Config

func (s *Server) Config() Config

Config returns the server configuration.

func (*Server) HostIPs

func (s *Server) HostIPs() []net.IP

HostIPs returns the local IP addresses being advertised.

func (*Server) HostName

func (s *Server) HostName() string

HostName returns the hostname being advertised.

func (*Server) RegisterService

func (s *Server) RegisterService(svc *ServiceInstance) error

RegisterService registers a service instance with the mDNS server. The service will be probed for uniqueness, then announced on the network. Returns an error if a service with the same instance name is already registered.

func (*Server) ResolveHost

func (s *Server) ResolveHost(ctx context.Context, host string) ([]net.IP, error)

ResolveHost resolves a hostname using the running server's cache and network. IPv4 addresses are returned first, then IPv6 (if enabled).

func (*Server) Services

func (s *Server) Services() []*ServiceInstance

Services returns information about all registered services.

func (*Server) Start

func (s *Server) Start() error

Start begins listening for mDNS packets and starts all background tasks.

func (*Server) String

func (s *Server) String() string

String returns a debug string for the server state.

func (*Server) UnregisterService

func (s *Server) UnregisterService(svc *ServiceInstance) error

UnregisterService removes a previously registered service and sends goodbye.

type ServiceEvent

type ServiceEvent struct {
	Action   int                  // EventAdd or EventRemove
	Instance *ServiceInstanceInfo // the discovered service
}

ServiceEvent is sent to Browser subscribers when a service is found or lost.

type ServiceInstance

type ServiceInstance struct {
	// Type is the service type, e.g. "_http._tcp".
	Type string

	// Name is the instance name, e.g. "My Web Server".
	Name string

	// Domain is the domain, e.g. "local.".
	Domain string

	// Host is the hostname, e.g. "myhost.local.".
	// If empty, the server's hostname is used.
	Host string

	// Port is the service port.
	Port uint16

	// IPs is the list of IP addresses for the service.
	// If empty, the server's local addresses are used.
	IPs []net.IP

	// Text is the TXT record data.
	Text []string

	// Priority is the SRV priority.
	Priority uint16

	// Weight is the SRV weight.
	Weight uint16

	// TTL override (0 = use defaults).
	TTL uint32
}

ServiceInstance describes a service to be registered or discovered.

func (*ServiceInstance) InstanceName

func (s *ServiceInstance) InstanceName() string

InstanceName returns the full instance name, e.g. "My Web Server._http._tcp.local.".

func (*ServiceInstance) ServiceType

func (s *ServiceInstance) ServiceType() string

ServiceType returns the full service type domain, e.g. "_http._tcp.local.".

type ServiceInstanceInfo

type ServiceInstanceInfo struct {
	Name     string   // instance name (e.g. "My Web Server")
	Type     string   // service type (e.g. "_http._tcp.local.")
	Domain   string   // domain (e.g. "local.")
	Host     string   // hostname (e.g. "myhost.local.")
	Port     uint16   // service port
	IPs      []net.IP // IP addresses
	Text     []string // TXT record data
	Priority uint16   // SRV priority
	Weight   uint16   // SRV weight
}

ServiceInstanceInfo contains discovered service instance details.

func LookupService

func LookupService(ctx context.Context, serviceType string, port int) ([]*ServiceInstanceInfo, error)

LookupService discovers service instances of the given type. It blocks until the context is cancelled or the timeout expires.

func (*ServiceInstanceInfo) String

func (s *ServiceInstanceInfo) String() string

String returns a human-readable description of the service instance.

type Warning added in v1.3.0

type Warning struct {
	// Code is a machine-readable identifier for the warning.
	// Known codes:
	//   - "multicast_route_broken" — the system cannot send multicast packets
	//     (commonly caused by VPN network extensions corrupting the 224.0.0.0/4 route).
	Code string

	// Message is a human-readable description of the issue.
	Message string

	// Hint is a suggested action to resolve the issue.
	Hint string
}

Warning describes a non-fatal issue detected by the mDNS server. Warnings are delivered via Config.WarningFunc.

type WarningFunc added in v1.3.0

type WarningFunc func(Warning)

WarningFunc is a callback invoked when the server detects a non-fatal issue.

Directories

Path Synopsis
cmd
mdns-demo command
mdns-demo: Zero-config mDNS service announcer and discovery monitor.
mdns-demo: Zero-config mDNS service announcer and discovery monitor.
mdns-example command

Jump to

Keyboard shortcuts

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