Discovery daemon (discd) is an implementation of the "Discovery Proxy for Multicast DNS-Based Service Discovery" specified as an internet draft of the IETF:


It dynamically maps multicast DNS services into the unicast DNS name space. This allows remote service discovery requests to be answered when the querier is not on the same link local network as the service provider.

Traditionally, zero-conf networking (or Bonjour as Apple Computer calls it) only provides answers to queries on the local network. This works great for home and small offfice (SOHO) networks but frustrates corporate and campus users when a device they want to communicate with is on another IP subnet for network scaling reasons.

By dynamically mapping the ever changing multicast DNS (mDNS) services into the unicast DNS namespace, it's possible to remotely query services through a proxy.

discd is that proxy.

more ...

iPhone/iPad TLS DNS Proxy

As Sarah Dickinson recently mentioned at DNS-OARC 27 in San Jose, CA, https://indico.dns-oarc.net/event/27/session/4/contribution/20, there is a work in progress for a TLS DNS Proxy for the Apple iPhone/iPad running iOS 11 and above. This uses the new DNS Proxy Network Extension and, when enabled, all DNS requests will be sent to a resolver over TLS.

I expect this new DNS Network Extension to be available for macOS in a future release as well.

Check back here in a bit to see the status and sign up for beta testing.


After receiving the following message on the Console, it appears that the only way to use the new DNS Proxy Network Extension in iOS 11 is through Mobile Device Management (MDM) Tools as a supervised device. This makes it impossible to install for the average user through the App Store.

Therefore, I am suspending this effort until this extension is more useful to a wider audience.

Oct  5 17:29:26 iPhone nehelper(NetworkExtension)[99] <Error>: -[NEHelperConfigurationManager:562  Warning: allowing creation/modification of a DNS proxy configuration on non-supervised device because the requesting app (DNS-TLS) is a development version. This will not be allowed for the production version of DNS-TLS


An Apple representative confirmed this is currently only for supervised devices but he seems to indicate they are considering opening this up to all devices but with no assurances or timeline:

I’ve just confirmed that, as things currently stand, NEDNSProxyProvider is limited to supervised devices.  We have a bug on file (r. 34843801) requesting that this restriction be lifted.  I suspect that this will happen but, as per usual, I can’t make any specific promises about that, or about the timeline for this change.  It certainly wouldn’t hurt for each of you to file your own bug describing your use case, how this restriction is affecting you, and what workarounds you’ve resorted to.
more ...

IETFers iPhone/iPad app

The IETFers iPhone/iPad app I wrote and maintain for the worldwide Internet Engineering Task Force (IETF) meetings is available for download in the Apple App Store.

If you have bug reports or feature requests, use the Settings panel and send me your wishes!


more ...



  • sdtest is a client simulation tool for testing DNS subscriptions. It supports both the older Long Lived Queries (LLQ) and the new replacement DNS Push Notifications.

  • sdtest will provide a command line interface (CLI) for interactive use or take commands from an input file. DNS Internet Class 'IN' is used in all cases. Optional arguments are in brackets.

discover-soa [--verbose] [--force_ipv4|--force_ipv6] 
             [--nameserver=<IPv4 or IPv6 address>]
             [--transport=udp|tcp|tls] _http._tcp.foo.bar.com
  • find the DNS server responsible for subscriptions for the service using type SOA then, if defined, issue an SRV query for _dns-llq.<proto>.<zone> or _dns-push-tls._tcp.<zone>.
  • default resolver will be used unless a nameserver is specified.
  • default ports used: UDP 53, TCP 53, TLS 853
  • can force IPv4 or IPv6. Otherwise, first IPv4 address is used
  • defaults to Push Notifications over TLS for all commands. Push over TCP is allowed for testing only, but should not be deployed in production. Push over UDP is not permitted.
test-session-signal [--verbose] [--nameserver=<IPv4 or IPv6 address>]
                    [--transport=tcp|tls] [--keepalive-interval=n]
  • Send a Session Signaling Keepalive request and get back the servers adjusted keepalive interval and idle timeout value.
  • If the nameserver doesn' support the session signaling opcode, NOTIMP will be returned.
  • Other errors could be returned for other reasons. Consult the spec.
test-session-signal-errors [--verbose] [--nameserver=<IPv4 or IPv6 address>]
                           [--transport=tcp|tls] [--keepalive-interval=n]
  • Test a server for different Session Signaling error conditions.
subscribe [--verbose] [--protocol=llq|push] [--target=<IPv4 or IPv6 address>]
          [--transport=udp|tcp|tls] [--type=PTR] _http._tcp.foo.bar.com
  • After subscription confirmation, any matching instances will be displayed. Transport defaults to UDP for LLQ and TLS for Push. type defaults to PTR. An succesor ordinal number subscription id is assigned to each subscription starting with '1'.
  • Discovery is performed for each subscription.
  • When an explicit subscription is issued, the connection will remain open until there is an explicit 'unsubscribe', an explicit 'close', or the test program exits and automatically closes all sockets.
  • By default, an SOA discovery followed by SRV discovery will locate the target to send the subscription to. The --target option can be used to bypass the discovery process.
show nameservers
  • Display current nameserver state.
show subscriptions
  • Display current subscription state.
unsubscribe [--verbose] [--protocol=llq|push]
            [--target=<IPv4 or IPv6 address>]
            [--transport=udp|tcp|tls] [--force] [--type=PTR]
            id=n | _http._tcp.foo.bar.com
  • must match the subscription exactly. Unsubscribe commands that do not match a current subscription will not be sent by default. Use --force to send them for testing Unsubscribe with no subscription. Use 'show subscriptions' to see current subscription state if specifying by id.
  • By default, the unsubscribe will be sent to the same address as the subscribe. This can be bypassed with the --target option.
close id=n
  • close the socket of an existing subscription without sending the unsubscribe. With TCP/TLS, the server will get signaled that the client has closed the socket. For LLQ over UDP, no indication will be sent. The id is discovered using 'show subscriptions'.
query-soa [--verbose] [--target=<IPv4 or IPv6 address>]
          [--transport=udp|tcp|tls] [--id=n] [--type=PTR]
  • Send query to SOA for record with type. Transport defaults to match subscription. While the subscription channel is intended for asynchronous responses from the server, direct unicast queries are supported and are included for testing. Subscription IDs are sequential numbers based on order of subscription and can be found with 'show subscriptions'. Without the subscription ID, the first subscription will be the default.
  • By default, the query will be sent the same address as the subscribe. This can be bypassed with the --target option.
test-register-receive-single [--verbose] [--protocol=llq|push]
                             [--transport=udp|tcp|tls] [--target=foo.bar.com] 
                             [--txt="PATH=/"] [--port=8080] [--timeout=2]
  • register a service over mDNS and then look for an LLQ subscription notification from the server. Includes PTR, SRV, TXT. This will register the service instance, receive the service notification and compare. It will wait timeout seconds (default 2) before declaring an error if it is not received. It assumes you have already subscribed to the service with the subscribe command.
test-register-receive-poisson [--verbose] [--rate=50] [--interval=2]
                              [--protocol=llq|push] [--transport=udp|tcp|tls] 
                              [--service=_poisson-llq._tcp] [--timeout=4] 
  • this is an automated test which subscribes to a service (defaults to _poisson-llq._tcp), then generates 'rate' events per second over the interval in seconds using a poisson distribution and correlates the responses. After the timeout, it unsubscribes from the service.
more ...

DNS Delegating Server

Requirements of the delegating server

The hybrid proxy is an authoritative DNS server for one or more subdomains. Each of these subdomains MUST be delegated to the hybrid proxy by the parent zone.


Subdomains are delegated to another server by defining NS records in the delegating server. The following records create three subdomains and delegate those subdomains to the listed servers.

floor1.example.com. IN      NS      server1.example.com.
floor2.exmaple.com. IN      NS      server2.example.com.
floor3.example.com. IN      NS      server3.example.com.

Browse Records

Service Discovery clients will query known search domains to see if they are browseable for services. Initially, they will query for b.dns-sd.udp.example.com. If the domain is browseable, it will have PTR records for one or more browseable domains. This could include a PTR record for the domain and also for subdomains. For a client to search a hybrid proxy for discoverable services, PTR records for the subdomain of each IP subnet represented by the hybrid proxy must be listed in the delegating server.

b._dns-sd._udp IN      PTR     @                   ;apex is browseable
b._dns-sd._udp IN      PTR     floor1.example.com. ;delegated to discovery proxy
b._dns-sd._udp IN      PTR     floor2.example.com.
b._dns-sd._udp IN      PTR     floor3.example.com.

The client will then query each of the subdomains listed to see if they are browseable, for example, b.dns-sd.udp.floor1.example.com. The hybrid proxy should answer this query with its hostname.

more ...


Lua style configuration

Most configuration can be provided in the delegating DNS server. discd queries this DNS server for subdomains and names to listen for. If you don't have full control over the delegating server, you can override or augment the configuration with a local config file.

There is a sample config file in $SYSCONFIDR/discd.lua. For Linux, this is /etc/discd.lua. For FreeBSD, it would be /usr/local/etc/discd.lua. Here, you can override the host and domain name as well as the subdomains for each interface. Some sample configuration is included below. While it might not be obvious, using a Lua language file for configuration provides a lot of flexibility for generating the variables to be read by the discd daemon.

hostname = 'foo.bar.com' -- only needed to override default
port = {
    -- defaults, not yet implemented
    udp = 53, tcp = 53, tls = 853, llq = 5352, push = 853
certificate = {
    -- looks for letsencrypt certs automatically in the default location by hostname
    crt = '/etc/letsenscrypt/live/foo.bar.com/cert.pem',
    key = '/etc/letsenscrypt/live/foo.bar.com/privkey.pem',
    chain = '/etc/letsenscrypt/live/foo.bar.com/fullchain.pem'
interfaces = {
    -- currently required if no reverse PTR net records
    { name = 'eth0', subdomain = 'sub1.bar.com' },
    { name = 'eth1', disable = true },


LLQ and DNS Push Notifications are not fully implemented.

more ...


To install on Ubuntu 14.04 LTS (Trusty Tahr), please add this repo and update. 64-bit only.

sudo apt-key adv --keyserver pgp.mit.edu --recv-keys F93418C56652E60C
sudo add-apt-repository 'deb [arch=amd64] http://dl.dnsdisco.com/ trusty main'
sudo apt-get update

To install on Ubuntu 16.04 LTS (Xenial Xerus), please add this repo and update. 64-bit only.

sudo apt-key adv --keyserver pgp.mit.edu --recv-keys F93418C56652E60C
sudo add-apt-repository 'deb [arch=amd64] http://dl.dnsdisco.com/ xenial main'
sudo apt-get update

The software can then be installed with the following commands:

sudo apt-get install discd
sudo apt-get install discli
sudo apt-get install discweb # (coming soon)
more ...

IETF 92 DNS Push Talk

In March of 2015, I gave a talk to the IETF DNS-SD Working Group in Dallas introducing DNS Push Notifications. This work was a joint effort between Stuart Cheshire and myself as a next generation follow on to LLQ.

Here are the slides:

IETF 92 DNS Push Slides

more ...