记一次关于 LanCache 和 OpenClash 使用的坑
本文最后更新于 113 天前,其中的信息可能已经有所发展或是发生改变。
内容目录

前情提要

首先简述一下我的网络环境,所有设备通过 OpenWRT 接入网络,OpenWRT 上安装了 OpenClash 以实现透明代理和 DNS 解析服务,OpenClash 启用了 “本地 DNS 劫持”(划重点,后面要考)。

关于 LanCache

官方文档:Quickstart | LanCache.NET

LanCache 是一个被动缓存服务器,将需要缓存的域名解析到 LanCache 实例地址,LanCache 会检测本地是否存在缓存,不存在则将请求代理到真实地址并缓存响应结果,存在则直接从本地缓存。

例如若将 lancache.steamcontent.com 解析到 LanCache 地址,则 Steam 可支持缓存,第二次下载速度就能跑满局域网,且不需要从服务器重复下载。

起因

本来是,我在 OpenWRT 的 Dnsmasq 中设置好将 lancache.steamcontent.com 解析到 LanCache,也实验成功有效,Steam 成功命中缓存,第二次下载速度跑满局域网。

然后我查阅文档:Monolithic | LanCache.NET – Monolithic,他说支持 HTTP 范围请求,也就是说,只要请求使用的是 HTTP,他就能缓存。

而刚好我这两天在制作 Docker 镜像,测试的时候需要重复使用 apt-get 从 deb.debian.org 下载依赖包,我就想着把 deb.debian.org 也加入缓存。

于是乎参照 lancache.steamcontent.com 的设置方式,我在 OpenWRT 的 Dnsmasq 中设置将 deb.debian.org 也解析到 LanCache,然后 apt-get 直接报错 HTTP 508,然后就开始了排查。

排查过程

HTTP 508 代表请求发生了回环,由于我将 deb.debian.org 解析到了 LanCache,而 LanCache 没有命中缓存的情况下,需要将请求代理到真实地址,而真实地址需要解析 DNS,但 deb.debian.org 被解析到了 LanCache,于是乎请求又回到了 LanCache,这样就造成了回环。

于是我按照文档,添加了环境变量 UPSTREAM_DNS 为 8.8.8.8,意思是缓存未命中的时候,DNS 解析使用 8.8.8.8 而非当前默认 DNS 服务器也就是路由器,然而重启之后请求依旧 508。

那自然要用到 nslookup 来看 deb.debian.org 究竟解析到哪里了。

madray@nas:~$ nslookup
> server 8.8.8.8
Default server: 8.8.8.8
Address: 8.8.8.8#53
> deb.debian.org
Server:         8.8.8.8
Address:        8.8.8.8#53

Name:   deb.debian.org
Address: 192.168.6.140
> server 114.114.114.114
Default server: 114.114.114.114
Address: 114.114.114.114#53
> deb.debian.org
Server:         114.114.114.114
Address:        114.114.114.114#53

Name:   deb.debian.org
Address: 192.168.6.140

可以看到,就算我将 server 设置为外部地址,而非路由器地址,查询结果也始终返回我在 Dnsmasq 上设置的地址。

于是乎怀疑 OpenWRT 拦截了 DNS 请求,使用“openwrt 拦截dns请求”关键词搜索,找到这篇文章:openwrt 路由器的奇怪 DNS 劫持 (green-m.me),按照这篇文章的描述,OpenClash 如果启用了 “本地 DNS 劫持” 会劫持所有 DNS 请求转发到路由器,我原本以为这仅仅是让请求到路由器地址的 DNS 请求转发到 OpenClash,但实际上是劫持所有 DNS 请求,无论目标地址是谁。

关闭之后,deb.debian.org 的请求成功缓存。

结论

需要关闭 OpenClash 的 “本地 DNS 劫持”,但 OpenClash 就不会设置 Dnsmasq 转发 DNS 请求了,可以手动添加,也可以按照 openwrt 路由器的奇怪 DNS 劫持 (green-m.me) 的描述添加一个脚本,自动设置:

#!/bin/sh /etc/rc.common
# file: /etc/init.d/dnswatcher

START=10
STOP=15

watchdir=/var/etc/
LOGFILE=/tmp/openclash_mylogger.log


start() {
    inotifywait -q -m "$watchdir"  -e delete,create |
        while read -r path action file; do
            #echo "The file '$file' appeared in directory '$path' via '$action'" >> $LOGFILE

            if  printf "%s" "$file" |grep -q "openclash.include" ; then
                sleep 5

                enable=$(uci get openclash.config.enable)

                # if enable ,modify dns
                if [ "$enable" -eq 1 ]; then
                    #echo "enabled"
                    echo "$(date)-----openclash dns not set right, changing it!" >> $LOGFILE
                    uci del dhcp.@dnsmasq[-1].server >/dev/null 2>&1
                    uci add_list dhcp.@dnsmasq[0].server="127.0.0.1#7874"
                    uci delete dhcp.@dnsmasq[0].resolvfile
                    uci set dhcp.@dnsmasq[0].noresolv=1
                    uci set dhcp.@dnsmasq[0].cachesize=0
                    uci commit dhcp
                    /etc/init.d/dnsmasq restart

                # else revert dns setting
                else
                    #echo "disabled"
                    echo "$(date)-----Reverting dns!" >> $LOGFILE
                    uci del dhcp.@dnsmasq[-1].server >/dev/null 2>&1
                    uci add_list dhcp.@dnsmasq[0].server="223.5.5.5#53"
                    uci set dhcp.@dnsmasq[0].resolvfile=/tmp/resolv.conf.auto >/dev/null 2>&1
                    uci set dhcp.@dnsmasq[0].noresolv=0
                    uci set dhcp.@dnsmasq[0].cachesize=0
                    uci commit dhcp
                    /etc/init.d/dnsmasq restart
                fi
            fi
    done &
    return 0
}

stop() {
     ps -ef | grep inotifywait | grep -v grep | awk {'print $1'} | xargs kill -9
     return 0
}

上一篇
下一篇