Daniel's Blog
× 私有图床 私有云 离线下载 茶茶子の小站

这篇文章主要是记录如何在将树莓派作为旁路由,配合 V2Ray,搭建透明代理,以实现局域网内设备的无感翻墙。

1. 刷写系统

我使用的是 Ubuntu Server 20.04,当然,其他系统也可以。刷写工具为 Win32DiskImager。

2. 更改 APT 软件源

# apt edit-sources

这里选择你喜欢的编辑器即可,我选择的是 Vim。

如果你也一样,可以像我接下来这样替换软件源,此处我选择清华源。

:%s/ports.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g

修改后保存并退出即可。之后运行:

# apt update && apt upgrade

更新并升级。

3. 配置内核、网络(静态地址)

新版 Ubuntu 默认使用 Netplan + Systemd-networkd 管理网络,而 Netplan 文件使用了可读性高且人性化的 YAML 格式文件。

# vim /etc/netplan/50-cloud-init.yaml
network:
    ethernets:
        eth0:
            dhcp4: false
            dhcp6: false
            link-local: [] # 停止自动获取 IP 地址
            accept-ra: false # 同时不接受 IPv6 地址的广播
            # optional: true # 值为“真”时,开机时不等待获取到网络。这里作为路由器,我就注释掉了
            addresses:
                - 192.168.0.5/24 # IP 地址,注意有子网长度,相当于 IP 地址 + 子网掩码
            gateway4: 192.168.0.1 # 网关地址
            nameservers:
                addresses:
                    - 192.168.0.1 # DNS 服务器地址
    version: 2

保存退出后运行:

# netplan apply

这里由于配置了修改了 IP,如果使用 SSH 连接的话,将会断线,重连即可。

使用:

$ ip addr show

可以查看本机 IP 地址。

编辑 /etc/sysctl.conf 配置包转发:

…
# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1
…
# sysctl -p

运行以上指令后,转发即可生效。

4. 安装 V2Ray

使用官方脚本即可(实话说这域名不错)

$ wget https://install.direct/go.sh
# bash go.sh

然而由于安装时脚本需要从 GitHub 上下载最新的程序文件,所以速度很慢。所以需要通过本机代理下载或者在其他设备上下载后进行本地安装。

运行

# bash go.sh -h

后可以看到以下输出:

./install-release.sh [-h] [-c] [--remove] [-p proxy] [-f] [--version vx.y.z] [-l file]
  -h, --help            Show help
  -p, --proxy           To download through a proxy server, use -p socks5://127.0.0.1:1080 or -p http://127.0.0.1:3128 etc
  -f, --force           Force install
      --version         Install a particular version, use --version v3.15
  -l, --local           Install from a local file
      --remove          Remove installed V2Ray
  -c, --check           Check for update

这里我通过一台境外 VPS 下载安装包,之后通过 scp 指令传输到本地进行安装。具体步骤请自行查询。注意手动从 GitHub 上进行下载时要选对架构,实在分不清可以先运行一下脚本,这是会输出下载链接,然后结束运行,复制链接,下载。

安装过程中脚本会自动修复依赖和创建 Systemd 单元。

5. 配置 V2Ray

接下来我们就要进入重头戏:配置 V2Ray 透明代理。我的思路是由 V2Ray 的 Dokodemo door(任意门)协议接收除 53 端口的 UDP 和特殊地址以外的流量,之后通过内置的路由功能进行分流,分流方式为代理被墙域名和 IP 列表,其他全部直连。至于 53 端口的 UDP 流量,也就是 DNS 查询,通过一个 DNS 分流器进行分流,以防污染。

好,思路解释完毕,下面开始实践。首先我们编辑 V2Ray 配置文件:/etc/v2ray/config.json

{
  "log": {
    "error": "/var/log/v2ray/error.log", // 错误日志目录
    "access": "/var/log/v2ray/access.log", // 访问日志目录
    "loglevel": "error" // 错误日志级别
  },
  "inbounds": [
    {
      "protocol": "dokodemo-door", // 透明代理流量入口
      "port": 12345, // 端口,可自定义
      "settings": {
        "network": "tcp,udp",
        "followRedirect": true
      },
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ]
      },
      "streamSettings": {
        "sockopt": {
          "tproxy": "tproxy" // 使用 TPROXY 方式实现透明代理,相应的还有 REDIRECT 方式
        }
      }
    },
    {
      "port": 1080,
      "protocol": "socks", // SOCKS 代理,可选,方便测试
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ]
      },
      "settings": {
        "auth": "noauth",
        "udp": true,
        "ip": "127.0.0.1"
      }
    },
    {
      "port": 8081,
      "protocol": "http", // HTTP 代理,可选,想用、会用可以保留
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ]
      }
    }
  ],
  "outbounds": [
    {
      "tag": "direct", // 出口流量直连标签
      "protocol": "freedom",
      "streamSettings": {
        "sockopt": {
          "mark": 2 // 一个可爱的小标记,数字自定义(可能有范围,使用“2”即可),后面能用到
        }
      }
    },
    {
      "tag": "proxy", // 出口流量代理标签
      "protocol": "vmess", // V2Ray 服务端信息配置
      "settings": {
        "vnext": [
          {
            "address": "服务器地址或域名",
            "port": 端口,
            "users": [
              {
                "id": "UUID",
                "alterId": 4,
                "security": "auto"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "ws", // WebSocket 传输方式配置,请根据实际情况进行修改
        "wsSettings": {
          "path": "路径"
        },
        "security": "tls",
        "sockopt": {
          "mark": 2 // 和上面一样可爱的小标记,两者需相同,后面能用到
        }
      }
    },
    {
      "tag": "block", // 出口流量丢弃标签
      "protocol": "blackhole",
      "settings": {
        "response": {
          "type": "http"
        }
      }
    }
  ],
  "routing": {
    "domainStrategy": "IPIfNonMatch", // 此方式匹配最为全面
    "rules": [
      {
        "type": "field",
        "outboundTag": "proxy",
        "ip": [
          // 需要远程解析的 DNS 服务器地址,单独列出,方便维护,与后面 DNS 分流器中的地址相同
        ]
      },
      {
        "type": "field",
        "outboundTag": "block",
        "domain": [
          // 一些想要禁止访问的域名,如广告
        ]
      },
      {
        "type": "field",
        "outboundTag": "block",
        "ip": [
          // 一些想要禁止的 IP,目的同上
        ]
      },
      {
        "type": "field",
        "outboundTag": "proxy",
        "domain": [
          // 一些想要代理的域名,如被墙的域名
        ]
      },
      {
        "type": "field",
        "outboundTag": "proxy",
        "ip": [
          // 一些想要代理的 IP,目的同上(Telegram 就需要指定 IP 走代理)
        ]
      }
    ]
  }
}

配置文件虽然很长,但是配合注释来看比较好理解,请根据实际情况进行修改。需要注意的是,如果在 VSCode、Vim 等编辑器中修改本文件,可能会对有注释的地方报错,这是因为 JSON 格式的文件理论上不支持注释,然而 V2Ray 程序却支持,所以不删除注释也不会影响正常使用。

另外,上面的配置最后有几个包含“一些想要”注释开头的数组(即中括号“[]”内),其中的内容需要按照实际情况进行修改,这里我分享一下自用的规则:config_routing.json,下载后补充到上面配置文件中即可。这里需要注意的是,我分享的规则中的 Block 部分由于过于强力,可能会导致一些网站无法正常使用(已发现并修改:B 站登录界面、优酷播放界面),所以介意的话可以删除这一部分。如果想要使用,还要解决这个问题,请在网页功能无法正常使用时打开浏览器的开发人员工具,里面应该会提示某一域名(IP)无法访问的错误,之后在配置中查找此域名(IP)并将其删除即可。

如果以上步骤都做好了,那么就可以保存退出了。

现在运行

# /usr/bin/v2ray/v2ray -config /etc/v2ray/config.json -test

如果无报错,出现 Configuration OK. 则说明配置文件表面上没有错误。

最后,需要修改一下 /etc/systemd/system/v2ray.service 文件,以免运行时出现错误:

…
[Service]
…
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_NET_ADMIN
# 4.23.1 需要在 “CapabilityBoundingSet” 的最后添加 “CAP_NET_ADMIN”,否则透明代理无法正常使用
…
LimitNPROC=500
LimitNOFILE=1000000
# 修改后解决日志中出现非常多“too many open files”的问题
# systemctl daemon-reload

这里有一个可选的步骤,如果细心查看配置的话,可能会在路由规则中发现与 geosite:category-ads-all 类似的奇怪字样,这些其实是 V2Ray 中自带的域名(IP)规则,但是此规则文件只能随着 V2Ray 版本更新而更新,所以如果有新的域名出现,不会及时进行补充(虽然内置规则加上配置中的其他规则足够了)。不过有人利用 GitHub Action 每天自动生成此规则文件,其中除了官方自带的地址,又增加了一些地址,以便更好的满足使用者的需求。

使用方法很简单:用 geoip.datgeosite.dat 两个文件替换 /usr/bin/v2ray 目录下的同名文件即可。

最后重启 V2Ray。

# systemctl restart v2ray

之后可以使用 cURL 测试配置是否正确(所以建议添加 SOCKS 代理以便测试)。

$ curl -x socks5h://127.0.0.1:1080 google.com
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.com/">here</A>.
</BODY></HTML>

如出现问题,请检查配置和日志文件(可能需要调整错误日志级别以获取更多信息)。

6. 配置 DNS 服务器(Telescope DNS 分流器)

Telescope DNS 是一位大佬用 Go 语言开发的 DNS 分流器,在这里使用非常合适,大家觉得好用可以去给项目一个 Star。

安装与配置 Systemd 单元的教程在项目主页上面都有,这里不作过多讲解。

如果已经安装好了,先不要着急启动。

首先,我们修改 Telescope DNS 的配置文件:/etc/ts-dns/ts-dns.toml

# Telescope DNS Configure File
# https://github.com/wolf-joe/ts-dns

listen = ":53"  # 监听端口
gfwlist = "gfwlist.txt"  # gfwlist文件路径,release包中已预下载。官方地址:https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt
gfwlist_b64 = true  # 是否使用base64解码gfwlist文件,默认为true
cnip = "cnip.txt"  # 中国ip网段列表,用于辅助域名分组
disable_ipv6 = true  # 禁用IPv6地址解析,默认为false

hosts_files = ["/etc/hosts"]  # hosts文件路径,支持多hosts
[hosts] # 自定义域名映射
"cloudflare-dns.com" = "1.0.0.1"  # 防止下文提到的DoH回环解析,此处地址与 V2Ray 路由规则中的地址相同
"dns.google" = "8.8.8.8"
"dns.adguard.com" = "176.103.130.130"
"dns.quad9.net" = "9.9.9.9"

[query_log]
file = ""  # dns请求日志文件,值为/dev/null时不记录,值为空时记录到stdout
ignore_qtypes = ["DNSKEY", "NS"]  # 不记录指定类型的dns请求,默认为空
ignore_cache = true  # 不记录命中缓存的dns请求,默认为false
ignore_hosts = true  # 不记录命中hosts的dns请求,默认为false

[cache]  # dns缓存配置
size = 4096  # 缓存大小,为负数时禁用缓存
min_ttl = 60  # 最小ttl,单位为秒
max_ttl = 86400  # 最大ttl,单位为秒

[groups] # 对域名进行分组
  [groups.clean]  # 必选分组,默认域名所在分组
  dns = ["223.5.5.5", "114.114.114.114"]  # DNS服务器列表,默认使用53端口
  concurrent = true  # 并发请求dns服务器列表

  [groups.dirty]  # 必选分组,匹配GFWList的域名会归类到该组
  # 警告:如果本机的dns指向ts-dns自身,且DoH地址中的域名被归类到该组,则会出现回环解析的情况,此时需要在上面的hosts中指定对应IP
  doh = ["https://dns.quad9.net/dns-query", "https://dns.adguard.com/dns-query", "https://cloudflare-dns.com/dns-query", "https://dns.google/dns-query"]  # dns over https服务器,由于分流到此处的域名大多被墙,需要通过代理访问,所以选择 DNS 远程解析以获取最佳速度
  concurrent = true

需要注意的是,如果系统使用了 Systemd-resolved 或其他监听 53 端口的 DNS 解析服务,需要将其停止,否则 Telescope DNS 无法启动。

# systemctl stop systemd-resolved
# systemctl disable systemd-resolved

之后就可以开启 Telescope DNS 并设置自启。

# systemctl start ts-dns
# systemctl enable ts-dns

再之后需要修改 /etc/netplan/50-cloud-init.yaml/etc/resolv.conf。建议删除原有的 resolv.conf 文件并重新创建。

# vim /etc/netplan/50-cloud-init.yaml
network:
    ethernets:
        eth0:
            dhcp4: false
            dhcp6: false
            link-local: [] # 停止自动获取 IP 地址
            accept-ra: false # 同时不接受 IPv6 地址的广播
            # optional: true # 值为“真”时,开机时不等待获取到网络。这里作为路由器,我就注释掉了
            addresses:
                - 192.168.0.5/24 # IP 地址,注意有子网长度,相当于 IP 地址 + 子网掩码
            gateway4: 192.168.0.1 # 网关地址
            # nameservers:
                # addresses:
                    # - 192.168.0.1 # DNS 服务器地址
    version: 2
# netplan apply
# rm /etc/resolv.conf
# vim /etc/resolv.conf
nameserver 127.0.0.1
options edns0

配置完成后,可以使用 dignslookup 指令检测 DNS 解析是否正常。如出现问题,可以查看日志获取更多信息。

另外,如果执行命令出现 sudo: unable to resolve host xxx: Temporary failure in name resolution,可以在 /etc/hosts 中将主机名,也就是这里的 xxx 添加到 127.0.0.1 之后。

7. 配置 iptables

iptables 的配置是最关键的一步,只有这里配置完成后,透明代理才能正常使用,少或多一条规则都可能引起很多问题。以下所有指令都需要管理员权限运行。

配置策略路由:

ip rule add fwmark 1 table 100 # 一个不可爱的小标记“1”,理论自定义,其他未测试
ip route add local default dev lo table 100

配置防火墙:

iptables -t mangle -N V2RAY
iptables -t mangle -A V2RAY -d 0.0.0.0/8 -j RETURN
iptables -t mangle -A V2RAY -d 10.0.0.0/8 -j RETURN
iptables -t mangle -A V2RAY -d 100.64.0.0/10 -j RETURN
iptables -t mangle -A V2RAY -d 127.0.0.0/8 -j RETURN
iptables -t mangle -A V2RAY -d 169.254.0.0/16 -j RETURN
iptables -t mangle -A V2RAY -d 172.16.0.0/12 -j RETURN
iptables -t mangle -A V2RAY -d 192.0.0.0/24 -j RETURN
iptables -t mangle -A V2RAY -d 192.0.2.0/24 -j RETURN
iptables -t mangle -A V2RAY -d 192.88.99.0/24 -j RETURN
iptables -t mangle -A V2RAY -d 192.168.0.0/16 -j RETURN
iptables -t mangle -A V2RAY -d 198.18.0.0/15 -j RETURN
iptables -t mangle -A V2RAY -d 198.51.100.0/24 -j RETURN
iptables -t mangle -A V2RAY -d 203.0.113.0/24 -j RETURN
iptables -t mangle -A V2RAY -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A V2RAY -d 240.0.0.0/4 -j RETURN
iptables -t mangle -A V2RAY -d 255.255.255.255/32 -j RETURN # 以上均为特殊地址,直连
iptables -t mangle -A V2RAY -p udp --dport 53 -j RETURN # 国内域名查询,直连
iptables -t mangle -A V2RAY -p tcp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A V2RAY -p udp -j TPROXY --on-port 12345 --tproxy-mark 1 
# 代理需要加一个不可爱的标记
iptables -t mangle -A PREROUTING -j V2RAY

iptables -t mangle -N V2RAY_MARK # 本机代理
iptables -t mangle -A V2RAY_MARK -d 0.0.0.0/8 -j RETURN
iptables -t mangle -A V2RAY_MARK -d 10.0.0.0/8 -j RETURN
iptables -t mangle -A V2RAY_MARK -d 100.64.0.0/10 -j RETURN
iptables -t mangle -A V2RAY_MARK -d 169.254.0.0/16 -j RETURN
iptables -t mangle -A V2RAY_MARK -d 172.16.0.0/12 -j RETURN
iptables -t mangle -A V2RAY_MARK -d 192.0.0.0/24 -j RETURN
iptables -t mangle -A V2RAY_MARK -d 192.0.2.0/24 -j RETURN
iptables -t mangle -A V2RAY_MARK -d 192.88.99.0/24 -j RETURN
iptables -t mangle -A V2RAY_MARK -d 192.168.0.0/16 -j RETURN
iptables -t mangle -A V2RAY_MARK -d 198.18.0.0/15 -j RETURN
iptables -t mangle -A V2RAY_MARK -d 198.51.100.0/24 -j RETURN
iptables -t mangle -A V2RAY_MARK -d 203.0.113.0/24 -j RETURN
iptables -t mangle -A V2RAY_MARK -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A V2RAY_MARK -d 240.0.0.0/4 -j RETURN
iptables -t mangle -A V2RAY_MARK -d 255.255.255.255/32 -j RETURN # 除本机外,其他直连
iptables -t mangle -A V2RAY_MARK -p udp --dport 53 -j RETURN
iptables -t mangle -A V2RAY_MARK -j RETURN -m mark --mark 2 # 打一个可爱的标记
iptables -t mangle -A V2RAY_MARK -p tcp -j MARK --set-mark 1 # 同样需要不可爱的标记
iptables -t mangle -A V2RAY_MARK -p udp -j MARK --set-mark 1
iptables -t mangle -A OUTPUT -j V2RAY_MARK
$ lsmod | grep TPROXY
…
xt_TPROXY              20480  2
…

如未出现此模块,说明系统未自动加载,需要手动设置。

# modprobe xt_TPROXY

之后编辑 /etc/modules 设置开机自动加载。

…
xt_TPROXY

保存并退出即可。

执行上述命令之后,理论上应该成功了,同样可以使用 cURL 进行测试。

$ curl google.com

出现和上文中一样的结果,说明没有问题了。现在只需将局域网内其他设备的网关和 DNS 服务器换成透明代理设备的 IP 即可。如果没有配置成功,那么就再一次阅读上文,检查配置,以及配合搜索引擎解决问题,实在不行可以请求大佬提供帮助。

不过呢,由于最后输入的一大串指令只是临时生效,重启后就需要重新配置,所有我们需要将其保存下来,并编写 Systemd 单元以方便使用。

# mkdir /etc/iptables
# iptables-save -f /etc/iptables/v2tproxy.rules
# vim /etc/systemd/system/v2tproxy.service
[Unit]
Description=Transparent proxy configurations for V2Ray
After=network.target

[Service]
Type=oneshot
ExecStart=/sbin/ip rule add fwmark 1 table 100 ; /sbin/ip route add local default dev lo table 100 ; /sbin/iptables-restore /etc/iptables/v2tproxy.rules

[Install]
WantedBy=multi-user.target
# systemctl enable v2tproxy

至此,一切都大功告成了。

参考

  1. TProxy實現透明代理 - 小學霸
  2. Netplan | Backend-agnostic network configuration in YAML
  3. 在 Vim 中优雅地查找和替换 | Harttle Land
  4. 在透明代理环境中开放 UDP 53 端口作为 DNS 服务器出现问题 · Issue #1971 · v2ray/v2ray-core
  5. 启用iptables后无法解析域名和ping - tlanyan
  6. Linux使用TPROXY进行UDP的透明代理 - 简书
  7. Dokodemo UDP转发导致断流 · Issue #1432 · v2ray/v2ray-core
  8. Iptables+Tproxy+RedSocks(TCP/UDP)透明代理原理浅析_网络_T3rry'S Blog-CSDN博客
  9. Iptables 指南 1.1.19
  10. smgate/tcp-config.json at master · MassSmith/smgate
  11. 透明代理(TPROXY) | 新 V2Ray 白话文指南
  12. 使用Ubuntu 18.04打造超级家庭网关(边缘路由器)
  13. V2Ray透明代理/透明网关/广告屏蔽/路由器翻墙-荒岛
  14. Kernel module - ArchWiki

标签: 翻墙, 树莓派, 透明代理, TPROXY, Raspberry Pi, V2Ray, Ubuntu, 路由器

已有 3 条评论

  1. tankren tankren

    不错的内容 很详细 用Linux做透明代理的唯一弊端就是万一节点挂了 还要手动改config

    1. 是的,不过如果是自己搭建的梯子一般也不会失效,而且就我个人而言,手动改 config.json 也不是什么复杂的事情。

  2. 茶戍菌 茶戍菌

    虽然看不懂,但觉得很厉害!

添加新评论