mdns

package module
v0.1.1-knt.0 Latest Latest
Warning

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

Go to latest
Published: May 30, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

README

mdns

Zero-configuration peer discovery for local networks using mDNS/DNS-SD.

import "github.com/kinet-labs/mdns"

Quick Start

// Create discovery for your service
disc := mdns.New("_myservice._tcp", "node-1", 8080,
    mdns.WithMetadata(map[string]string{
        "version": "1.0.0",
    }),
)

// Handle peer events
disc.OnPeer(func(peer *mdns.Peer, joined bool) {
    if joined {
        fmt.Printf("Peer joined: %s at %s\n", peer.NodeID, peer.Address())
    } else {
        fmt.Printf("Peer left: %s\n", peer.NodeID)
    }
})

// Start discovery
if err := disc.Start(); err != nil {
    log.Fatal(err)
}
defer disc.Stop()

// List all peers
for _, peer := range disc.Peers() {
    fmt.Printf("Found: %s\n", peer.NodeID)
}

Service Types

Service Type
FHE daemon _fhed._tcp
MPC daemon _mpcd._tcp
Kinet node _kinetd._tcp

Options

mdns.New(serviceType, nodeID, port,
    mdns.WithLogger(logger),           // Custom slog logger
    mdns.WithMetadata(map[string]string{}), // TXT record metadata
    mdns.WithBrowseInterval(5*time.Second), // How often to scan
    mdns.WithBrowseTimeout(3*time.Second),  // Scan timeout
    mdns.WithStaleTimeout(30*time.Second),  // When peers are lost
)

API

// Lifecycle
disc.Start() error
disc.Stop()

// Events
disc.OnPeer(func(peer *Peer, joined bool))

// Query
disc.Peers() []*Peer
disc.Peer(nodeID string) *Peer
disc.PeerCount() int
disc.NodeID() string
disc.ServiceType() string

// Peer
peer.Address() string      // "192.168.1.1:8080"
peer.Get("key") string     // Metadata lookup
peer.Age() time.Duration   // Since last seen
peer.Clone() *Peer

Documentation

Overview

Package mdns provides zero-configuration peer discovery for local networks. It uses mDNS/DNS-SD (Bonjour/Avahi) for automatic service advertisement and peer discovery without requiring manual configuration.

Package mdns provides zero-configuration peer discovery for local networks using mDNS/DNS-SD (Multicast DNS Service Discovery).

This enables automatic service advertisement and peer discovery without requiring manual configuration, DHCP, or central registries. Nodes on the same local network can find each other automatically.

Quick Start

import "github.com/kinet-labs/mdns"

// Create discovery for your service
disc := mdns.New("_myservice._tcp", "node-1", 8080,
	mdns.WithMetadata(map[string]string{
		"version": "1.0.0",
		"role":    "worker",
	}),
)

// Handle peer events
disc.OnPeer(func(peer *mdns.Peer, joined bool) {
	if joined {
		fmt.Printf("Peer joined: %s at %s\n", peer.NodeID, peer.Address())
	} else {
		fmt.Printf("Peer left: %s\n", peer.NodeID)
	}
})

// Start discovery
if err := disc.Start(); err != nil {
	log.Fatal(err)
}
defer disc.Stop()

// List all peers
for _, peer := range disc.Peers() {
	fmt.Printf("Found: %s (%s)\n", peer.NodeID, peer.Get("version"))
}

Service Types

Service types follow the DNS-SD naming convention:

_servicename._tcp  (for TCP services)
_servicename._udp  (for UDP services)

Examples:

  • _fhed._tcp - FHE daemon
  • _mpcd._tcp - MPC daemon
  • _kinetd._tcp - Kinet node
  • _http._tcp - HTTP server

How It Works

1. When Start() is called, the node registers itself via mDNS 2. A background goroutine periodically browses for other nodes 3. When new nodes are discovered, the OnPeer handler is called 4. When nodes go stale (not seen for 30s), they're removed

Use Cases

  • Zero-config FHE/MPC clusters
  • Kinet node discovery for local testnets
  • Local development environments
  • IoT device discovery
  • Microservice discovery in local networks
  • Testing distributed systems locally

Limitations

  • Only works on local networks (mDNS is link-local)
  • Requires multicast support on the network
  • Not suitable for cross-network discovery (use Consul, etcd, etc.)
Example
package main

import (
	"fmt"
	"log/slog"
	"os"
	"time"

	"github.com/kinet-labs/mdns"
)

func main() {
	// Create a discovery instance for your service
	disc := mdns.New("_myservice._tcp", "node-1", 8080,
		mdns.WithLogger(slog.New(slog.NewTextHandler(os.Stdout, nil))),
		mdns.WithMetadata(map[string]string{
			"version": "1.0.0",
			"role":    "worker",
		}),
	)

	// Handle peer events
	disc.OnPeer(func(peer *mdns.Peer, joined bool) {
		if joined {
			fmt.Printf("Peer joined: %s at %s (version: %s)\n",
				peer.NodeID, peer.Address(), peer.Get("version"))
		} else {
			fmt.Printf("Peer left: %s\n", peer.NodeID)
		}
	})

	// Start discovery
	if err := disc.Start(); err != nil {
		fmt.Printf("Failed to start: %v\n", err)
		return
	}
	defer disc.Stop()

	// List all discovered peers
	time.Sleep(100 * time.Millisecond) // Allow time for discovery
	fmt.Printf("Found %d peers\n", disc.PeerCount())
}

Index

Examples

Constants

View Source
const (
	// DefaultDomain is the mDNS domain
	DefaultDomain = "local."
	// DefaultBrowseInterval is how often to scan for peers
	DefaultBrowseInterval = 5 * time.Second
	// DefaultBrowseTimeout is the timeout for each browse operation
	DefaultBrowseTimeout = 3 * time.Second
	// DefaultStaleTimeout is when peers are considered gone
	DefaultStaleTimeout = 30 * time.Second
)

Variables

This section is empty.

Functions

func LocalIPs

func LocalIPs() []net.IP

LocalIPs returns the local IP addresses of this machine.

Types

type Discovery

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

Discovery handles mDNS-based peer discovery for zero-config clustering.

func New

func New(serviceType, nodeID string, port int, opts ...Option) *Discovery

New creates a new mDNS discovery instance.

serviceType should be in the format "_servicename._tcp" (e.g., "_fhed._tcp"). nodeID is a unique identifier for this node. port is the port this service is listening on.

func (*Discovery) NodeID

func (d *Discovery) NodeID() string

NodeID returns this node's ID.

func (*Discovery) OnPeer

func (d *Discovery) OnPeer(handler PeerHandler)

OnPeer sets the handler for peer events.

func (*Discovery) Peer

func (d *Discovery) Peer(nodeID string) *Peer

Peer returns a specific peer by ID, or nil if not found.

func (*Discovery) PeerCount

func (d *Discovery) PeerCount() int

PeerCount returns the number of known peers.

func (*Discovery) Peers

func (d *Discovery) Peers() []*Peer

Peers returns all currently known peers.

Example
package main

import (
	"fmt"

	"github.com/kinet-labs/mdns"
)

func main() {
	disc := mdns.New("_fhed._tcp", "node-1", 8448)

	if err := disc.Start(); err != nil {
		return
	}
	defer disc.Stop()

	// List all peers
	for _, peer := range disc.Peers() {
		fmt.Printf("Node: %s, Address: %s\n", peer.NodeID, peer.Address())
	}
}

func (*Discovery) ServiceType

func (d *Discovery) ServiceType() string

ServiceType returns the service type being advertised.

func (*Discovery) Start

func (d *Discovery) Start() error

Start begins advertising this node and discovering peers.

func (*Discovery) Stop

func (d *Discovery) Stop()

Stop stops advertising and discovering.

type Option

type Option func(*Discovery)

Option configures the Discovery instance.

func WithBrowseInterval

func WithBrowseInterval(interval time.Duration) Option

WithBrowseInterval sets how often to scan for peers.

func WithBrowseTimeout

func WithBrowseTimeout(timeout time.Duration) Option

WithBrowseTimeout sets the timeout for each browse operation.

func WithLogger

func WithLogger(logger *slog.Logger) Option

WithLogger sets a custom logger.

func WithMetadata

func WithMetadata(metadata map[string]string) Option

WithMetadata sets additional metadata to advertise.

func WithStaleTimeout

func WithStaleTimeout(timeout time.Duration) Option

WithStaleTimeout sets when peers are considered gone.

type Peer

type Peer struct {
	NodeID   string            // Unique node identifier
	Addr     string            // IP address
	Port     int               // Service port
	Metadata map[string]string // Additional metadata from TXT records
	LastSeen time.Time         // Last time this peer was seen
}

Peer represents a discovered node on the network.

func (*Peer) Address

func (p *Peer) Address() string

Address returns the full address string (host:port).

func (*Peer) Age

func (p *Peer) Age() time.Duration

Age returns how long since this peer was last seen.

func (*Peer) Clone

func (p *Peer) Clone() *Peer

Clone returns a deep copy of the peer.

func (*Peer) Get

func (p *Peer) Get(key string) string

Get returns a metadata value, or empty string if not found.

type PeerHandler

type PeerHandler func(peer *Peer, joined bool)

PeerHandler is called when peers join or leave the network.

Jump to

Keyboard shortcuts

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