我想对一个特定域使用非默认 DNS 解析器,第一个想法是简单地使用本地 dnsmasq。在寻找 MacOS 版本时,我发现只需创建一个域名为 的文件即可实现相同的目的/etc/resolver/example.com
,只需一行简单的操作:
nameserver 8.8.8.8
一切都很好并且按预期工作,该决议有效并scutil --dns
确认:
resolver #8
domain : example.com
nameserver[0] : 8.8.8.8
flags : Request A records
reach : Reachable
接下来,我想通过创建一个可以在终端中运行的简单单行代码与朋友分享:
sudo mkdir -p /etc/resolver/ && echo "nameserver 8.8.8.9" | sudo tee /etc/resolver/example.net
再次scutil --dns
确认:
resolver #10
domain : example.net
nameserver[0] : 8.8.8.9
flags : Request A records
reach : Reachable
然后我注意到一个拼写错误,所以我将地址更正为 8.8.8.8 并再次运行该行:
sudo mkdir -p /etc/resolver/ && echo "nameserver 8.8.8.8" | sudo tee /etc/resolver/example.net
但这似乎没有任何效果:
resolver #10
domain : example.net
nameserver[0] : 8.8.8.9
flags : Request A records
reach : Reachable
我检查了文件内容,一切似乎都很好:
$ cat /etc/resolver/example.net
nameserver 8.8.8.8
然后我打开 中的文件vim
,更改为8.8.4.4
and:
resolver #10
domain : example.net
nameserver[0] : 8.8.4.4
flags : Request A records
reach : Reachable
我来回检查了几次,当我将地址回显到文件时,更改没有任何效果,但仅打开它就足够了vim
,甚至不更改任何内容(只需退出),将应用先前回显的更改。这背后的机制是什么?
答案1
[它] 只需打开它就足够了
vim
,甚至不更改任何内容(只需退出),将应用先前回显的更改。
我必须使用sudo vim
它才能工作。用我的普通用户运行它没有效果。我的理论是,无论什么正在监视/etc/resolver
目录的更改,而不是目录中文件的更改,并且当它看到目录的更改时,都会重新加载其中的所有内容。 Vim 创建一个交换文件,默认情况下与正在编辑的文件位于同一目录中。这是对目录的更改,并由观察者发现。所以,当我这样做时:
sudo vim -n /etc/resolver/example.net
如果-n
禁用交换文件创建,则不再拾取对文件的更改。
答案2
不会注意到对现有文件的更改/etc/resolver
,仅在该文件夹中创建或删除文件时才会注意到。
这是监视该文件夹IPMonitor
的插件。 从源代码来看:configd
status = notify_monitor_file(notify_token, resolver_directory_path, 0);
这个函数的作用是在inode
路径上设置一个监视器。因此,只有当该目录中的任何文件发生变化时,它才会收到通知inode
,/etc/resolver
而不会收到通知。inode
在 UNIX 中,目录就像一个文件,其内容是列出目录内容的表。因此,每当您添加或删除文件时,该表都会更新,因此inode
也会更新,从而触发通知。如果您编辑目录中的文件,则inode
根本不会触及该目录。
但你/etc/resolver
根本不应该在 macOS 上使用,它只是为了向后兼容而保留。相反,您应该在动态存储中创建一个 DNS 条目,您可以使用该工具访问该条目scutil
。请查看我对这个话题的回复。
答案3
在重新启动计算机或强制刷新网络设备 DNS 设置之前,我无法scutil --dns
返回预期的 DNS 条目,如下所示:
networksetup -setdnsservers Wi-fi 8.8.8.8
在这里写下有关此修复/黑客的更多详细信息:https://josephharding.github.io/tutorials/2018/06/28/mac-resolver-refresh.html