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

xpt*_*xpt 5 networking linux dns debian ubuntu

虽然它似乎是一个常见问题解答,但我从来没有找到一种正确的方法来在 Debian/Ubuntu 上用域名更改主机名。

首先,许多“答案”或著作都是错误的,将主机名和域名(FQDN)放入/etc/hostname, like this , thisthis 中,因为

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

3.5.5. 主机名

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

此外,从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

Run Code Online (Sandbox Code Playgroud)

更新

我对 进行了跟踪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

Run Code Online (Sandbox Code Playgroud)

任何帮助表示赞赏。

$ 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

Run Code Online (Sandbox Code Playgroud)

use*_*686 6

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

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

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

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

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

      所以你可能有这样的条目:

      127.0.0.1 coral.my.domain.org coral localhost
      -or-
      192.168.0.234 coral.my.domain.org coral
      
      Run Code Online (Sandbox Code Playgroud)

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

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

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

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

      DNS 应答中的任何名称都将作为规范名称(即您的 FQDN)返回 A 记录;如果有任何 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
      
      Run Code Online (Sandbox Code Playgroud)

      thencoral.home.domain.net将是规范名称,左列中的其他两个名称将是别名。

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

    各种其他模块,例如“myhostname”或“ldap”或“nis”也可以参与其中。列表中第一个产生答案的人获胜。仅当没有模块找到查询结果时,才会返回错误“没有与主机名关联的地址” 。

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

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

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

      127.0.0.1 coral.my.domain.org coral localhost
      -or-
      192.168.0.234 coral.my.domain.org coral
      
      Run Code Online (Sandbox Code Playgroud)
    • 在 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)
Run Code Online (Sandbox Code Playgroud)

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

不 - 它来自 libc 中的高级 nsswitch 代码,在它尝试调用所有启用的模块(首先是 nss_files,然后是 nss_dns?libresolv)并且没有一个返回答案之后。

首先,将带有域名(FQDN)的主机名放入 /etc/hostname 中,例如这个,这个和这个,许多“答案”或著作都是错误的,因为

他们并非完全错了。Glibc DNS 解析器实际上从您的内核主机名中获取域,并将其用作后备“搜索”域(如果尚未在 resolv.conf 中指定)。

因此,它不会立即作为您的 FQDN 返回,但它确实以与您在 /etc/resolv.conf 中searchdomain在 /etc/resolv.conf中完全相同的方式影响该过程。不仅用于本地 FQDN 查找,也用于通过 Glibc 函数完成的任何DNS 查找。(参见 resolv/res_init.c 中的函数 domain_from_hostname())