分类: network

  • 如何使用 Zerotier 连接你家中的设备

    我在家里的旧笔记本上使用 Open My Vault 建立了 NAS,不过我只能在家里连上 WiFi 才能访问它。在过年回老家、出门旅游或者外出办公的时候就没法使用了。虽然在这些场景经常用不上 NAS,不过,“我可以不用,但不能没有”。

    经过一番调研后,我发现我需要的是一个 VPN 软件,通过 VPN 安全地访问运行在家里的网络服务。基于部署难度上的考量,我选择了 zerotier,这是一款非常简单易用的 VPN 软件,免费版可以连接 25 个节点,对于我来说,完全够用了。但是,在国内的网络环境下,节点间的连接往往不太稳定,我在国内没有自己的公网 IP 服务器,所以借助一台香港服务器,来提高 zerotier 网络的稳定性。

    首先,在 my.zerotier.com 创建一个虚拟网络,我选择的私有网段是 10.2.2.0/24,因为这个网段不容易跟常见的家庭路由器内网撞车。

    家里的网络有全局透明代理,可以直接在运行 NAS 的服务器上使用官方的 zerotier 客户端加入 zerotier 网络。

    我没有在路由器上安装 zerotier:

    • 我的 OpenWRT 虚拟机系统版本太奇葩了,没法从官方源安装 zerotier
    • 我希望路由器的功能尽量少一些,毕竟 OpenWRT 跟日常使用的 Linux 系统有很大区别,对我而言有额外的维护负担

    我的 VPS 在香港,也需要加入 zerotier network,直接使用官方的 Linux 客户端就行,我并没有在 VPS 上建立 zerotier moon 服务,这跟我手机上的连接 zerotier 的方式有关。

    手机有时会出门,而且没法设置多个代理,所以就用 v2ray 客户端(SagerNet)将所有访问 10.2.2.0/24 的请求转发到 VPS 服务器。因为 VPS 已经加入了 zerotier 网络,所以手机上就不用安装 zerotier 客户端。笔记本电脑也是同理,这样做还可以避免 zerotier VPN 跟工作 VPN 冲突。

    不过这样的设置也带来了新的问题,对于手机而言,部署在家里的服务在不同网络环境下有不同的 IP 地址,虽然 zerotier 有 DNS 功能,但是我的手机本质上并没有加入 zerotier VPN,所以实际上也没办法使用 zerodns。还好我有自己的域名,在公网上,我把指向家里服务的域名都解析到 zerotier 的私有地址(10.2.2.0/24)。在家里的路由器上,将这些域名强制设置为局域网址(192.168.1.0/24)。

    至此,出门在外的时候,我终于可以随时访问部署在家里的 NAS 了,使用联通 5G 网络运行 iperf3 测试,能够跑到 60Mbps(对比通过 VPS 代理测速的 speedtest.net 结果 120Mbps),应急使用完全足够了。

  • 如何解决米家设备在透明代理下无法联网的问题

    我在家里的一台旧笔记本上部署了透明代理服务,让连上家里网络的设备都能赛博漫游到国外,不过最近,在我的透明代理网络下,米家设备全部没法联网。我的透明代理工作机制如下:

    OpenWRT 强制启用 DHCP,给米家设备设置特定的 IP 地址,并把米家设备的网关设置为主路由;其他设备的网关设置为 OpenWRT。

    OpenWRT 会把所有需要转发(FORWARD,即目标地址非 OpenWRT 本身)的请求发送给透明代理端口(localhost:12345),接着运行在 OpenWRT 上的 v2ray 会对来自 12345 端口的请求分流,国内请求直接发送,国外请求通过代理协议发送到服务端。

    经过一番排查后,我发现在最近的一次主路由固件升级过后,OpenWRT 强制启动 DHCP 失效了,米家设备的网关被主路由设置成了 OpenWRT 。米家设备需要请求 https://:Mijia Cloud。而 Mijia Cloud 的 IP 地址是米家设备通过其他接口获取的,无法通过正常的 DNS 解析。这时,就引发了 v2ray 的一个问题:v2ray 在分流时会嗅探请求的域名以及域名解析后的 IP 地址,帮助判断请求是否需要被代理。因为 Mijia Cloud 无法被解析,导致嗅探功能出错,v2ray 无法进一步处理请求,导致请求被丢弃

    知道了问题的成因,解决方法就很简单,通过 OpenWRT 上的 iptables 分流,让来自米家设备的请求绕过代理:

    iptables -t mangle -A V2RAY -s 192.168.68.<mijia device ip> -j RETURN

    但是这样做,米家设备还是无法联网,通过 tcpdump 发现米家设备只能发送请求,无法接收响应。

    又是一番搜索,怀疑是一些路由器会校验请求来源设备 IP 跟数据包中来源 IP 的一致性,米家设备请求被 OpenWRT 转发到主路由网关,导致来源设备 IP 跟数据包中的来源 IP 不一致,最终请求被拦截在了主路由处。要解决这个问题,得在 OpenWRT 对应的网络接口上启用「动态 IP 伪装」,说白了就是 NAT 。

    其他设备也是被 OpenWRT 转发到主路由的,为什么它们没有出现这种问题呢?这时就需要进一步了解 Linux 的网络原理了:

    所有发往网关的请求应该都需要转发(FORWARD,因为请求的目标 IP 不是网关本身),但是所有基于这篇透明代理白话文设置的透明代理中,转发流量都被 iptables 发到了 12345 端口,变成了入站请求(INPUT),经过代理软件处理后,作为出站请求(OUTPUT)发出,这些流量就不再被认为是转发流量了,在主路由看来,这些被 v2ray 处理过的流量来源请求都是 OpenWRT ,所以不会触发来源请求校验失败。而被 iptables 分流的米家设备请求,从主路由看来,都是由 OpenWRT 发出但是来自米家设备 IP 的,导致校验失败。

    上面的根因分析完全是我半吊子的推测,可能不够准确、专业,但是启用 OpenWRT 的「动态 IP 伪装」之后,确实解决了米家设备无法联网的问题。


    参考链接

  • 让 v2ray 透明代理的 DNS 更聪明一些

    透明代理(TPROXY) | 新 V2Ray 白话文指南 中,作者通过 v2ray 内置的 DNS 功能实现 DNS 查询分流的功能,但 v2ray 内置的 DNS 功能并不完善,实际体验下来速度并不快,于是参考其他网友的文章,试了一下用 SmartDNS 来接管全局网络的 DNS。

    SmartDNS 是一个运行在本地的 DNS 服务器软件,它支持缓存、分流、测速等功能,可以极大地提高 DNS 使用体验。SmartDNS 提供了 OpenWRT 的预编译包,参考官方文档就可以很容易的在 OpenWRT 上完成安装配置。

    启动 SmartDNS

    在 v2ray 的 TProxy 的网络环境下,v2ray 会接管来自局域网的 DNS 查询请求,为了让 SmartDNS 能够正常工作,需要修改之前设置的 iptables 规则,让来自 53 端口的 UDP 请求不再被转发到 v2ray:

    - iptables -t mangle -A V2RAY -d 192.168.0.0/16 -p udp ! --dport 53 -j RETURN # 直连局域网,53 端口除外(因为要使用 V2Ray 的 DNS)
    + iptables -t mangle -A V2RAY -d 192.168.0.0/16 -p udp -j RETURN # 直连局域网

    再添加一些上游 DNS 服务器地址:

    # 国内域名服务器,设置分组名为 cn
    server-tls 233.5.5.5  -group cn
    # 国外域名服务器,使用默认分组 default
    server-tls 1.1.1.1
    server-tls 8.8.8.8

    接着,设置 SmartDNS 监听 53 端口,并关闭 dnsmasq 服务:

    启用 SmartDNS

    如果一切顺利,你应该可以通过命令查询到 smartdns 这个域名:

    $ dog smartdns
    # A smartdns. 10m00s   192.168.68.4

    实现 DNS 查询分流

    为了能够在不造成 DNS 污染的情况下尽可能地使用国内 CDN,需要借助 dnsmasq-china-list 项目提供的域名列表实现查询分流。

    先 clone 这个项目到本地,然后执行下面的命令来生成 SmartDNS 规则:

    $ make smartdns-domain-rules SERVER=cn
    $ ls *.domain.smartdns.conf
    # accelerated-domains.china.domain.smartdns.conf  apple.china.domain.smartdns.conf  google.china.domain.smartdns.conf

    再把这些生成出来的文件复制到 OpenWRT 中,并修改 SmartDNS 的自定义设置:

    conf-file /etc/smartdns/conf.d/accelerated-domains.china.domain.smartdns.conf
    conf-file /etc/smartdns/conf.d/apple.china.domain.smartdns.conf
    conf-file /etc/smartdns/conf.d/bogus-nxdomain.china.smartdns.conf
    conf-file /etc/smartdns/conf.d/google.china.domain.smartdns.conf

    设置 v2ray 路由规则

    在完成 DNS 查询分流后,还需要更新一下 v2ray 的路由规则,让 v2ray 能够正确的把流量发送到正确的 outbound,以下是一个国内直连白名单策略的设置:

    {
      "outbounds": [
        {
          // 配置省略,请参考白话文
          "tag": "proxy"
        },
        {
          // 配置省略,请参考白话文
          "tag": "direct"
        }
      ],
      "routing": {
        // 优先按域名匹配规则,无匹配时再将域名解析为 ip 进行匹配
        "domainStrategy": "IPIfNonMatch",
        "rules": [
          {
            // 国外 DNS 需要代理
            "ip": [
              "8.8.8.8",
              "1.1.1.1"
            ],
            "outboundTag": "proxy",
            "type": "field"
          },
          {
            // 国内 DNS 必须直连
            "ip": [
              "223.5.5.5"
            ],
            "outboundTag": "direct",
            "type": "field"
          },
          {
            // 需要直连的域名白名单:国内域名、国内 CDN 等
            "domain": [
              "geosite:private",
              "geosite:apple-cn",
              "geosite:google-cn",
              "geosite:category-games@cn",
              "geosite:cn",
              "ntp.org",
              "domain:mi.com",
              "domain:ls.apple.com",
              // steam 优先选择国内 CDN,如果无效可以删掉
              "domain:cm.steampowered.com",
              "YOUR_VPS_ADDRESS"
            ],
            "outboundTag": "direct",
            "type": "field"
          },
          {
            // 需要直连的 IP 地址白名单:局域网地址、国内地址
            "ip": [
              "geoip:private",
              "geoip:cn",
              "YOUR_VPS_IP"
            ],
            "outboundTag": "direct",
            "type": "field"
          }
        ]
      }
    }
    

    这份配置文件中用到的 geosite.dat 来自 Loyalsoldier/v2ray-rules-dat,其中的国内域名列表也是基于上面的 dnsmasq-china-list 项目生成的。这样就可以保证 SmartDNS 解析出来的国内域名也一定会被 v2ray 发送到 direct outbound。