Using dig as a LLMNR or mDNS CLI lookup utility
Published:
Updated:
I was looking for a LLMNR commandline lookup utility. Actually, dig
can do the job quite fine.
Warning: deprecated (not working anymore)
Update 2023-09-22: The commands using dig
(which were a convenient hack) do not work anymore with recent versions of dig (since v9.18).
TL:DR
LLMNR lookup:
dig +noedns -p 5355 @224.0.0.252 wpad
resolvectl query -p llmnr wpad
mDNS lookup:
dig -p 5353 @224.0.0.251 example.local
resolvectl query -p mdns example.local
avahi-resolve-host-name example.local
Choosing the network interface:
- When using dig, we can control the network interface we are querying by binding the socket (
-b 192.168.1.42
)[2]. Without this flag, the request will use the default route to choose which network interface to use. - With resolvectl we can choose the interface with
-i
.
LLMNR usage
LLMNR (Link-Local Multicast Name Resolution), RFC 4795, is a Microsoft-centric DNS-based protocol for resolving names using multicast on the local network. It is expected to be used by default for single label names only:
By default, an LLMNR sender SHOULD send LLMNR queries only for single-label names. Stub resolvers supporting both DNS and LLMNR SHOULD avoid sending DNS queries for single-label names, in order to reduce unnecessary DNS queries.
In the Windows world, it is used alongside with other protocols[3] such as NBNS/NBT-NS (NetBios/TCP Name Service, RFC 1001, RFC 1002), WINS and DNS. Apparently, LLMNR is tried before NBNS but it isnot really documented as far as I know.
LLMNR is quite similar in spirit to mDNS (multicast DNS, RFC 6762). mDNS is originated from Apple Bonjour where it is used with DNS-SD (DNS Service Discovery, RFC 6783) and has been available on Linux systemd for a long time through Avahi. It is normally used for domain names in the local
domain (eg. foo.local
, foo.bar.local
, etc.).
On Linux systems, in addition to Avahi, system-resolved supports both LLMNR and mDNS/DNS-SD.
LLMNR lookup with dig
I was looking for a CLI tool for resolving names with LLMNR but could not find any. In fact, dig
can be the job well. LLMNR is really DNS with a few changes:
-
queries requests are sent to multicast address 224.0.0.252 or ff02:0:0:0:0:0:1:3 with UDP port 5355;
-
responses are sent to the requester IP address and port using the IP and port the request was sent to;
-
a few flags have a different meaning.
LLMNR header:
1 1 1 1 1 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ID | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |QR| Opcode | C|TC| T| Z| Z| Z| Z| RCODE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QDCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ANCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | NSCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ARCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
DNS header:
1 1 1 1 1 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ID | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |QR| Opcode |AA|TC|RD|RA| Z | RCODE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QDCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ANCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | NSCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ARCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
This means we can actually do LLMNR requests with dig
. Dor example, we can do a DNS WPAD 😨 request:
dig +noedns -p 5355 @224.0.0.252 wpad
EDNS0 is disabled because the Microsoft LLMNR profile does not support EDNS0:
The Link Local Multicast Name Resolution (LLMNR) Profile [...] does not support Extension Mechanisms for DNS (EDNS0) [RFC 2671].
mDNS lookup with dig
Similarly for mDNS, requests are sent to 224.0.0.251 or ff02::fb on UDP port 5353. Full mDNS queries are expected to send queries from this same IP/port tuple (and receive the answer on this same tuple):
A compliant Multicast DNS querier, which implements the rules specified in this document, MUST send its Multicast DNS queries from UDP source port 5353 (the well-known port assigned to mDNS), and MUST listen for Multicast DNS replies sent to UDP destination port 5353 at the mDNS link-local multicast address (224.0.0.251 and/or its IPv6 equivalent FF02::FB).
This cannot be done with dig
: it cannot listen for answers sent to a multicast address.
However, the mDNS protocol allows for a simpler client implementation, One-Shot Multicast DNS Queries:
The most basic kind of Multicast DNS client may simply send standard DNS queries blindly to 224.0.0.251:5353, without necessarily even being aware of what a multicast address is. [...] these queries MUST NOT be sent using UDP source port 5353, since using UDP source port 5353 signals the presence of a fully compliant Multicast DNS querier, as described below.
This means we can use dig
as well:
dig -p 5353 @224.0.0.251 example.local
Alternatives
Using resolvectl
Alternatively if systemd-resolved
is running, resolvectl
can be used:
resolvectl query -p llmnr example
resolvectl query -p mdns example.local
Using avahi
mDNS request can be done through the Avahi damone using:
avahi-resolve-host-name example.local
These versions of
dig
useconnect()
-ed[1] UDP sockets. Whenconnect()
is used on a datagram socket, the socket drops any ingress packet which does not come from the chosen (multicast in our case) IP address. With mDNS and LLMNR, the response comes from the IP address of the responder which is not the multicast address (224.0.0.252 or 224.0.0.251) and will therefore be ignored by theconnect()
-ed UDP socket. ↩︎If you wonder how this works, I believe this is because the routing algorithm takes the source address (if any) into account in this case. You can see that by comparing,
ip route get 224.0.0.252
(goes through the interface if your default route) andip route get 224.0.0.252 from 127.0.0.1
(goes throughlo
). ↩︎Apparently there is as well PNRP (Peer Name Resolution Protocol) and SNID (Server Network Information Discovery). ↩︎