5

Although it seems to be an FAQ, but I had never been able find a proper way to change hostname with domainname on Debian/Ubuntu.

First of all, many "answers" or writings are just wrong by putting hostname with domainname (FQDN) into /etc/hostname, like this, this and this, because

The Debian reference says the hostname should not use the FQDN:

3.5.5. The hostname

The kernel maintains the system hostname. The init script in runlevel S which is symlinked to "/etc/init.d/hostname.sh" sets the system hostname at boot time (using the hostname command) to the name stored in "/etc/hostname". This file should contain only the system hostname, not a fully qualified domain name.

Also, from man hostname, it says,

"/etc/hosts Usually, this is where one sets the domain name by aliasing the host name to the FQDN." and "A FQDN consists of a short host name and the DNS domain name. Unless you are using bind or NIS for host lookups you can change the FQDN and the DNS domain name (which is part of the FQDN) in the /etc/hosts file."

OK. The above is what I should do, but this is what I'm getting:

$ cat /etc/hostname
coral

$ head -1 /etc/hosts 
127.0.0.1       coral.my.domain.org localhost

$ dnsdomainname
ht.home

$ cat /etc/resolv.conf
domain ht.home
search ht.home
nameserver 192.168.0.1

# after I change it to --

$ cat /etc/resolv.conf
# Fixed resolv.conf file
domain my.domain.org
search my.domain.org
nameserver 192.168.0.1

# everything just gone wrong --

$ dnsdomainname
dnsdomainname: No address associated with hostname

$ hostname -f
hostname: No address associated with hostname

$ hostname -d
hostname: No address associated with hostname

Update

I did a trace on hostname -f, and it seems the "No address associated with hostname" error comes from libresolv.so:

$ strace -o /tmp/strace.log hostname -f
hostname: No address associated with hostname

$ grep -E 'openat|close|No address' /tmp/strace.log
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
close(3)                                = 0
close(3)                                = 0
close(3)                                = 0
openat(AT_FDCWD, "/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
close(3)                                = 0
openat(AT_FDCWD, "/etc/host.conf", O_RDONLY|O_CLOEXEC) = 3
close(3)                                = 0
openat(AT_FDCWD, "/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 3
close(3)                                = 0
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 3
close(3)                                = 0
openat(AT_FDCWD, "/etc/hosts", O_RDONLY|O_CLOEXEC) = 3
close(3)                                = 0
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libnss_dns.so.2", O_RDONLY|O_CLOEXEC) = 3
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libresolv.so.2", O_RDONLY|O_CLOEXEC) = 3
close(3)                                = 0
close(3)                                = 0
close(3)                                = 0
write(2, "No address associated with hostn"..., 35) = 35

Any help appreciated.

$ uname -rm
5.10.0-6-amd64 x86_64

$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux bullseye/sid
Release:        testing
Codename:       bullseye

1 Answer 1

6

Your "FQDN" is determined by different programs in two different ways:

  1. By making a 'hosts' lookup for your hostname (using the same Glibc functions that are typically used to resolve IP addresses) and returning the "canonical" domain name that produced the answer.

    For example, this is what getaddrinfo() with flags=AI_CANONNAME would return in the ai_canonname field, and what gethostbyname() would return in the ht_name field. Indeed inetutils' hostname -f literally calls gethostbyname() and prints the resulting ht_name if the lookup succeeded.

    This can be handled either via /etc/hosts or via DNS, so what happens next depends on the modules listed in nsswitch.conf, in order:

    • The 'files' module checks /etc/hosts for the literal hostname (without anything appended). If it finds a matching entry, the first name for that entry is the canonical name, the rest are aliases. The IP address is returned but ignored.

      So you might have an entry like this:

      127.0.0.1 coral.my.domain.org coral localhost
      -or-
      192.168.0.234 coral.my.domain.org coral
      

      The FQDN must go in the "canonical name" field, but the short hostname must be present among aliases otherwise a match won't be found.

      (The actual address doesn't matter here, only the existence of the entry. But because gethostbyname() is IPv4-only, hostname -f will skip /etc/hosts entries for IPv6 addresses, while programs using getaddrinfo(AI_CANONNAME) will include those.)

    • The 'dns' module makes a DNS 'A' query for the given hostname, combined with a search domain from /etc/resolv.conf. So with hostname coral and resolv.conf search my.domain.org, an A lookup for coral.my.domain.org will be made.

      (How are the search domains determined in Glibc? $LOCALDOMAIN is used first, then 'domain' or 'search' from resolv.conf, whichever occurs last, and finally the kernel hostname is checked if it has a domain in it.)

      Whatever name in the DNS answer has the A record will be returned as the canonical name (i.e. your FQDN); if there are any CNAMEs, their domains will be returned as aliases. For example, if the query produces these results:

      coral.my.domain.org.    CNAME    coral.reef.domain.org.
      coral.reef.domain.org.  CNAME    coral.home.domain.net.
      coral.home.domain.net.  A        1.2.3.4
      

      then coral.home.domain.net will be the canonical name and the other two names in the left column will be aliases.

      (The actual returned IP address still doesn't matter. Same note about gethostbyname() being IPv4-only applies.)

    Various other modules such as 'myhostname' or 'ldap' or 'nis' can get involved too. The first one in the list that produces an answer wins. The error "No address associated with hostname" is only returned if no module found a result for the query.

  2. Or, by making a 'hosts' lookup for your hostname, then making a reverse lookup for the resulting IP address. I think this is much less common but occurs nevertheless.

    These are straightforward lookups with no magic behind them. The forward 'hosts' lookup is commonly done using the IPv4-only gethostbyname(), returning an IP address, and the reverse using gethostbyaddr().

    • In /etc/hosts, with the 'files' module, you'll again want an entry practically the same as above – with your FQDN as the first name and your short hostname as one of the aliases in the same line. When a reverse lookup by IP address is made, the first name will be returned.

      127.0.0.1 coral.my.domain.org coral localhost
      -or-
      192.168.0.234 coral.my.domain.org coral
      
    • In DNS, with the 'dns' module, the forward lookup is again made same as above (with the search domain suffixed).

    The two lookups are independent; it's possible that one will be handled via /etc/hosts and the other via DNS, etc.

To poke around method #1:

import sys
import socket

try:
    host = sys.argv[1]
except IndexError:
    host = socket.gethostname()

try:
    name, aliases, addresses = socket.gethostbyname_ex(host)
    print("gethostbyname(): name = %s, aliases = %s" % (name, aliases))
except socket.gaierror as e:
    print("gethostbyname(): Not found (%s); must be IPv6-only" % e)

try:
    res = socket.getaddrinfo(host, 0, flags=socket.AI_CANONNAME)
    for (addr_family, socktype, protocol, canonname, sock_addr) in res:
        print("getaddrinfo(): canonname =", canonname)
        break # gai only fills in cname for the 1st result
except socket.gaierror as e:
    print("getaddrinfo(): Not found (%s)" % e)

I did a trace on hostname -f, and it seems the "No address associated with hostname" error comes from libresolv.so:

No – it comes from the high-level nsswitch code in libc, after it has tried calling into all enabled modules (first nss_files, then nss_dns→libresolv) and none of them returned an answer.

First of all, many "answers" or writings are just wrong by putting hostname with domainname (FQDN) into /etc/hostname, like this, this and this, because

They're not entirely wrong; Glibc DNS resolver in fact takes the domain from your kernel hostname and uses it as the fallback 'search' domain if one isn't specified in resolv.conf already.

So it doesn't immediately get returned as your FQDN, but it does influence the process in exactly the same way as if you had search or domain in /etc/resolv.conf. Not just for local FQDN lookups, too, but for any DNS lookup that is done via Glibc functions. (See function domain_from_hostname() in resolv/res_init.c)

1
  • "In /etc/hosts, with the 'files' module, you'll again want an entry practically the same as above – with your FQDN as the first name and your short hostname as one of the aliases in the same line" I found that to be the answer to my problem. Once I have both part of, FQDN as the first name and short hostname as one of the aliases in the same line, everything starting working, including the provided python code. Removing the short hostname again, and everything will get back to the stage in OP. Thanks!!!
    – xpt
    Commented May 17, 2021 at 4:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .