Macula mDNS

Hex.pmHex Docs

Zero-configuration networking for Erlang/OTP applications using Multicast DNS.

This is a rebar3-compatible fork of shortishly/mdns, maintained by macula-io for use in the Macula HTTP/3 mesh platform.

Attribution

This library was originally created by Peter Morgan (shortishly).

Peter Morgan’s implementation provides an elegant, production-ready mDNS solution that enables automatic node discovery and mesh formation in local networks. All credit for the design, protocol implementation, and core functionality goes to Peter Morgan. This fork adds rebar3/hex.pm packaging support while preserving the original functionality.

Original Repository:github.com/shortishly/mdns

Overview

mDNS is an implementation of the Multicast DNS discovery protocol written in Erlang/OTP. It enables two or more Erlang nodes to:

Installation

Add macula_mdns to your rebar.config dependencies:

{deps, [
    {macula_mdns, "0.1.0"}
]}.

Note: The hex package is named macula_mdns, but the OTP application is mdns for compatibility with the original API.

Quick Start

Automatic Node Discovery

By default, mDNS advertises a service of type _erlang._tcp. You can view registered services using standard tools:

Linux (Avahi):

avahi-browse _erlang._tcp

macOS:

dns-sd -B _erlang._tcp

Automatic Mesh Formation

mDNS can automatically form an Erlang/OTP mesh network when MDNS_CAN_MESH is enabled.

On dev001.local:

MDNS_CAN_MESH=true rebar3 shell

On dev002.local:

MDNS_CAN_MESH=true rebar3 shell

After a short period, both machines will have automatically formed a mesh:

(mdns@dev001.local)1> nodes().
['mdns@dev002.local']
(mdns@dev002.local)1> nodes().
['mdns@dev001.local']

Configuration

mDNS can be configured via environment variables or application environment:

Application Config Environment Variable Default Description
can_advertiseMDNS_CAN_ADVERTISEtrue Advertise this node’s services
can_discoverMDNS_CAN_DISCOVERtrue Discover other nodes
can_meshMDNS_CAN_MESHfalse Auto-form Erlang cluster
environmentMDNS_ENVIRONMENTdev Environment tag (nodes must match to mesh)
multicast_addressMDNS_MULTICAST_ADDRESS224.0.0.251 mDNS multicast address
udp_portMDNS_UDP_PORT5353 mDNS UDP port
domainMDNS_DOMAIN.local mDNS domain
serviceMDNS_SERVICE_erlang._tcp Service type to advertise
ttlMDNS_TTL120 DNS record TTL (seconds)

Environment-Based Isolation

Only nodes that share the same environment value can be automatically meshed together. This allows multiple development environments on the same network:

# Team A's development cluster
MDNS_ENVIRONMENT=team_a MDNS_CAN_MESH=true rebar3 shell

# Team B's development cluster (won't mesh with Team A)
MDNS_ENVIRONMENT=team_b MDNS_CAN_MESH=true rebar3 shell

Subscribing to Advertisements

mDNS uses gproc‘s pub/sub pattern. Applications can subscribe to mDNS advertisements:

%% Subscribe to advertisement events
mdns:subscribe(advertisement).

%% In your gen_server handle_info/2:
handle_info({gproc_ps_event, advertisement, Info}, State) ->
    #{host := Host,
      node := Node,
      port := Port,
      env := Env} = Info,
    %% Handle the discovered node...
    {noreply, State}.

Advertisement Map Structure

Key Type Description
hostbinary() Hostname of the advertised node
nodeatom() Node name of the advertised node
portinteger() Distribution protocol port
envbinary() Environment of this node

Integration with Macula

In the Macula HTTP/3 mesh platform, mDNS provides optional local network discovery. When available, Macula uses mDNS to discover seed nodes on the local network, reducing the need for static seed configuration.

%% Macula checks for mDNS availability
case whereis(mdns_advertise_sup) of
    undefined ->
        %% mDNS not available, use DHT discovery
        ok;
    _Pid ->
        %% Subscribe to local node advertisements
        mdns:subscribe(advertisement)
end.

See Macula mDNS Setup Guide for integration details.

Architecture

┌─────────────────────────────────────────────────────┐
│                    mdns_sup                         │
│                  (supervisor)                       │
└────────────────┬────────────────────────────────────┘
                 │
     ┌───────────┴───────────┐
     │                       │
┌────▼─────────────┐  ┌──────▼────────────┐
│ mdns_advertise_  │  │ mdns_discover_    │
│ sup (supervisor) │  │ sup (supervisor)  │
└────────┬─────────┘  └────────┬──────────┘
         │                     │
    ┌────▼────┐           ┌────▼────┐
    │ mdns_   │           │ mdns_   │
    │advertise│           │discover │
    │ (worker)│           │ (worker)│
    └─────────┘           └─────────┘

Dependencies

Requirements

Troubleshooting

No nodes discovered

  1. Check multicast: Ensure multicast is enabled on your network
  2. Check firewall: Allow UDP 5353 inbound and outbound
  3. Check environment: Nodes must share the same MDNS_ENVIRONMENT
  4. Check cookie: Nodes must share the same Erlang cookie for meshing

Verify mDNS traffic

# Linux - capture mDNS packets
sudo tcpdump -i any port 5353

# Verify service is advertised
avahi-browse -a

License

Apache-2.0

Links