Skip to content

Latest commit

 

History

History
145 lines (109 loc) · 5.4 KB

README.md

File metadata and controls

145 lines (109 loc) · 5.4 KB

zelect

Windows 10

zelect is a Python3 program that abuses mDNS to synthesize the DNS name test.local for any complete IPv6 link-local address (LLA) entered by the user in a simple command line interface (which incidentally conforms to draft-ietf-6man-zone-ui). This program is a hack inspired by draft-schinazi-httpbis-link-local-uri-bcp.

At present it only works properly on Windows 10, where it can use a regular socket call to send a synthetic unsolicited mDNS response message. While it is running, the user can perform ping test.local and it goes to the LLA supplied.

More interestingly, all the browsers tested so far on Windows 10 support http://test.local or https://test.local correctly - that is, they attempt an HTTP(S) connection to the target LLA. Typically it fails with a reset, which is the expected result.

When you tell zelect to stop (or it crashes), test.local reverts to not working.

This was tested on Windows 10 22H2 (build 19045.4046). No promises for any other Windows version.

Since Windows supports a default zone index for LLAs, this success is relative - with multiple LANs present, things might go wrong. I can't test that on my setup because my Ethernet and WiFi are bridged together.

An unintended side effect is that while zelect is running, all other Windows hosts on the same LAN will also see the test.local name in mDNS.

Obviously, this is a hack, you use it at your own risk.

Linux (a tale of woe)

It ought to work on Linux, but it doesn't. The code is in there, and anyone who can figure out how to make it work is owed a beer or an ice cream (offer applies in Auckland only). On Linux, the avahi mDNS implementation only accepts mDNS responses from port 5353. However, even that doesn't work because it seems that avahi ignores multicasts from its own host (IPPROTO_IPV6 IPV6_MULTICAST_LOOP 0, apparently). So even fabricating mDNS packets with scapy doesn't work.

Additionally, while zelect is running using scapy on Linux, Windows hosts on the same LAN will see the test.local name in mDNS. In other words, the Linux scapy code is working, but Linux isn't listening.

Even sending such fabricated packets from another machine didn't work at first. It turns out that there is a critical setting in /etc/nsswitch.conf. There MUST be a line like this:

hosts:      files mdns [NOTFOUND=return] resolve [!UNAVAIL=return] dns

Note, it's mdns NOT mdns4, which seems to be widely used, but prevents IPv6 resolution from working at all.

However, with packets fabricated using scapy on Windows, we then find that on Linux ping test.local works.

(This is done by the experimental version, 'zelect-try.py'.)

Also, on Firefox, http://test.local works too - it gets connection reset which is the expected result.

There are several gotchas:

  1. There is a very long delay (since apparently it attempts to resolve 'test.local' for IPv4, which has to time out first).

  2. Neither ping6 test.local nor ping -6 test.local works properly. They both resolve the name but then fail with a sendmsg() 'invalid argument' error, which indicates that they don't pick up the interface number from mDNS. It seems that these variants use a different and buggy code path than plain ping test.local.

  3. Chrome can resolve the name but the connection fails with ERR_INVALID_ARGUMENT, exactly the same error as with ping6.

  4. Avahi doesn't forget the mDNS record after 1 second, as Windows does. However, it does respect the TTL and therefore deletes the 'test.local' name after 5 minutes.

Note that avahi-publish-address cannot possibly work for LLAs, because it uses inet_pton() which doesn't understand zone identifiers at all.

Putting a link local address in the /etc/avahi/hosts file doesn't work either, for the same reason - you can't specify the interface name. (There are perhaps some corner cases where it might work, but if a host has several LAN interfaces active, it definitely won't work.)

Example run on Windows

Download zelect.py and double click on the file, assuming you have Python 3 and the standard libraries installed. (Tested on Python 3.11.)

This is zelect, which abuses mDNS to synthesize the DNS
name 'test.local' for any complete IPv6 link-local address
entered by the user.

Use with care!


Enter IPv6 link-local address%interface: fe80::2e3a:fdff:fea4:dde7%7
Invalid interface identifier, please try again.
Enter IPv6 link-local address%interface: fe80::2e3a:fdff:fea4:dde7%24
Sending mDNS unsolicited response.
'test.local' should now resolve as fe80::2e3a:fdff:fea4:dde7%24
Press enter to stop:

At this point, at the Windows prompt in another window, we can test it out:

C:\WINDOWS\system32>ping test.local

Pinging test.local [fe80::2e3a:fdff:fea4:dde7%24] with 32 bytes of data:
Reply from fe80::2e3a:fdff:fea4:dde7%24: time=1ms
Reply from fe80::2e3a:fdff:fea4:dde7%24: time=1ms
Reply from fe80::2e3a:fdff:fea4:dde7%24: time=1ms

Ping statistics for fe80::2e3a:fdff:fea4:dde7%24:
    Packets: Sent = 3, Received = 3, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 1ms, Maximum = 1ms, Average = 1ms

And then press Enter in zelect's window:

Stopping...
'test.local' should no longer resolve.
R to restart, anything else to exit: r
Enter IPv6 link-local address%interface: