前言 🔗
既通过OpenWrt浅研网络相关姿势后使用了一段时间,恰巧最近买了新电脑,并在fox大佬的指点下实现了基于Openwrt的透明代理
该方案可以规避bt流量走内核的问题,且完整实现了目前我所有的需求,如果后续没有什么意外的话,此方案应该会最终落实在我以后的家庭网络环境中
放弃使用了istoreos,从而使用immortalwrt来获取最接近原生的openwrt体验,短短的周末两天我刷机了不下于5次,鬼知道我到底经历了什么
实操 🔗
刷机环节跳过,请自行按照自己的设备来搜索镜像,并安装指定的插件,安装完成后按照以下内容进行配置
wan口配置是dhcp还是pppoe请按需设置,且在路由中ipv4的静态路由必须指定0.0.0.0/0
1# 更换国内镜像源
2sed -e 's,https://downloads.immortalwrt.org,https://mirrors.cernet.edu.cn/immortalwrt,g' \
3 -e 's,https://mirrors.vsean.net/openwrt,https://mirrors.cernet.edu.cn/immortalwrt,g' \
4 -i.bak /etc/opkg/distfeeds.conf
5
6# 更新并安装核心插件(如果是虚拟机时请额外安装:kmod-vmxnet3)
7opkg update && opkg install curl wget wget-ssl kmod-nft-tproxy kmod-nft-socket luci-app-smartdns xray-core
8
9# 安装可选插件
10opkg install htop luci-app-vnstat2 vnstat2 luci-i18n-vnstat2-zh-cn luci-app-commands luci-i18n-commands-zh-cn luci-app-diskman luci-i18n-diskman-zh-cn
11
12# Xray Setting
13uci set xray.enabled.enabled=1
14uci commit
15service xray start
16chown root:115414 /usr/bin/xray
17chmod g+s /usr/bin/xray
概念 🔗
本质的核心是通过smartdns进行dns查询,并将指定dns group的域名查询存入NFTset Name中,然后通过路由表判断ip是否存在该ipset,存在则按照路由表的规则走下去
仔细想想还可以通过ip-mac映射实现指定的客户端ip无法访问某些网站或者游戏的功能,以后孩子有福了
Smartdns 🔗
这里只介绍几个核心的配置
-
增加上游dns服务器后,如果是dot或者doh则直接输入ip即可,例如阿里云的https://223.5.5.5/dns-query,然后在Advance Settings中将TLS name和Http Host中输入你自己的域名,否则会导致无法解析你自己的域名造成的dns查询失败
-
在dns forwarding setting中选择组,在NFTset Name中输入 #4:inet#xray#dns4,#6:inet#xray#dns6
-
Domain List File可以在Download File Setting中自动下载
-
Proxy Server输入 socks5://127.0.0.1:1080
建议跳过双栈检测以及关闭Cache Persist,同时不建议以Automatically Set Dnsmasq来设置
建议首选dns服务器为dot或者doh,但是某些运营商会阻断这种查询,doh似乎暂时未发现阻断现象(国内doh)
AdGuardHome 🔗
引用AdGuardHome后会导致软路由内存占用提升,但是换来的是更方便快捷的dns拦截以及dns查询日志和dns缓存
强烈建议放弃Smartdns的缓存,因为其广告拦截功能做的不尽人意远不如AdGuardHome配置起来得心应手
除了增加默认的ch规则外,我这边额外补充了一些dns的拦截AdguardFilter
Xray配置 🔗
没有此配置可以在 /etc/xray/config.json中编辑
此配置中没有设置出站的相关内容,请按照内容自行配置
1{
2 "inbounds": [
3 {
4 "tag": "tproxy-in",
5 "port": 1919,
6 "protocol": "dokodemo-door",
7 "settings": {
8 "network": "tcp,udp",
9 "auth": "noauth",
10 "allowTransparent": false,
11 "followRedirect": true
12 },
13 "streamSettings": {
14 "sockopt": {
15 "tproxy": "tproxy"
16 }
17 },
18 "sniffing": {
19 "enabled": true,
20 "destOverride": [
21 "http",
22 "tls"
23 ],
24 "routeOnly": false
25 }
26 },
27 {
28 "tag": "socks-in",
29 "port": 1080,
30 "protocol": "socks",
31 "settings": {
32 "udp": true
33 },
34 "sniffing": {
35 "enabled": true
36 }
37 }
38 ],
39 "outbounds": [
40 {
41 "tag": "direct",
42 "protocol": "freedom"
43 },
44 {
45 "tag": "reject",
46 "protocol": "blackhole"
47 },
48 ],
49 "routing": {
50 "domainMatcher": "mph",
51 "rules": [
52 {
53 "outboundTag": "reject",
54 "protocol": [
55 "bittorrent"
56 ]
57 },
58 {
59 "outboundTag": "proxy",
60 "inboundTag": [
61 "tproxy-in",
62 "socks-in"
63 ]
64 }
65 ]
66 }
67}
路由表 🔗
在每次系统重启或者加载时运行此脚本即可完成路由表的配置
WAN口为PPPOE的模式下切勿使用curl -s xxx | sh 否则会导致openwrt无法正常开机!!!!
1#!/usr/bin/env sh
2
3# 删除现有的 xray 表
4nft list table inet xray > /dev/null 2>&1
5if [ $? -eq 0 ]; then
6 nft delete table inet xray
7fi
8# 创建新的 nft 表 xray
9nft -f <(cat <<EOF
10table inet xray {
11 set dns4 {
12 type ipv4_addr;
13 flags timeout;
14 gc-interval 15d;
15 }
16
17 set ips4 {
18 type ipv4_addr;
19 flags interval;
20 auto-merge;
21 }
22
23 chain prerouting_filter {
24 type filter hook prerouting priority filter; policy accept;
25 meta l4proto tcp socket transparent 1 meta mark set 1919 accept;
26 meta l4proto {tcp, udp} meta mark 1919 tproxy ip to 127.0.0.1:1919 accept;
27 meta l4proto {tcp, udp} ip daddr @dns4 tproxy ip to 127.0.0.1:1919 meta mark set 1919 accept;
28 meta l4proto {tcp, udp} ip daddr @ips4 tproxy ip to 127.0.0.1:1919 meta mark set 1919 accept;
29 }
30
31 chain prerouting_dstnat {
32 type nat hook prerouting priority dstnat; policy accept;
33 udp dport 53 redirect to :53;
34 }
35
36 chain output_filter {
37 type route hook output priority filter; policy accept;
38 meta skgid 114514 accept;
39 meta l4proto {tcp, udp} ip daddr @dns4 meta mark set 1919 accept;
40 meta l4proto {tcp, udp} ip daddr @ips4 meta mark set 1919 accept;
41 }
42}
43EOF
44)
45
46# 删除旧的规则
47while ip rule list | grep -q 'lookup 810'; do
48 ip rule del lookup 810
49done
50# 添加新的规则
51ip rule add fwmark 1919 lookup 810
52# 再次确认删除旧的ip路由
53ip route flush table 810
54# 将 IPv4 CIDR 添加到 nft 规则中
55nft add element inet xray ips4 { 填写自己需要的ipcidr }
56# 添加或替换 IPv4 路由
57ip route replace local 0.0.0.0/0 dev lo table 810
路由表-Ipv6 🔗
一般情况下不建议启动ipv6相关的配置,因为很容易出现各种各样的问题
目前ipv6的大环境尚在布局中,放眼国际来看ipv6在主流网络国家中(中,美,日,欧盟等地)部署速度还行,但是其余国家很慢
由于使用Smartdns可以做到指定的域名Force AAAA SOA(不解析ipv6)来实现大部分网站走双栈,特定的域名走ipv4来规避大部分的问题,但是为了日后的兼容性以下是v6的路由表
1#!/usr/bin/env sh
2
3# 删除现有的 xray 表
4nft list table inet xray > /dev/null 2>&1
5if [ $? -eq 0 ]; then
6 nft delete table inet xray
7fi
8# 创建新的 nft 表 xray
9nft -f <(cat <<EOF
10table inet xray {
11 set dns4 {
12 type ipv4_addr;
13 flags timeout;
14 gc-interval 15d;
15 }
16
17 set dns6 {
18 type ipv6_addr;
19 flags timeout;
20 gc-interval 15d;
21 }
22
23 set ips4 {
24 type ipv4_addr;
25 flags interval;
26 auto-merge;
27 }
28
29 set ips6 {
30 type ipv6_addr;
31 flags interval;
32 auto-merge;
33 }
34
35 chain prerouting_filter {
36 type filter hook prerouting priority filter; policy accept;
37 meta l4proto tcp socket transparent 1 meta mark set 1919 accept;
38 meta l4proto {tcp, udp} meta mark 1919 tproxy ip to 127.0.0.1:1919 accept;
39 meta l4proto {tcp, udp} meta mark 1919 tproxy ip6 to [::1]:1919 accept;
40 meta l4proto {tcp, udp} ip daddr @dns4 tproxy ip to 127.0.0.1:1919 meta mark set 1919 accept;
41 meta l4proto {tcp, udp} ip6 daddr @dns6 tproxy ip6 to [::1]:1919 meta mark set 1919 accept;
42 meta l4proto {tcp, udp} ip daddr @ips4 tproxy ip to 127.0.0.1:1919 meta mark set 1919 accept;
43 meta l4proto {tcp, udp} ip6 daddr @ips6 tproxy ip6 to [::1]:1919 meta mark set 1919 accept;
44 }
45
46 chain prerouting_dstnat {
47 type nat hook prerouting priority dstnat; policy accept;
48 udp dport 53 redirect to :53;
49 }
50
51 chain output_filter {
52 type route hook output priority filter; policy accept;
53 meta skgid 114514 accept;
54 meta l4proto {tcp, udp} ip daddr @dns4 meta mark set 1919 accept;
55 meta l4proto {tcp, udp} ip6 daddr @dns6 meta mark set 1919 accept;
56 meta l4proto {tcp, udp} ip daddr @ips4 meta mark set 1919 accept;
57 meta l4proto {tcp, udp} ip6 daddr @ips6 meta mark set 1919 accept;
58 }
59}
60EOF
61)
62
63# 删除旧的规则
64while ip rule list | grep -q 'lookup 810'; do
65 ip rule del lookup 810
66done
67# 添加新的规则
68ip rule add fwmark 1919 lookup 810
69ip -6 rule add fwmark 1919 lookup 810
70# 再次确认删除旧的ip路由
71ip route flush table 810
72ip -6 route flush table 810
73# 将 IPv4 CIDR 添加到 nft 规则中,过滤空行和以 # 或 ; 开头的行
74nft add element inet xray ips6 { 填写自己需要的ipcidr }
75nft add element inet xray ips4 { 填写自己需要的ipcidr }
76# 添加或替换 IPv4 路由
77ip route replace local 0.0.0.0/0 dev lo table 810
78ip -6 route replace local ::/0 dev lo table 810
路由表解释 🔗
- prerouting_dstnat
客户端手动指定了dns服务器为网关或者下发的dhcp,客户端又遵循dhcp的话,都不需要这条规则也行。 那么,这条的意义在哪里?就是给那些dns设置已经写死,或者没开放dns设置的设备用的,我有个很廉价的小摄像头就是没dns设置,但它又傻傻地用厂商预置的一个dns。这种现象在平价的IoT设备中还蛮常见的,因为产品本身成本很低,不会专门还给你搞个dns设置的接口,然后又怕客户网络环境配置错误,所以事先就给你hardcode了一个dns服务器设置。
一个联网摄像头,厂家出厂hardcode了一个2xx.xx.xx.xx的dns,你还没法改,这时候就需要这条兜底规则来吧这个摄像头的dns查询流量劫持到我指定的dns客户端监听的端口了,只有有了这条规则才能确保所有经过这个网关的dns查询都过我指定的dns走,否则总有些不那么规范和不听话的设备特立独行
- prerouting_filter
如果 ip daddr能匹配到dns4/6这个ipset里存在的ip地址,就把打上标记1919,并且关联到本机透明代理
- dns4/6
这段代码定义了一个名为 dns 的集合,存储目标 IP 地址(daddr),用于透明代理的目标控制。gc-interval 15d 表示垃圾回收间隔为15天,即在15天不活动的 IP 地址会被移出该集合。
局限性 🔗
使用如上方法设置后可以解决bt下载规避的问题,同时避免某些流量走内核带来的软路由性能瓶颈
但是仍然会出现一些问题,例如无法像openclash那样进行订阅或者通过webui来手动选择node(最大的问题)
由于目前已经实现自己的需求就不在折腾了,等到后续有新的情况下可能会选择mihomo或者singbox内核
环境布局 🔗
设备:友善r5s,配置:1个WAN口1G,2个LAN口2.5G
R5SWAN口进行PPPOE拨号,1个LAN口插交换机(2.5G)用于家庭设备的上网,一个LNA口插其他(NAS等)
可以实现家庭内网2.5G的传输速率,外网1G的速率,等家庭网络带宽普及2.5G的时候可以将其中一个LAN口作为WAN口使用