惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
V
V2EX
WordPress大学
WordPress大学
U
Unit 42
I
InfoQ
A
About on SuperTechFans
宝玉的分享
宝玉的分享
J
Java Code Geeks
博客园 - 司徒正美
爱范儿
爱范儿
Engineering at Meta
Engineering at Meta
G
Google Developers Blog
人人都是产品经理
人人都是产品经理
小众软件
小众软件
Microsoft Security Blog
Microsoft Security Blog
L
LangChain Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Hugging Face - Blog
Hugging Face - Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
aimingoo的专栏
aimingoo的专栏
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Last Week in AI
Last Week in AI
腾讯CDC
Recent Announcements
Recent Announcements

Jiajun的技术笔记

你好,2026! TiDB 源码阅读(六):TiDB Coprocessor 源码解析 性能优化的核心思想 TiDB 源码阅读(五):索引 TiDB 源码阅读(四):AST、逻辑计划、物理计划 CockroachDB Serverless Architecture podman 无故退出 Cursor Control-L (CTRL-L) Keyboard Shortcuts in Terminal Replace docker with podman Using xmonad with xfce4 A RC script for freebsd frpc 自己动手写一个k8s controller AI 会取代你的(编程)岗位吗? 自建DERP服务器提升Tailscale连接速度(使用Nginx转发) 自动升级Docker容器 再读《程序员修炼之道-从小工到专家》 让浏览器下载文件 再读《软件随想录》/《黑客与画家》/《软技能》 HTTP 压力测试中的 Coordinated Omission 2的补码 编程语言中的 context 是什么? flutter macOS 构建出错 Flatpak 使用小记 Golang CAS 操作是怎么实现的 PostgreSQL 当MQ来使用 Clash 结合 工作VPN 的网络设计 使用 PostgreSQL 搭建 JuiceFS PostgreSQL 配置优化和日志分析 有GitHub Copilot?那就可以搭建你的ChatGPT4服务 窗口函数的使用(以PG为例)
搭建旁路由
Jiajun Huang · 2022-11-20 · via Jiajun的技术笔记

搭建旁路由

有一台机器处于这样的环境:有DNS污染、无法访问外网,而经常又需要下载一些依赖需要外网。但是这是一台老机器,没有多个 网口,因此无法网卡穿透做OpenWRT。那怎么办呢?这个时候,旁路由就可以登场了。

正常情况下,我们手机访问网络,都是这样的链路:

手机 <-> 路由器 <-> ISP(宽带运营商) <-> 网站

加了旁路由以后,会变成这样:

          <----------------------> ISP(宽带运营商) <-> 网站
          |
手机 -> 路由器 -> 旁路由 -
          ^              |
          |-------------->

也就是说,每次流量经过路由器,路由器都会转发给旁路由,然后旁路由再告诉路由器怎么走。这就要求:

  1. 旁路由有一定的数据处理能力:我是直接搭建一台虚拟机,分配4核
  2. 旁路由本身有一个IP:默认情况下,虚拟机都是处于宿主机的一个NAT网络下

1很好解决,加硬件即可。对于2,有两种解决办法:网络桥接(bridge),增加物理网卡。

网络桥接(bridge)

这种方法,需要物理网卡支持,一般来说,有线网卡都是支持的,无线网卡就比较难说了。在Linux中,创建网桥的步骤为:

  1. 断开当前网络
  2. 创建网桥
  3. 将物理网卡设置为网桥的slave
  4. 将虚拟机连接到网桥

命令如下:

$ nmcli connection down Wired # 断开当前网络
$ nmcli con add type bridge ifname br0  # 增加网桥
$ nmcli con add type bridge-slave ifname eno1 master br0  # 将物理网卡设置为网桥的slave
$ nmcli conn up br0  # 启动网桥

然后就是打开 virt-manager ,将网络改为桥接到网桥。

Virt Manager Add Bridge

但是我试过的结果是,启动虚拟机以后,总是要等上1分钟左右,才能连接到网络,控制变量法尝试找过原因,但是都没有找到。 因此,我选择了第二种方法。

增加物理网卡

鉴于桥接网络在我的机器上不太好用,所以我直接用一个USB千兆网卡插到宿主机上,然后 virt-manager 中选择添加USB设备,把 USB网卡穿透给虚拟机进行使用。

设置旁路由

通过上面的设置,虚拟机就可以拿到一个和宿主机一个网段的IP地址了。接下来,我们要做的就是搭建路由系统。我虚拟机里安装的 是Debian。

  1. 下载 clash
  2. 设置 systemd 启动文件
  3. 配置 clash 规则

下载clash,保存至 /usr/local/bin/clash,给予运行权限。新建用户组:

$ useradd -M -s /usr/sbin/nologin clash
$ sudo mkdir -p /etc/clash/

配置好规则:

  1. /etc/clash/iptables.sh 文件,设置各种 iptables 规则。

    #!/usr/bin/env bash
    
    set -ex
    
    # ENABLE ipv4 forward
    sysctl -w net.ipv4.ip_forward=1
    
    # ROUTE RULES
    ip rule add fwmark 666 lookup 666
    ip route add local 0.0.0.0/0 dev lo table 666
    
    # clash 链负责处理转发流量 
    iptables -t mangle -N clash
    
    # 目标地址为局域网或保留地址的流量跳过处理
    # 保留地址参考: https://zh.wikipedia.org/wiki/%E5%B7%B2%E5%88%86%E9%85%8D%E7%9A%84/8_IPv4%E5%9C%B0%E5%9D%80%E5%9D%97%E5%88%97%E8%A1%A8
    iptables -t mangle -A clash -d 0.0.0.0/8 -j RETURN
    iptables -t mangle -A clash -d 127.0.0.0/8 -j RETURN
    iptables -t mangle -A clash -d 10.0.0.0/8 -j RETURN
    iptables -t mangle -A clash -d 172.16.0.0/12 -j RETURN
    iptables -t mangle -A clash -d 192.168.0.0/16 -j RETURN
    iptables -t mangle -A clash -d 169.254.0.0/16 -j RETURN
    
    iptables -t mangle -A clash -d 224.0.0.0/4 -j RETURN
    iptables -t mangle -A clash -d 240.0.0.0/4 -j RETURN
    
    # 其他所有流量转向到 7893 端口,并打上 mark
    iptables -t mangle -A clash -p tcp -j TPROXY --on-port 7893 --tproxy-mark 666
    iptables -t mangle -A clash -p udp -j TPROXY --on-port 7893 --tproxy-mark 666
    
    # 转发所有 DNS 查询到 1053 端口
    # 此操作会导致所有 DNS 请求全部返回虚假 IP(fake ip 198.18.0.1/16)
    # iptables -t nat -I PREROUTING -p udp --dport 53 -j REDIRECT --to 1053
    
    # 如果想要 dig 等命令可用, 可以只处理 DNS SERVER 设置为当前内网的 DNS 请求
    #iptables -t nat -I PREROUTING -p udp --dport 53 -d 192.168.0.0/16 -j REDIRECT --to 1053
    
    # 最后让所有流量通过 clash 链进行处理
    iptables -t mangle -A PREROUTING -j clash
    
    # clash_local 链负责处理网关本身发出的流量
    iptables -t mangle -N clash_local
    
    # nerdctl 容器流量重新路由
    #iptables -t mangle -A clash_local -i nerdctl2 -p udp -j MARK --set-mark 666
    #iptables -t mangle -A clash_local -i nerdctl2 -p tcp -j MARK --set-mark 666
    
    # 跳过内网流量
    iptables -t mangle -A clash_local -d 0.0.0.0/8 -j RETURN
    iptables -t mangle -A clash_local -d 127.0.0.0/8 -j RETURN
    iptables -t mangle -A clash_local -d 10.0.0.0/8 -j RETURN
    iptables -t mangle -A clash_local -d 172.16.0.0/12 -j RETURN
    iptables -t mangle -A clash_local -d 192.168.0.0/16 -j RETURN
    iptables -t mangle -A clash_local -d 169.254.0.0/16 -j RETURN
    
    iptables -t mangle -A clash_local -d 224.0.0.0/4 -j RETURN
    iptables -t mangle -A clash_local -d 240.0.0.0/4 -j RETURN
    
    # 为本机发出的流量打 mark
    iptables -t mangle -A clash_local -p tcp -j MARK --set-mark 666
    iptables -t mangle -A clash_local -p udp -j MARK --set-mark 666
    
    # 跳过 clash 程序本身发出的流量, 防止死循环(clash 程序需要使用 "clash" 用户启动) 
    iptables -t mangle -A OUTPUT -p tcp -m owner --uid-owner clash -j RETURN
    iptables -t mangle -A OUTPUT -p udp -m owner --uid-owner clash -j RETURN
    
    # 让本机发出的流量跳转到 clash_local
    # clash_local 链会为本机流量打 mark, 打过 mark 的流量会重新回到 PREROUTING 上
    iptables -t mangle -A OUTPUT -j clash_local
    
    # 修复 ICMP(ping)
    # 这并不能保证 ping 结果有效(clash 等不支持转发 ICMP), 只是让它有返回结果而已
    # --to-destination 设置为一个可达的地址即可
    sysctl -w net.ipv4.conf.all.route_localnet=1
    iptables -t nat -A PREROUTING -p icmp -d 198.18.0.0/16 -j DNAT --to-destination 127.0.0.1
    

这里需要根据自己的实际情况进行调整。例如我是直接让clash监听了53端口,所以不需要那个将53转发到1053的规则。

  1. /etc/clash/clean.sh 清理iptables文件

    #!/usr/bin/env bash
    
    set -ex
    
    ip rule del fwmark 666 table 666 || true
    ip route del local 0.0.0.0/0 dev lo table 666 || true
    
    iptables -t nat -F
    iptables -t nat -X
    iptables -t mangle -F
    iptables -t mangle -X clash || true
    iptables -t mangle -X clash_local || true
    
  2. /etc/clash/config.yaml clash配置文件

这个就需要你本来就有,或者本来就知道怎么配置了。可以直接从官网抄一下:https://github.com/Dreamacro/clash/wiki/configuration#all-configuration-options

但是注意几点:

  • tproxy-port: 7893 需要设置成和 /etc/clash/iptables.sh 中的一致
  • allow-lan: true 要设置为 true
  • dns 要打开

    # DNS server settings
    # This section is optional. When not present, the DNS server will be disabled.
    dns:
    enable: true
    listen: 0.0.0.0:53
    # ipv6: false # when the false, response to AAAA questions will be empty
    
    # These nameservers are used to resolve the DNS nameserver hostnames below.
    # Specify IP addresses only
    nameserver:
    - 'tls://dns.rubyfish.cn:853'
    - 'tls://1.1.1.1:853'
    - 'tcp://1.1.1.1'
    - 'tcp://208.67.222.222:443'
    - 'tls://dns.google'
    enhanced-mode: redir-host
    fake-ip-range: 198.18.0.1/16 # Fake IP addresses pool CIDR
    

还有一个 systemd service 文件 /lib/systemd/system/clash.service

[Unit]
Description=Clash TProxy
After=network.target

[Service]
Type=simple
User=clash
Group=clash
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW
Restart=on-failure

ExecStartPre=+/usr/bin/bash /etc/clash/clean.sh
ExecStart=/usr/local/bin/clash -d /etc/clash
ExecStartPost=+/usr/bin/bash /etc/clash/iptables.sh

ExecStopPost=+/usr/bin/bash /etc/clash/clean.sh

[Install]
WantedBy=multi-user.target

配置好以后,启动 clash:

$ sudo systemctl enable --now clash

到这里,你的路由器本身就可以提供DNS服务和代理了。

将虚拟机设置为默认网关和默认DNS服务器

在路由器中,将默认网关和DNS服务器,分别改为虚拟机的IP地址,另外,将虚拟机设置为分配一个固定IP(省得后面DHCP IP变化了 还要改配置)。

至此,重连设备,大功告成。

总结

这一篇文章记录了如何配置一个旁路由,比较适合的情况是物理网口不够用,无法直接搭建OpenWRT,而又需要访问外网,配置好以后, 效果其实和OpenWRT软路由一样。只是还需要在路由器里设置一下默认网关,如果路由器不支持更改,就需要在设备上自定义网关,相对 来说会麻烦一些。


ref: