关于dnsmasq结合ipset/nft实现“允许列表”式captive portal的疑问
嘿,你的思路方向是对的,但其实不用给每个域名都写ipset条目——这也太麻烦了,dnsmasq本身就支持基于客户端IP的条件规则,能帮你轻松实现这个允许列表的需求。
先理下你的现有场景:你用address=/#/123.123.123.123让所有DNS请求都指向本地Nginx的限制页面,现在想让captive-allowed这个ipset里的客户端IP绕过这个重定向,直接用dnsmasq转发到1.1.1.1/1.0.0.1查询真实DNS。
你之前误以为要给每个域名加ipset=/xxx.com/captive-allowed/xxx.ip,这完全没必要,其实只需要调整dnsmasq的配置规则优先级就行:
先保留你创建ipset的操作,这部分是对的:
ipset create captive-allowed hash:ip ipset add captive-allowed 222.222.222.222修改dnsmasq的配置文件,把规则反过来写:
- 首先给允许列表里的客户端设置专属的DNS转发规则:
# 仅当客户端IP在captive-allowed集合里时,所有域名的DNS请求转发到1.1.1.1和1.0.0.1 server=/#/1.1.1.1,1.0.0.1[/captive-allowed] - 然后设置全局的重定向规则,对不在允许列表的客户端生效:
# 其他所有客户端的DNS请求,统一指向本地限制页面的IP address=/#/123.123.123.123
- 首先给允许列表里的客户端设置专属的DNS转发规则:
dnsmasq的规则是更具体的条件规则优先于全局规则,所以当客户端IP在captive-allowed里时,会优先使用带ipset条件的server规则,直接转发到公共DNS;不在列表里的客户端则会触发全局的address规则,被重定向到本地页面。
如果你觉得用dnsmasq自身的规则不够灵活,也可以配合nftables/iptables来实现:比如拦截所有非允许列表客户端的53端口请求,转发到你的本地dnsmasq实例(配置了全局重定向),而允许列表的客户端直接放行DNS请求到公共DNS。不过这种方法需要额外配置防火墙,不如直接用dnsmasq的ipset条件规则来得简洁。
总结一下:你的初始假设是错的,不用写亿条域名规则,靠dnsmasq的server指令结合ipset后缀就能搞定允许列表的需求~
备注:内容来源于stack exchange,提问作者Bubonic Pestilence

