This is an old revision of the document!
MulticastDNS mdnsd
Status: Last large piece started, the ability for clients (libmsnds) to talk to the daemon through a UNIX socket.
Parts completed
- Low level stack, both IPv4 and IPv6 (multicast join/leave, buffer management, packet (de)construction).
- Automatic interface add/remove, address add/remove, link state aware.
- Record cache.
- Configuration file with a variable system. (use of $(hostname), $(ifaddr4) etc)
- Record database (for self-claimed records).
- Probing and announcing works.
Goals
- Implement all MUST and SHOULD parts of draft-cheshire-dnsext-multicastdns.txt
- Should pass Apples Bonjour Conformance Test
- Expose a low-level client API through local UNIX sockets.
- Should handle interface addition/removal automatically.
- Should handle ip-address addition/removal automatically.
- Must support IPv6
Design
This is the overall principle, clients (programs) performs queries through a local unix socket to the responder daemon which in turn performs these queries on the network and provides a cache of previously asked records.
[Other mDNS responders] <--network (mdns protocol)--> [mdnsd] <--unix sockets--> [clients]
The responder itself is multi-threaded using a simple work-queue scheme. This has the advantage that threads can be completely disabled on systems where libpthread or threads in general aren't desired (small embedded systems in particular), while at the same time has the ability to take advantage of modern multicore processors.
This is some ugly ascii to demonstrate the general data flow within and around the application
---------------------
_____ | UNIX pipe socket(s) | <---> [Local client applications]
/ ---------------------
/ __________
--> [work queue] <---------[event dispatcher] <--I/O ready signal--- | |
| ___|_____ | NETWORK |
----| Workers | <--------------------- read from fdX----------------- | |
|w0,w1,wn | | |
|_________| ------------------> [output queue] --- write fdX ---> |__________|
The event dispatcher is implemented on top of kqueue(), it's used both for I/O ready signals and general timers. The purpose of the output queue is to aggregate several responses into one mdns packet (multicast allows packet sizes as large as the MTU of the network with an upper limit of 9000 bytes).
Static configuration
Configuration of “static” hosts will be done using /etc/mdnsd.conf (or similar)
This is an example of what an configuration file could look like. All variables are expanded and auto-updated when something changes. All resources are claimed unique on the network except those marked as shared. Interface specific statements can be wrapped inside a interface {} statement. Any number of res {} are allowed, even with the same type.
# A zone is only a way to avoid duplicate typing, one could have skipped it and simply
# used $(hostname).local. as the rrset.
zone "local." {
# A rrset holds a name and one or more resources, a resource type can hold multiple data sets
# The value after the rrset keyword serves as an identifier to this resource.
rrset hostname {
# Primary name
name = "$(hostname)";
# Alternative name if unable claim first as unique, any number of alt-statements can exist.
name = "$(hostname)-$(ifname)";
# This is a resource for the IN type A with the data set to $(ifaddrs4)
res A { data = "$(ifaddrs4)"; }
res AAAA { data = "$(ifaddrs6)"; }
}
}
# Announce PTR record for all configured ipv4 addresses, this will follow whatever name
# that is configured on the rrset with the identity "hostname".
rrset ip4-ptr {
name = "$(ifaddrs4)";
res PTR { record = hostname; }
}
# Announce PTR record for all configured ipv6 addresses, this works just as the the ipv4 case,
# the resource data will be whatever the rrset "hostname" has as its name.
rrset ip6-ptr {
name = "$(ifaddrs6)";
res PTR { record = hostname; }
}
#
# Announce a shared rrset with a PTR record on interface em0
#
interface "em0" {
rrset ssh-sd-rrset {
name = "ssh._tcp.local.";
shared;
res PTR { data = "$(hostname)._ssh._tcp.local."; }
}
}