This is an old revision of the document!
MulticastDNS mdnsd
Status: More or less feature complete, requires heavy testing.
TODO
- Implement proxy support.
- Implement “cache limit” to avoid memory exhausting DoS (throw out cached objects prematurely when number of cached entries reach a certain limit)
- Expand variable system with new variables ($(macaddr) etc)
- Fix the non-threaded version (broken)
- Stress testing (broken/malicious input, zzuf).
- More testing :)
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) | <--> [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 a 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."; }
}
}