虽然这似乎是一个常见问题解答,但我一直找不到在 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”由不同的程序通过两种不同的方式确定:
通过对您的主机名进行“主机”查找(使用通常用于解析 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 中的搜索域。因此,使用 hostname
coral
和 resolv.conf ,将进行search my.domain.org
A 查找。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”)也可能参与其中。列表中第一个产生答案的模块获胜。只有在以下情况下才会返回错误“没有与主机名关联的地址”不模块找到了查询的结果。
或者,通过对主机名进行“主机”查找,然后进行撤销查找结果 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 中设置或一样search
。domain
不仅适用于本地 FQDN 查找,还适用于任何通过 Glibc 函数完成的 DNS 查找。(请参阅 resolv/res_init.c 中的 domain_from_hostname() 函数)