如何在 Debian/Ubuntu 上使用域名更改主机名

如何在 Debian/Ubuntu 上使用域名更改主机名

虽然这似乎是一个常见问题解答,但我一直找不到在 Debian/Ubuntu 上使用域名更改主机名的正确方法。

首先,许多“答案”或文字都是错误的,它们把主机名和域名(FQDN)放进去/etc/hostname,比如, 因为

Debian 参考说主机名不应使用 FQDN

3.5.5. 主机名

内核维护系统主机名. 运行级别 S 中的 init 脚本,符号链接到“/etc/init.d/主机名.sh“在启动时设置系统主机名(使用主机名命令)存储在“/etc/主机名“。该文件应该包含仅有的系统主机名,而不是完全限定的域名。

此外,man hostname它还表示,

/etc/hosts通常,这是通过将主机名别名为 FQDN 来设置域名的地方。”和“FQDN 由短主机名和 DNS 域名组成。除非您使用 bind 或 NIS 进行主机查找,否则您可以在 /etc/hosts 文件中更改 FQDN 和 DNS 域名(它是 FQDN 的一部分)。”

好的。以上是我应该做的,但我得到的结果如下:

$ 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

更新

我做了一个跟踪hostname -f,似乎“没有与主机名关联的地址”错误来自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

任何帮助均感激不尽。

$ 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

您的“FQDN”由不同的程序通过两种不同的方式确定:

  1. 通过对您的主机名进行“主机”查找(使用通常用于解析 IP 地址的相同 Glibc 函数)并返回产生答案的“规范”域名。

    例如,这是 getaddrinfo() 加上 flags=AI_CANONNAME 后在 ai_canonname 字段中返回的内容,也是 gethostbyname() 后在 ht_name 字段中返回的内容。事实上,如果查找成功,inetutils 会hostname -f直接调用 gethostbyname() 并打印结果 ht_name。

    这可以通过 /etc/hosts 或 DNS 来处理,因此接下来发生的事情取决于 nsswitch.conf 中列出的模块,顺序如下:

    • “文件”模块检查 /etc/hosts 中的文字主机名(没有任何附加内容)。如果找到匹配的条目,则第一的该条目的名称是规范名称,其余的是别名。IP 地址被返回但被忽略。

      因此你可能会有这样的条目:

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

      FQDN 必须位于“规范名称”字段中,但短主机名必须存在于别名中,否则将找不到匹配项。

      (这里的实际地址并不重要,只有条目的存在才重要。但由于 gethostbyname() 仅适用于 IPv4,因此hostname -f将跳过 IPv6 地址的 /etc/hosts 条目,而使用 getaddrinfo(AI_CANONNAME) 的程序将包括这些条目。)

    • “dns”模块针对给定的主机名进行 DNS “A”查询,并结合 /etc/resolv.conf 中的搜索域。因此,使用 hostnamecoral和 resolv.conf ,将进行search my.domain.orgA 查找。coral.my.domain.org

      (Glibc 中如何确定搜索域?首先使用 $LOCALDOMAIN,然后使用 resolv.conf 中的“域”或“搜索”(以最后出现者为准),最后检查内核主机名中是否有域。)

      DNS 答案中具有 A 记录的任何名称都将作为规范名称(即您的 FQDN)返回;如果有任何 CNAME,则其域将作为别名返回。例如,如果查询产生以下结果:

      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
      

      coral.home.domain.net是规范名称,左列中的另外两个名称将是别名。

      (实际返回的 IP 地址仍然无关紧要。关于 gethostbyname() 仅适用于 IPv4 的相同说明也适用。)

    各种其他模块(例如“myhostname”或“ldap”或“nis”)也可能参与其中。列表中第一个产生答案的模块获胜。只有在以下情况下才会返回错误“没有与主机名关联的地址”模块找到了查询的结果。

  2. 或者,通过对主机名进行“主机”查找,然后进行撤销查找结果 IP 地址。我认为这种情况不太常见,但仍然会发生。

    这些是简单的查找,没有任何魔法。正向“主机”查找通常使用仅限 IPv4 的 gethostbyname() 完成,返回 IP 地址,反向查找使用 gethostbyaddr()。

    • 在 /etc/hosts 中,使用“文件”模块,您将再次需要一个与上面几乎相同的条目 - 以您的 FQDN 作为名字,以您的短主机名作为同一行中的别名之一。当通过 IP 地址进行反向查找时,将返回名字。

      127.0.0.1 coral.my.domain.org coral localhost
      -or-
      192.168.0.234 coral.my.domain.org coral
      
    • 在 DNS 中,使用“dns”模块,正向查找再次与上面相同(以搜索域为后缀)。

    这两次查找是独立的;一次可能通过 /etc/hosts 处理,另一次通过 DNS 处理,等等。

探究方法 #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)

我对 hostname -f 进行了跟踪,似乎“没有与主机名关联的地址”错误来自 libresolv.so:

不是 – 它来自 libc 中的高级 nsswitch 代码,在尝试调用所有启用的模块(首先是 nss_files,然后是 nss_dns→libresolv)但均未返回答案之后。

首先,许多“答案”或文字都是错误的,它们将主机名和域名(FQDN)放入 /etc/hostname,例如这个、这个和这个,因为

他们不是完全错误;事实上,如果 resolv.conf 中尚未指定域,Glibc DNS 解析器会从您的内核主机名中获取域并将其用作后备“搜索”域。

因此它不会立即作为您的 FQDN 返回,但它确实会影响该过程,就像您在 /etc/resolv.conf 中设置或一样searchdomain不仅适用于本地 FQDN 查找,还适用于任何通过 Glibc 函数完成的 DNS 查找。(请参阅 resolv/res_init.c 中的 domain_from_hostname() 函数)

相关内容