因为有些软件不支持主动设置代理,所以有时候还得开个透明代理,在实际买设备前先用虚拟机安装 OpenWrt 实验一把。
一开始想着去找那些有一键设置的工具或脚本,结果来回折腾花了不少时间,最后还是参考这里的教程搞定了。

准备镜像

  1. 下载目前最新的 OpenWrt 镜像
  2. 解压得到 *.img,记为 op.img
  3. (可选)用这个镜像安装后的默认可用空间只有 100M,比较捉鸡。为了方便后续安装各种软件先做个扩容:到 Linux 系统下或用 wsl,运行 dd if=/dev/zero bs=1M count=2048 >> op.img,将镜像扩容到 2G
  4. (可选)执行 parted op.img,再输入 print,可以看到镜像中有两个分区,第二个范围是 17.3M~126M,共 109M 大小。
  5. (可选)执行 resizepart 2 100% 让分区 2 占满剩余的全部空间,再 print 一次可以看到分区 2 的大小已经更新,执行 quit 退出。

转换格式为 vhd

为了给 hyper-v 用还需要转换镜像格式,下一个 StarWind V2V Converter 将扩容后的镜像转为 VHD 格式,要选 VHD pre-allocated image,这样转出来的 vhd 也是 2.1G 大小。

创建 hyper-v 虚拟交换机

  1. 安装完 hyper-v 后系统会自动创建 Default Switch,这里要额外创建两个交换机,分别用于外网和内网的连接,对应网关上的 wan 和 lan。
  2. 外网的 External 选中物理网卡,并去掉 允许管理操作系统共享此网络适配器 勾选
  3. 内网的 Internal 直接选 内部网络 就行

创建 hyper-v 虚拟机

  1. 选第一代
  2. 1G 内存,不用动态
  3. 选中 External 交换机
  4. 使用刚才创建好的 vhd 虚拟硬盘,下一步
  5. 确认下配置,完成
  6. 创建完后先不要运行,打开虚拟机的设置,添加 Internal 交换机
  7. 现在可以启动虚拟机,并用 hyper-v 连接了
  8. 看到这个后可以按回车激活控制台
  9. 首先用 passwd 创建 root 密码
  10. 然后输入 vi /etc/config/network 修改网络接口配置
  11. 刚才创建虚拟机时先选择了 External,创建后再添加的 Internal 交换机,所以这里的 eth0 对应外网 wan,eth1 对应内网 lan,有对应顺序。lan 的网段不要和现有网段重复,选个没用过的
  12. 保存退出后用 reboot 重启虚拟机,之后就可以在浏览器里用 192.168.5.1 访问 openwrt 后台了(对应上面修改的网关地址)

OpenWrt LuCI

这里的操作用 opkg updateopkg install *** 在 ssh 控制台操作也是一样的。

  1. 到 Software 菜单,点绿色的 Update lists,看到下面的弹窗说明操作成功了。如果有错误发生窗口里会有一栏显示相关的错误信息
  2. 分别在输入框输入 iptables-nftiptables-mod-tproxyiptables-mod-socket 并安装
  3. 搜索 v2ray 并安装前三个

OpenWrt ssh

  1. 再用 ssh 登录 OpenWrt,将以下配置内容写入到 /etc/v2ray/config.json 里,outbounds/proxy 节里要替换上自己的服务器信息。广告拦截部分有个别网站也会被拦截,所以注掉了。路由规则的最后再加上 proxy 的规则,表示所有剩余流量都发到代理上。
    {
      "inbounds": [
        {
          "tag":"transparent",
          "port": 12345,
          "protocol": "dokodemo-door",
          "settings": {
            "network": "tcp,udp",
            "followRedirect": true
          },
          "sniffing": {
            "enabled": true,
            "destOverride": [
              "http",
              "tls"
            ]
          },
          "streamSettings": {
            "sockopt": {
              "tproxy": "tproxy", // 透明代理使用 TPROXY 方式
              "mark":255
            }
          }
        },
        {
          "port": 1080, 
          "protocol": "socks", // 入口协议为 SOCKS 5
          "sniffing": {
            "enabled": true,
            "destOverride": ["http", "tls"]
          },
          "settings": {
            "auth": "noauth"
          }
        }
      ],
      "outbounds": [
        {
          "tag": "proxy",
          "protocol": "vmess",
          "settings": {
            "vnext": [
              // 把你的服务器信息贴到这里
            ]
          },
          "streamSettings": {
    
            // 如果有 http 伪装之类的也抄过来
    
            "sockopt": {
              "mark": 255  // 这些要保留
            }
          },
          "mux": {
            "enabled": true
          }
        },
        {
          "tag": "direct",
          "protocol": "freedom",
          "settings": {
            "domainStrategy": "UseIP"
          },
          "streamSettings": {
            "sockopt": {
              "mark": 255
            }
          }      
        },
        {
          "tag": "block",
          "protocol": "blackhole",
          "settings": {
            "response": {
              "type": "http"
            }
          }
        },
        {
          "tag": "dns-out",
          "protocol": "dns",
          "streamSettings": {
            "sockopt": {
              "mark": 255
            }
          }  
        }
      ],
      "dns": {
        "servers": [
          {
            "address": "223.5.5.5", //中国大陆域名使用阿里的 DNS
            "port": 53,
            "domains": [
              "geosite:cn",
              "ntp.org",   // NTP 服务器
              "$myserver.address" // 此处改为你 VPS 的域名
            ]
          },
          {
            "address": "114.114.114.114", //中国大陆域名使用 114 的 DNS (备用)
            "port": 53,
            "domains": [
              "geosite:cn",
              "ntp.org",   // NTP 服务器
              "$myserver.address" // 此处改为你 VPS 的域名
            ]
          },
          {
            "address": "8.8.8.8", //非中国大陆域名使用 Google 的 DNS
            "port": 53,
            "domains": [
              "geosite:geolocation-!cn"
            ]
          },
          {
            "address": "1.1.1.1", //非中国大陆域名使用 Cloudflare 的 DNS
            "port": 53,
            "domains": [
              "geosite:geolocation-!cn"
            ]
          }
        ]
      },
      "routing": {
        "domainStrategy": "IPOnDemand",
        "rules": [
          { // 劫持 53 端口 UDP 流量,使用 V2Ray 的 DNS
            "type": "field",
            "inboundTag": [
              "transparent"
            ],
            "port": 53,
            "network": "udp",
            "outboundTag": "dns-out"
          },
          { // 直连 123 端口 UDP 流量(NTP 协议)
            "type": "field",
            "inboundTag": [
              "transparent"
            ],
            "port": 123,
            "network": "udp",
            "outboundTag": "direct"
          },
          { // 直连中国大陆主流网站 ip 和 保留 ip
            "type": "field", 
            "ip": [
              "geoip:private",
              "geoip:cn"
            ],
            "outboundTag": "direct"
          },
          { // 直连中国大陆主流网站域名
            "type": "field", 
            "domain": [
              "geosite:cn"
            ],
            "outboundTag": "direct"
          },
          {
            "type": "field",
            "ip": [
              // 设置 DNS 配置中的国内 DNS 服务器地址直连,以达到 DNS 分流目的
              "223.5.5.5",
              "114.114.114.114"
            ],
            "outboundTag": "direct"
          },
          {
            "type": "field",
            "ip": [
              // 设置 DNS 配置中的国外 DNS 服务器地址走代理,以达到 DNS 分流目的
              "8.8.8.8",
              "1.1.1.1"
            ],
            "outboundTag": "proxy" // 改为你自己代理的出站 tag
          },
          //{ // 广告拦截
          //  "type": "field",
          //  "domain": [
          //   "geosite:category-ads-all"
          //  ],
          //  "outboundTag": "block"
          //},
          { // BT 流量直连
            "type": "field",
            "protocol":["bittorrent"],
            "outboundTag": "direct"
          },
          {
            "type": "field",
            "outboundTag": "proxy",
            "network": "udp,tcp"
          }
        ]
      }
    }
  2. geoip.dat 和 geosite.dat 可以到这里这里下载,下载后可以放 /usr/bin 目录,自动更新可以自行处理下
  3. 执行 v2ray test -c /etc/v2ray/config.json 确保配置文件正确
  4. 执行 v2ray run -c /etc/v2ray/config.json 启动 v2ray
  5. 另起一个 ssh 执行 curl -so /dev/null -w "%{http_code}" google.com -x socks5://127.0.0.1:1080 (按上面的配置就是用 1080 端口)应该可以看到输出 301;或者把浏览器的代理地址改成 192.168.5.1:1080 就可以科学上网(网关地址改成自己设置的)

透明代理

  1. 接下最后一步设置成透明代理
    # 设置策略路由
    ip rule add fwmark 1 table 100 
    ip route add local 0.0.0.0/0 dev lo table 100
    
    # 代理局域网设备
    iptables -t mangle -N V2RAY
    iptables -t mangle -A V2RAY -d 127.0.0.1/32 -j RETURN
    iptables -t mangle -A V2RAY -d 224.0.0.0/4 -j RETURN 
    iptables -t mangle -A V2RAY -d 255.255.255.255/32 -j RETURN 
    iptables -t mangle -A V2RAY -d 192.168.0.0/16 -p tcp -j RETURN # 直连局域网,避免 V2Ray 无法启动时无法连网关的 SSH,如果你配置的是其他网段(如 10.x.x.x 等),则修改成自己的
    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 -j RETURN -m mark --mark 0xff    # 直连 SO_MARK 为 0xff 的流量(0xff 是 16 进制数,数值上等同与上面V2Ray 配置的 255),此规则目的是解决v2ray占用大量CPU(https://github.com/v2ray/v2ray-core/issues/2621)
    iptables -t mangle -A V2RAY -p udp -j TPROXY --on-ip 127.0.0.1 --on-port 12345 --tproxy-mark 1 # 给 UDP 打标记 1,转发至 12345 端口
    iptables -t mangle -A V2RAY -p tcp -j TPROXY --on-ip 127.0.0.1 --on-port 12345 --tproxy-mark 1 # 给 TCP 打标记 1,转发至 12345 端口
    iptables -t mangle -A PREROUTING -j V2RAY # 应用规则
    
    # 代理网关本机
    iptables -t mangle -N V2RAY_MASK 
    iptables -t mangle -A V2RAY_MASK -d 224.0.0.0/4 -j RETURN 
    iptables -t mangle -A V2RAY_MASK -d 255.255.255.255/32 -j RETURN 
    iptables -t mangle -A V2RAY_MASK -d 192.168.0.0/16 -p tcp -j RETURN # 直连局域网
    iptables -t mangle -A V2RAY_MASK -d 192.168.0.0/16 -p udp ! --dport 53 -j RETURN # 直连局域网,53 端口除外(因为要使用 V2Ray 的 DNS)
    iptables -t mangle -A V2RAY_MASK -j RETURN -m mark --mark 0xff    # 直连 SO_MARK 为 0xff 的流量(0xff 是 16 进制数,数值上等同与上面V2Ray 配置的 255),此规则目的是避免代理本机(网关)流量出现回环问题
    iptables -t mangle -A V2RAY_MASK -p udp -j MARK --set-mark 1   # 给 UDP 打标记,重路由
    iptables -t mangle -A V2RAY_MASK -p tcp -j MARK --set-mark 1   # 给 TCP 打标记,重路由
    iptables -t mangle -A OUTPUT -j V2RAY_MASK # 应用规则
    
    # 新建 DIVERT 规则,避免已有连接的包二次通过 TPROXY,理论上有一定的性能提升
    iptables -t mangle -N DIVERT
    iptables -t mangle -A DIVERT -j MARK --set-mark 1
    iptables -t mangle -A DIVERT -j ACCEPT
    iptables -t mangle -I PREROUTING -p tcp -m socket -j DIVERT
    
  2. 逐个执行完上面的这些命令后透明代理应该已经生效,关掉其他代理软件也可以直接上网了

开机自动运行透明代理

  1. 首先保存现有的 iptables 规则到文件
    mkdir -p /etc/iptables && iptables-save > /etc/iptables/rules.v4
  2. vi /root/run-proxy 新建一个脚本(前三条是清除透明代理规则,后三条是重建)
    /sbin/ip rule del fwmark 1 table 100
    /sbin/ip route del local 0.0.0.0/0 dev lo table 100
    /usr/sbin/iptables -t mangle -F
    /sbin/ip rule add fwmark 1 table 100
    /sbin/ip route add local 0.0.0.0/0 dev lo table 100
    /usr/sbin/iptables-restore /etc/iptables/rules.v4
    
  3. 到 LuCI 的 System - Startup - Local Startup 页面,在 exit 0 之前插入一行 /bin/sh /root/run-proxy,这样开机后就会自动配置代理规则
  4. 打开 /etc/config/v2ray,把 option enabled '0' 的 0 改成 1,使 v2ray 开机自启,配合上一条就完成启动配置了(不过这几天试用下来在 PC 睡眠恢复后常有部分网站代理不了的情况出现,比如 google 打不开但 youtube 能打开,或者反过来,再继续找找原因看)