All Projects → nerves-networking → mdns_lite

nerves-networking / mdns_lite

Licence: Apache-2.0 license
A simple, no frills mDNS implementation in Elixir

Programming Languages

elixir
2628 projects
erlang
1774 projects

Projects that are alternatives of or similar to mdns lite

playercast
Cast to media player and control playback remotely.
Stars: ✭ 46 (+58.62%)
Mutual labels:  mdns
shoehorn
Handle OTP application failures without restarting the Erlang VM
Stars: ✭ 36 (+24.14%)
Mutual labels:  nerves
Nerves
Craft and deploy bulletproof embedded software in Elixir
Stars: ✭ 1,778 (+6031.03%)
Mutual labels:  nerves
nerves thermal camera
Thermal camera imaging with Elixir, Nerves, Raspberry Pi, and a MLX90640 sensor
Stars: ✭ 28 (-3.45%)
Mutual labels:  nerves
hap
A HomeKit Accessory Protocol (HAP) Implementation for Elixir
Stars: ✭ 50 (+72.41%)
Mutual labels:  nerves
scenic asteroids
A toy Asteroids clone written in Elixir with the Scenic UI library
Stars: ✭ 42 (+44.83%)
Mutual labels:  nerves
Francis
Bonjour browser for macOS and iOS
Stars: ✭ 25 (-13.79%)
Mutual labels:  mdns
libmicrodns
Minimal mDNS resolver (and announcer) cross-platform library
Stars: ✭ 48 (+65.52%)
Mutual labels:  mdns
grovepi
Use the GrovePi in Elixir
Stars: ✭ 46 (+58.62%)
Mutual labels:  nerves
pigpiox
An Elixir wrapper around pigpiod for the Raspberry PI
Stars: ✭ 29 (+0%)
Mutual labels:  nerves
elixir-opencv
OpenCv NIF Bindings for Erlang/Elixir.
Stars: ✭ 30 (+3.45%)
Mutual labels:  nerves
nerves system ev3
Base Nerves system configuration for the Lego EV3
Stars: ✭ 23 (-20.69%)
Mutual labels:  nerves
nerves livebook
Develop on embedded devices with Livebook and Nerves
Stars: ✭ 135 (+365.52%)
Mutual labels:  nerves
Super-Simple-RGB-WiFi-Lamp
A project based on the ESP8266 and WS2812b
Stars: ✭ 61 (+110.34%)
Mutual labels:  mdns
inky
A library for managing Inky e-ink displays from Elixir.
Stars: ✭ 60 (+106.9%)
Mutual labels:  nerves
docker-mdns
Simple mDNS/ZeroConf demonstration of a nginx container, acessible at http://nginx.local
Stars: ✭ 25 (-13.79%)
Mutual labels:  mdns
nerves init gadget
Simple initialization for devices running Nerves
Stars: ✭ 53 (+82.76%)
Mutual labels:  nerves
VCVRack-Holon.ist
Holon.ist Receiver for VCV Rack
Stars: ✭ 13 (-55.17%)
Mutual labels:  mdns
mix tasks upload hotswap
Deploy local code changes to the remote node(s) in a hot-code-swapping manner
Stars: ✭ 31 (+6.9%)
Mutual labels:  nerves
kiwi
Kiwi turns your Pimoroni Keybow into a fully customizable poor-man's Elgato Stream Deck!
Stars: ✭ 40 (+37.93%)
Mutual labels:  nerves

MdnsLite

Hex version CircleCI

MdnsLite is a simple, limited, no frills implementation of an mDNS (Multicast Domain Name System) client and server. It operates like DNS, but uses multicast instead of unicast so that any computer on a LAN can help resolve names. In particular, it resolves hostnames that end in .local and provides a way to advertise and discovery service.

MdnsLite is intended for environments like on Nerves devices that do not already have an mDNS service. If you're running on desktop Linux or on MacOS, you already have mDNS support and do not need MdnsLite.

Features of MdnsLite:

  • Advertise <hostname>.local and aliases for ease of finding devices
  • Static (application config) and dynamic service registration
  • Support for multi-homed devices. For example, mDNS responses sent on a network interface have the expected IP addresses for that interface.
  • DNS bridging so that Erlang's built-in DNS resolver can look up .local names via mDNS.
  • Caching of results and advertisements seen on the network
  • Integration with VintageNet and Erlang's :inet application for network interface monitoring
  • Easy inspection of mDNS record tables to help debug service discovery issues

MdnsLite is included in NervesPack so you might already have it!

Configuration

A typical configuration in the config.exs file looks like:

config :mdns_lite,
  # Advertise `hostname.local` on the LAN
  hosts: [:hostname],
  # If instance_name is not defined it defaults to the first hostname
  instance_name: "Awesome Device",
  services: [
    # Advertise an HTTP server running on port 80
    %{
      id: :web_service,
      protocol: "http",
      transport: "tcp",
      port: 80,
    },
    # Advertise an SSH daemon on port 22
    %{
      id: :ssh_daemon,
      protocol: "ssh",
      transport: "tcp",
      port: 22,
    }
  ]

The services section lists the services that the host offers, such as providing an HTTP server. Specifying a protocol, transport and port is usually the easiest way. The protocol and transport get combined to form the service type that's actually advertised on the network. For example, a "tcp" transport and "ssh" protocol will end up as "_ssh._tcp" in the advertisement. If you need something custom, specify :type directly. Optional fields include :id, :weight, :priority, :instance_name and :txt_payload. An :id is needed to remove the service advertisement at runtime. If not specified, :instance_name is inherited from the top-level config. A :txt_payload is a list of "<key>=<value>" string that will be advertised in a TXT DNS record corresponding to the service.

See MdnsLite.Options for information about all application environment options.

It's possible to change the advertised hostnames, instance names and services at runtime. For example, to change the list of advertised hostnames, run:

iex> MdnsLite.set_hosts([:hostname, "nerves"])
:ok

To change the advertised instance name:

iex> MdnsLite.set_instance_name("My Other Awesome Device")
:ok

Here's how to add and remove a service at runtime:

iex> MdnsLite.add_mdns_service(%{
    id: :my_web_server,
    protocol: "http",
    transport: "tcp",
    port: 80,
  })
:ok
iex> MdnsLite.remove_mdns_service(:my_web_server)
:ok

Client

MdnsLite.gethostbyname/1 uses mDNS to resolve hostnames. Here's an example:

iex> MdnsLite.gethostbyname("my-laptop.local")
{:ok, {172, 31, 112, 98}}

If you just want mDNS to "just work" with Erlang, you'll need to enable MdnsLite's DNS Bridge feature and configure Erlang's DNS resolver to use it. See the DNS Bridge section for details.

Service discovery docs TBD...

DNS Bridge configuration

MdnsLite can start a DNS server to respond to .local queries. This enables code that has no knowledge of mDNS to resolve mDNS queries. For example, Erlang/OTP's built-in DNS resolver doesn't know about mDNS. It's used to resolve hosts for Erlang distribution and pretty much any code using :gen_tcp and :gen_udp. MdnsLite's DNS bridge feature makes .local hostname lookups work for all of this. No code modifications required.

Note that this feature is useful on Nerves devices. Erlang/OTP can use the system name resolver on desktop Linux and MacOS. The system name resolver should already be hooked up to an mDNS resolver there.

To set this up, you'll need to enable the DNS bridge on MdnsLite and then set up the DNS resolver to use it first. Here are the options for the application environment:

config :mdns_lite,
  dns_bridge_enabled: true,
  dns_bridge_ip: {127, 0, 0, 53},
  dns_bridge_port: 53,
  dns_bridge_recursive: true

config :vintage_net,
  additional_name_servers: [{127, 0, 0, 53}]

The choice of running the DNS bridge on 127.0.0.53:53 is mostly arbitrary. This is the default.

There is an issue on Nerves and Linux that you may hit if the :mdns_lite application is not running. The Erlang DNS resolver calls connect to the IP address of the DNS server and then calls connect again to the next one. The second connect call fails when the first one is a 127.0.0.x address. See Issue 5092. Setting dns_bridge_recursive: true works around this issue.

Update: Issue 5092 has been fixed in Erlang/OTP 24.1 and you can safely use dns_bridge_recursive: false in that version or later.

Debugging

MdnsLite maintains a table of records that it advertises and a cache per network interface. The table of records that it advertises is based solely off its configuration. Review it by running:

iex> MdnsLite.Info.dump_records
<interface_ipv4>.in-addr.arpa: type PTR, class IN, ttl 120, nerves-2e6d.local
<interface_ipv6>.ip6.arpa: type PTR, class IN, ttl 120, nerves-2e6d.local
_epmd._tcp.local: type PTR, class IN, ttl 120, nerves-2e6d._epmd._tcp.local
_services._dns-sd._udp.local: type PTR, class IN, ttl 120, _epmd._tcp.local
_services._dns-sd._udp.local: type PTR, class IN, ttl 120, _sftp-ssh._tcp.local
_services._dns-sd._udp.local: type PTR, class IN, ttl 120, _ssh._tcp.local
_sftp-ssh._tcp.local: type PTR, class IN, ttl 120, nerves-2e6d._sftp-ssh._tcp.local
_ssh._tcp.local: type PTR, class IN, ttl 120, nerves-2e6d._ssh._tcp.local
nerves-2e6d._epmd._tcp.local: type SRV, class IN, ttl 120, priority 0, weight 0, port 4369, nerves-2e6d.local.
nerves-2e6d._epmd._tcp.local: type TXT, class IN, ttl 120,
nerves-2e6d._sftp-ssh._tcp.local: type SRV, class IN, ttl 120, priority 0, weight 0, port 22, nerves-2e6d.local.
nerves-2e6d._sftp-ssh._tcp.local: type TXT, class IN, ttl 120,
nerves-2e6d._ssh._tcp.local: type SRV, class IN, ttl 120, priority 0, weight 0, port 22, nerves-2e6d.local.
nerves-2e6d._ssh._tcp.local: type TXT, class IN, ttl 120,
nerves-2e6d.local: type A, class IN, ttl 120, addr <interface_ipv4>
nerves-2e6d.local: type AAAA, class IN, ttl 120, addr <interface_ipv6>

Note that some addresses have not been filled in. They depend on which network interface receives the query. The idea is that if a computer is looking for you on the Ethernet interface, you should give records with that Ethernet's interface rather than, say, the IP address of the WiFi interface.

MdnsLite's cache is filled with records that it sees advertised. It's basically the same, but can be quite large depending on the mDNS activity on a link. It looks like this:

iex> MdnsLite.Info.dump_caches
Responder: 172.31.112.97
  ...
Responder: 192.168.1.58
  ...

In memory

Peter Marks wrote and maintained the original version of mdns_lite.

License

Copyright (C) 2019-21 SmartRent

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].