Why can't I ssh to a local (single-label) hostname: "ssh: connect to host myserver port 22: Invalid argument"?
When I brought a Raspberry Pi onto the network, this problem manifested itself in a new way and I was able to finally diagnose it.
The problem is related to systemd-resolved
. This has been affecting
other users, see for example Ask Ubuntu's nslookup finds ip, but ping
doesnt
or systemd-resolved does not query dns server for local
domain.
I had assumed that ssh myserver
would trigger a DNS lookup of
myserver
. However, that is not the case on my system, here is the
default nsswitch.conf
:
$ cat /etc/nsswitch.conf
# Name Service Switch configuration file.
# See nsswitch.conf(5) for details.
...
hosts: files mymachines myhostname resolve [!UNAVAIL=return] dns
...
The resolve
component is systemd-resolved
, which is a Lennart
Poettering project to implement the
Zeroconf
protocols Multicast DNS
and Link-Local Multicast Name
Resolution.
The [!UNAVAIL=return]
means that when systemd-resolved
is
available, DNS host resolution is never used. Usually this is not a
problem because systemd-resolved
is also able to create DNS queries.
However it apparently does not do this for single-label hostnames like
myserver
, even when the DNS server is on my local router
(192.168.1.1). This is because it is reasoned that single-label
hostnames should not be exposed to the outside network, as explained
by Lennart in this Github thread.
This explains the fact that host myserver
produced an IPv4 address
(from the router) while ssh myserver
produced an IPv6 address (from
Multicast DNS or LLNR, not sure which).
I was confused by this because I never learned about Multicast DNS or LLNR or IPv6. I never learned about these technologies because I thought the familiar technologies of IPv4 and DNS were sufficient for me.
Apparently systemd-resolved
is necessary not just for producing
Zeroconf requests, but also for replying to them. The Raspberry Pi
which I brought onto my network had its systemd-resolved
stopped for
some reason, so although I was able to look up the hostname with
host
and dig
, I was not able to see it via ssh
or ping
:
$ ping raspberrypi
ping: raspberrypi: Name or service not known
[2]$ host raspberrypi
raspberrypi has address 192.168.1.135
This led me to the first Ask Ubuntu bug report above, which led me to
the solution. If I start systemd-resolved
on the Pi then I am able
to ping
and ssh
it. However, if I disable systemd-resolved
locally then I am also able to ping
and ssh
to the Pi.
For now I have just disabled systemd-resolved
on all my systems,
$ sudo systemctl stop systemd-resolved.service
$ sudo systemctl disable systemd-resolved.service
since it seems to create problems with GNU libc's nscd
and since it
requires me to learn about technologies like IPv6, mDNS, and LLNR,
which I don't currently need - because my computers are all connected
to a basic consumer router which provides familiar technologies of DNS
and NAT out-of-the-box.
Thanks to those who commented on my original question, but in the end
it was not necessary to "configure yourself a ULA prefix, or get
global IPv6 connectivity, or both" via "a setting in your home router,
if it's not a complete piece of ****" or "to yell at your ISP". I just
had to disable some of Lennart's new software to take myself away from
the bleeding edge. The Github thread has some discussion about whether
the software is actually behaving correctly, but I find myself in the
same position as many other users: after spending hours of time
figuring out that systemd-resolved
is the culprit, I'd rather not
spend more hours trying to understand how to fix it, when disabling is
so easy.