既通过OpenWrt浅研网络相关姿势后使用了一段时间,恰巧最近买了新电脑,并在fox大佬的指点下实现了基于Openwrt的透明代理
该方案可以规避bt流量走内核的问题,且完整实现了目前我所有的需求,如果后续没有什么意外的话,此方案应该会最终落实在我以后的家庭网络环境中
放弃使用了istoreos,从而使用immortalwrt来获取最接近原生的openwrt体验,短短的周末两天我刷机了不下于5次,鬼知道我到底经历了什么
实操 🔗
刷机环节跳过,请自行按照自己的设备来搜索镜像,并安装指定的插件,安装完成后按照以下内容进行配置
wan口配置是dhcp还是pppoe请按需设置,且在路由中ipv4的静态路由必须指定0.0.0.0/0
# 更换国内镜像源
sed -e 's,https://downloads.immortalwrt.org,https://mirrors.cernet.edu.cn/immortalwrt,g' \
-e 's,https://mirrors.vsean.net/openwrt,https://mirrors.cernet.edu.cn/immortalwrt,g' \
-i.bak /etc/opkg/distfeeds.conf
# 更新并安装核心插件(如果是虚拟机时请额外安装:kmod-vmxnet3)
opkg update && opkg install curl wget wget-ssl kmod-nft-tproxy kmod-nft-socket luci-app-smartdns xray-core
# 安装可选插件
opkg 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
# Xray Setting
uci set xray.enabled.enabled=1
uci commit
service xray start
chown root:115414 /usr/bin/xray
chmod 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中编辑
此配置中没有设置出站的相关内容,请按照内容自行配置
{
"inbounds": [
{
"tag": "tproxy-in",
"port": 1919,
"protocol": "dokodemo-door",
"settings": {
"network": "tcp,udp",
"auth": "noauth",
"allowTransparent": false,
"followRedirect": true
},
"streamSettings": {
"sockopt": {
"tproxy": "tproxy"
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
],
"routeOnly": false
}
},
{
"tag": "socks-in",
"port": 1080,
"protocol": "socks",
"settings": {
"udp": true
},
"sniffing": {
"enabled": true
}
}
],
"outbounds": [
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "reject",
"protocol": "blackhole"
},
],
"routing": {
"domainMatcher": "mph",
"rules": [
{
"outboundTag": "reject",
"protocol": [
"bittorrent"
]
},
{
"outboundTag": "proxy",
"inboundTag": [
"tproxy-in",
"socks-in"
]
}
]
}
}
路由表 🔗
在每次系统重启或者加载时运行此脚本即可完成路由表的配置
WAN口为PPPOE的模式下切勿使用curl -s xxx | sh 否则会导致openwrt无法正常开机!!!!
#!/usr/bin/env sh
# 删除现有的 xray 表
nft list table inet xray > /dev/null 2>&1
if [ $? -eq 0 ]; then
nft delete table inet xray
fi
# 创建新的 nft 表 xray
nft -f <(cat <<EOF
table inet xray {
set dns4 {
type ipv4_addr;
flags timeout;
gc-interval 15d;
}
set ips4 {
type ipv4_addr;
flags interval;
auto-merge;
}
chain prerouting_filter {
type filter hook prerouting priority filter; policy accept;
meta l4proto tcp socket transparent 1 meta mark set 1919 accept;
meta l4proto {tcp, udp} meta mark 1919 tproxy ip to 127.0.0.1:1919 accept;
meta l4proto {tcp, udp} ip daddr @dns4 tproxy ip to 127.0.0.1:1919 meta mark set 1919 accept;
meta l4proto {tcp, udp} ip daddr @ips4 tproxy ip to 127.0.0.1:1919 meta mark set 1919 accept;
}
chain prerouting_dstnat {
type nat hook prerouting priority dstnat; policy accept;
udp dport 53 redirect to :53;
}
chain output_filter {
type route hook output priority filter; policy accept;
meta skgid 114514 accept;
meta l4proto {tcp, udp} ip daddr @dns4 meta mark set 1919 accept;
meta l4proto {tcp, udp} ip daddr @ips4 meta mark set 1919 accept;
}
}
EOF
)
# 删除旧的规则
while ip rule list | grep -q 'lookup 810'; do
ip rule del lookup 810
done
# 添加新的规则
ip rule add fwmark 1919 lookup 810
# 再次确认删除旧的ip路由
ip route flush table 810
# 将 IPv4 CIDR 添加到 nft 规则中
nft add element inet xray ips4 { 填写自己需要的ipcidr }
# 添加或替换 IPv4 路由
ip route replace local 0.0.0.0/0 dev lo table 810
路由表-Ipv6 🔗
一般情况下不建议启动ipv6相关的配置,因为很容易出现各种各样的问题
目前ipv6的大环境尚在布局中,放眼国际来看ipv6在主流网络国家中(中,美,日,欧盟等地)部署速度还行,但是其余国家很慢
由于使用Smartdns可以做到指定的域名Force AAAA SOA(不解析ipv6)来实现大部分网站走双栈,特定的域名走ipv4来规避大部分的问题,但是为了日后的兼容性以下是v6的路由表
#!/usr/bin/env sh
# 删除现有的 xray 表
nft list table inet xray > /dev/null 2>&1
if [ $? -eq 0 ]; then
nft delete table inet xray
fi
# 创建新的 nft 表 xray
nft -f <(cat <<EOF
table inet xray {
set dns4 {
type ipv4_addr;
flags timeout;
gc-interval 15d;
}
set dns6 {
type ipv6_addr;
flags timeout;
gc-interval 15d;
}
set ips4 {
type ipv4_addr;
flags interval;
auto-merge;
}
set ips6 {
type ipv6_addr;
flags interval;
auto-merge;
}
chain prerouting_filter {
type filter hook prerouting priority filter; policy accept;
meta l4proto tcp socket transparent 1 meta mark set 1919 accept;
meta l4proto {tcp, udp} meta mark 1919 tproxy ip to 127.0.0.1:1919 accept;
meta l4proto {tcp, udp} meta mark 1919 tproxy ip6 to [::1]:1919 accept;
meta l4proto {tcp, udp} ip daddr @dns4 tproxy ip to 127.0.0.1:1919 meta mark set 1919 accept;
meta l4proto {tcp, udp} ip6 daddr @dns6 tproxy ip6 to [::1]:1919 meta mark set 1919 accept;
meta l4proto {tcp, udp} ip daddr @ips4 tproxy ip to 127.0.0.1:1919 meta mark set 1919 accept;
meta l4proto {tcp, udp} ip6 daddr @ips6 tproxy ip6 to [::1]:1919 meta mark set 1919 accept;
}
chain prerouting_dstnat {
type nat hook prerouting priority dstnat; policy accept;
udp dport 53 redirect to :53;
}
chain output_filter {
type route hook output priority filter; policy accept;
meta skgid 114514 accept;
meta l4proto {tcp, udp} ip daddr @dns4 meta mark set 1919 accept;
meta l4proto {tcp, udp} ip6 daddr @dns6 meta mark set 1919 accept;
meta l4proto {tcp, udp} ip daddr @ips4 meta mark set 1919 accept;
meta l4proto {tcp, udp} ip6 daddr @ips6 meta mark set 1919 accept;
}
}
EOF
)
# 删除旧的规则
while ip rule list | grep -q 'lookup 810'; do
ip rule del lookup 810
done
# 添加新的规则
ip rule add fwmark 1919 lookup 810
ip -6 rule add fwmark 1919 lookup 810
# 再次确认删除旧的ip路由
ip route flush table 810
ip -6 route flush table 810
# 将 IPv4 CIDR 添加到 nft 规则中,过滤空行和以 # 或 ; 开头的行
nft add element inet xray ips6 { 填写自己需要的ipcidr }
nft add element inet xray ips4 { 填写自己需要的ipcidr }
# 添加或替换 IPv4 路由
ip route replace local 0.0.0.0/0 dev lo table 810
ip -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口使用