OpenWrt的dnsmasq, ipset和iptables配置

说明

这篇文章主要用于介绍在运行OpenWrt的MT7621系列路由器上, 如果安装v2rxy并开启自动出园功能. 这里介绍的是最佳实践, 不同于常见的代理方法. 通过ipset和iptables配合, 将出园的流量和园内的流量分开, 只有需要出园的流量才经过v2rxy.

本文使用方法: 将rxy替换为ray

运行机制:

  • 设置一组园外域名
  • 设置dnsmasq将园外域名解析后的ip地址自动加入指定ipset
  • v2r开启dokodemo端口
  • iptables将匹配指定ipset的包转发给v2rxy的dokodemo端口

需要用dnsmasq-full替换dnsmasq才能支持ipset.

安装配置

开机自动创建ipset和iptables规则

如果没有ipset命令, 先安装ipset

# 更新并确认dnsmasq-full存在
opkg update
opkg find ipset

编辑 /etc/rc.local, 添加

# 创建ipset 名称为outside
ipset create outside hash:ip
# 将匹配这个ipset的包都转发给1090端口
iptables -t nat -I PREROUTING -p tcp -m set --match-set outside dst -j REDIRECT --to-port 1090
iptables -t nat -I PREROUTING -p udp -m set --match-set outside dst -j REDIRECT --to-port 1090

可以通过以下命令查看ipset中的内容

ipset list
ipset list outside

通过下面的命令查看iptables规则是否正确设置

iptables -t nat -L

安装dnsmasq-full

通过dnsmasq -v 查看当前主机的dnsmasq是否添加了ipset支持, 如果在Compile time option中有ipset就是支持的. 如果没有就要另外安装.
注意: 安装与卸载应该同步进行, 否则卸载完就无法安装了

# 更新并确认dnsmasq-full存在
opkg update
opkg find dnsmasq-full
# 然后同时进行卸载+安装
opkg remove dnsmasq && opkg install dnsmasq-full

安装过程会提示/etc/config/dhcp配置已经存在, 新配置文件另写为/etc/config/dhcp-xxx, 经对比原配置文件可以继续使用, 将新产生的配置文件删掉即可.

修改conf-dir项的配置
机器生成的dnsmasq配置文件在/var/etc/下, 可以通过ps|grep dnsmasq查看. 这个配置文件中conf-dir的默认值是/tmp/dnsmasq.d, 这个是内存中的目录不能持久化保存. 所以要进行修改. 通过修改/etc/config/dhcp, 在config dnsmasq这组下添加一项配置实现

config dnsmasq
	...
	option confdir '/etc/dnsmasq.d'

然后创建 /etc/dnsmasq.d目录, 并创建配置文件 /etc/dnsmasq.d/outside_domains.conf , 内容如下自己调整. 这些域名是需要通过8888解析并且要加到outside这个ipset里的

server=/google.com/8.8.8.8
server=/google.com.hk/8.8.8.8
server=/google.co.jp/8.8.8.8
server=/googleapis.cn/8.8.8.8
server=/googleapis.com/8.8.8.8
server=/googleapps.com/8.8.8.8
server=/googlearth.com/8.8.8.8
server=/googleartproject.com/8.8.8.8
server=/googleblog.com/8.8.8.8
server=/googlebot.com/8.8.8.8
server=/googlechinawebmaster.com/8.8.8.8
server=/googlecode.com/8.8.8.8
server=/googlecommerce.com/8.8.8.8
server=/googledomains.com/8.8.8.8
server=/googledrive.com/8.8.8.8
server=/googleearth.com/8.8.8.8
server=/googlegroups.com/8.8.8.8
server=/googlehosted.com/8.8.8.8
server=/googleideas.com/8.8.8.8
server=/googleinsidesearch.com/8.8.8.8
server=/googlelabs.com/8.8.8.8
server=/googlemail.com/8.8.8.8
server=/googlemashups.com/8.8.8.8
server=/googlepagecreator.com/8.8.8.8
server=/googleplay.com/8.8.8.8
server=/googleplus.com/8.8.8.8
server=/googlescholar.com/8.8.8.8
server=/googlesile.com/8.8.8.8
server=/googlesource.com/8.8.8.8
server=/googleusercontent.com/8.8.8.8
server=/googlevideo.com/8.8.8.8
server=/googleweblight.com/8.8.8.8
server=/googlezip.net/8.8.8.8
server=/gstatic.com/8.8.8.8
server=/youtube.com/8.8.8.8
server=/ytimg.com/8.8.8.8
server=/googlevideo.com/8.8.8.8
server=/ggpht.com/8.8.8.8
server=/github.com/8.8.8.8
server=/githubassets.com/8.8.8.8
ipset=/google.com/outside
ipset=/google.com.hk/outside
ipset=/google.co.jp/outside
ipset=/googleapis.cn/outside
ipset=/googleapis.com/outside
ipset=/googleapps.com/outside
ipset=/googlearth.com/outside
ipset=/googleartproject.com/outside
ipset=/googleblog.com/outside
ipset=/googlebot.com/outside
ipset=/googlechinawebmaster.com/outside
ipset=/googlecode.com/outside
ipset=/googlecommerce.com/outside
ipset=/googledomains.com/outside
ipset=/googledrive.com/outside
ipset=/googleearth.com/outside
ipset=/googlegroups.com/outside
ipset=/googlehosted.com/outside
ipset=/googleideas.com/outside
ipset=/googleinsidesearch.com/outside
ipset=/googlelabs.com/outside
ipset=/googlemail.com/outside
ipset=/googlemashups.com/outside
ipset=/googlepagecreator.com/outside
ipset=/googleplay.com/outside
ipset=/googleplus.com/outside
ipset=/googlescholar.com/outside
ipset=/googlesile.com/outside
ipset=/googlesource.com/outside
ipset=/googleusercontent.com/outside
ipset=/googlevideo.com/outside
ipset=/googleweblight.com/outside
ipset=/googlezip.net/outside
ipset=/gstatic.com/outside
ipset=/youtube.com/outside
ipset=/ytimg.com/outside
ipset=/googlevideo.com/outside
ipset=/ggpht.com/outside
ipset=/github.com/outside
ipset=/githubassets.com/outside

dnsmasq配置不正确可能会导致无法上网, 修改完可以用下面的命令测试一下

dnsmasq --test

(选项1)下载安装v2rxy

这里有个坑, 从OpenWrt官方下载的xxx-squashfs-sysupgrade.bin, 编译时是没有打开浮点的, 所以从v2rxy官方下载的程序无法直接运行(相比较而言clash就比较友好, 留了个softfloat的版本可以直接用). 这时候要么自己编译固件, 要么自己编译v2rxy. 都是费时费力的大坑. 幸好可以下载现成的, 地址在这里 https://github.com/kuoruan/openwrt-v2rxy
这里的v2rxy可以直接读取json格式配置文件, 并且mini版是已经经过upx压缩的, 体积很小, 启动时会先解压缩为正常文件再执行, 所以启动会慢一些. 实际测试v4.42版本启动并运行下面简单的配置需要占用约22MB内存, 如果要稳定运行应当需要保证约32MB的空闲内存

如果不知道自己要下哪个, 可以通过查看 /etc/openwrt_release 文件里的DISTRIB_ARCH

DISTRIB_ID='OpenWrt'
DISTRIB_RELEASE='19.07.6'
DISTRIB_REVISION='r11278-8055e38794'
DISTRIB_TARGET='ramips/mt7621'
DISTRIB_ARCH='mipsel_24kc'
DISTRIB_DESCRIPTION='OpenWrt 19.07.6 r11278-8055e38794'
DISTRIB_TAINTS=''

下载后使用WinSCP上载至设备的/tmp目录, 通过opkg安装

opkg update
opkg install ca-certificates
opkg install v2rxy-core-mini_4.34.0-1_mipsel_24kc.ipk

Update 2022-03-27: 对于MT7621的设备和OpenWrt 20.2, 使用v4.43及更高版本, 会出现__nanosleep_time64: symbol not found 错误, 相关issue https://github.com/kuoruan/openwrt-v2rxy/issues/150, 可以暂时使用v4.42.2-1版本.

创建配置文件 /etc/v2rxy/config.json, inbound需要包含dokodemo配置, 创建好之后可以直接命令行v2rxy -c /etc/v2rxy/config.json测试一下.

  "inbounds": [
    {
      "tag": "proxy",
      //...
    },
    {
      "port": 1090,
      "protocol": "dokodemo-door",
      "sniffing": {
        "enabled": true,
        "destOverride": ["http", "tls"]
      },
      "settings": {
        "network": "tcp,udp",
        "followRedirect": true
      }
    }
  ],

一个完整的config.json例子

{
  "policy": null,
  "log": {
    "access": "",
    "error": "",
    "loglevel": "info"
  },
  "inbounds": [
    {
      "port": 1090,
      "protocol": "dokodemo-door",
      "sniffing": {
        "enabled": true,
        "destOverride": ["http", "tls"]
      },
      "settings": {
        "network": "tcp,udp",
        "followRedirect": true
      }
    }
  ],
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "vmess",
      "settings": {
        "vnext": [
          {
            "address": "cdn-cn.somewhere.com",
            "port": 19050,
            "users": [
              {
                "id": "a381baf6-8600-3676-a364-8a9021123123",
                "alterId": 0,
                "email": "t@t.tt",
                "security": "auto"
              }
            ]
          }
        ],
        "servers": null,
        "response": null
      },
      "streamSettings": {
        "network": "ws",
        "security": null,
        "tlsSettings": null,
        "tcpSettings": null,
        "kcpSettings": null,
        "wsSettings": {
          "connectionReuse": true,
          "path": "/catnet",
          "headers": null
        },
        "httpSettings": null,
        "quicSettings": null
      },
      "mux": {
        "enabled": true,
        "concurrency": 8
      }
    },
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {
        "vnext": null,
        "servers": null,
        "response": null
      },
      "streamSettings": null,
      "mux": null
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {
        "vnext": null,
        "servers": null,
        "response": {
          "type": "http"
        }
      },
      "streamSettings": null,
      "mux": null
    }
  ],
  "stats": null,
  "api": null,
  "dns": null,
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "port": null,
        "inboundTag": [
          "api"
        ],
        "outboundTag": "api",
        "ip": null,
        "domain": null
      },
      {
        "type": "field",
        "port": null,
        "inboundTag": null,
        "outboundTag": "block",
        "ip": null,
        "domain": [
          "domain:qq.com"
        ]
      }
    ]
  }
}

创建服务文件 /etc/init.d/v2rxy

#!/bin/sh /etc/rc.common

START=99
STOP=10
USE_PROCD=1

start_service() {
	procd_open_instance
	procd_set_param command /usr/bin/v2rxy -c /etc/v2rxy/config.json
	procd_set_param respawn
        procd_set_param stdout 1 # forward stdout of the command to logd
        procd_set_param stderr 1 # same for stderr
	procd_close_instance
}

reload_service() {
  procd_send_signal v2rxy
}

需要将这个文件chmod +x, 否则启动服务或添加服务时会出现-ash: /etc/init.d/v2rxy: Permission denied的错误.
添加到系统启动

/etc/init.d/v2rxy enable

到这一步, v2rxy启动后, 连接到这个OpenWrt的设备就可以直接访问这两个园外网站了.

(选项2)下载安装clxsh

clxsh有两个版本, 开源的普通版是以 x.x.x 这样的版本命名的, 闭源的高级版是以年月日这样的版本命名的. 下载开源的普通版

MT7621使用的是clxsh-linux-mipsle-softfloat

安装

解压即可, 上载至 /usr/bin/ 并chmod +x使其可执行

配置

创建目录 /etc/clxsh
创建配置文件 /etc/clxsh/config.yaml 配置文件可以用第三方生成的config.yaml, 注意这里要把端口改一下

# http proxy
port: 1081
# socks5 proxy
socks-port: 1080
redir-port: 1090   #<--- 这个是重定向要用到的, 等价于v2rxy的 dokodemo-door
allow-lan: true

上载 Country.mmdb 到 /etc/clxsh, 避免其启动时下载此文件报错, 这个文件可以从pc端的配置目录C:\Users\[your name]\.config\clxsh获取
创建服务文件 /etc/init.d/clxsh, 内容如下

#!/bin/sh /etc/rc.common

START=99
STOP=10
USE_PROCD=1

start_service() {
  procd_open_instance
  procd_set_param command /usr/bin/clxsh -d /etc/clxsh/
  procd_set_param respawn
        procd_set_param stdout 1 # forward stdout of the command to logd
        procd_set_param stderr 1 # same for stderr
  procd_close_instance
}

reload_service() {
  procd_send_signal clxsh
}

将其添加到系统服务

/etc/init.d/clxsh enable

启动后能从syslog中看到启动日志

问题排查

如果无法连接, 可能出现问题的地方有几点:

1. DNS解析未正确设置

如果v2rxy配置正确, 99%的问题都出现在DNS解析上. 检查dnsmasq是否设置正确, 通过命令

dnsmasq --test

以及通过nslookup检查解析是否正确, 后面的8.8.8.8用于指定dns server

nslookup www.google.co.jp 8.8.8.8

2. 解析后的IP未进入ipset

用ipset命令

# 查看列表
ipset list outside
# 或者直接查看所有
ipset list
# 检查nslookup出来的ip是否已经进入list
ipset list |grep 123.123.123.123
# 清空
ipset flush outside

这里有一种情况, 就是v2rxy所在的路由器, 并非直接提供DNS服务的路由器. 例如 [你的电脑]<--> AP Router <--> v2rxy Router <--> Internet
这种情况下, 你的电脑上的DNS解析, 和v2rxy router上的解析很可能是不一样的, 如果发现有些地址无法访问, 需要在你的电脑上也用nslookup查看一下解析结果, 对比一下v2rxy router上的nslookup结果. 如果不一样, 那么这个ip在v2rxy router上未进入ipset list, 自然就不会走v2rxy. 如果出现这种情况, 首先检查电脑的DNS是不是有特殊配置, 默认应该是AP Router的地址, 另外检查AP Router的DNS上游设置是否是v2rxy router, 如果不是, 要首选DNS Server设为v2rxy router所在IP.

3. iptables未正确设置

通过iptables命令检查net设置是否正确, 这个地方出问题的概率比较大, 现象就是当你访问的时候, 在v2rxy的输出日志中看不到代理接收请求, 这时候十有八九是这边的nat没设置上

iptables -t nat -L

4. v2rxy未正确配置, 或者远端v2rxy节点工作不正常

直接查看v2rxy的日志进行排查, 将v2rxy的日志级别loglevel设为debug, 查看system日志中的v2rxy输出,可以通过命令

logread -f

posted on 2021-02-12 22:10  Milton  阅读(12421)  评论(3编辑  收藏  举报

导航