> ## Content Index
> Fetch the complete content index at: https://sgpublic.xyz/llms.txt
> Use this file to discover other available public pages before exploring further.

# 记一次关于 LanCache 和 OpenClash 使用的坑
- URL: https://sgpublic.xyz/p/2024/07/6aac9cb1810a4800015335fe/
- Published: 2024-07-30T15:56:18.000Z
- Updated: 2024-07-30T15:56:18.000Z
- Author: Haven Madray
- Tags: 网络与路由, NAS, #wp-post

## 前情提要

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

## 关于 LanCache

官方文档：[Quickstart | LanCache.NET](https://lancache.net/docs/?ref=sgpublic.xyz)

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

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

## 起因

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

然后我查阅文档：[Monolithic | LanCache.NET - Monolithic](https://lancache.net/docs/containers/monolithic/?ref=sgpublic.xyz#introduction)，他说支持 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)](https://green-m.me/2022/11/01/openwrt-dns-hijack/?ref=sgpublic.xyz)，按照这篇文章的描述，OpenClash 如果启用了 “本地 DNS 劫持” 会劫持所有 DNS 请求转发到路由器，我原本以为这仅仅是让请求到路由器地址的 DNS 请求转发到 OpenClash，但实际上是劫持所有 DNS 请求，无论目标地址是谁。

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

## 结论

需要关闭 OpenClash 的 “本地 DNS 劫持”，但 OpenClash 就不会设置 Dnsmasq 转发 DNS 请求了，可以手动添加，也可以按照 [openwrt 路由器的奇怪 DNS 劫持 (green-m.me)](https://green-m.me/2022/11/01/openwrt-dns-hijack/?ref=sgpublic.xyz) 的描述添加一个脚本，自动设置：

```
#!/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
}
```