Ubuntu 软路由(篇二):v2ray 与透明(全局)代理
发表于 2020-06-07 分类于
Linux ,
Router Valine:
0 本文字数: 6.8k 阅读时长 ≈ 6 分钟
如何在路由器上配置全局透明代理,以免被防火墙误伤。
接上一篇:Ubuntu 软路由(篇一):配置基于 ubuntu 的软路由
最早的时候,我使用了 shadowsocks 为基础的端口转发方案,但是配置复杂且不稳定。
这里使用的是 V2Ray + iptables 的转发方案。实际上由于 V2ray 支持路由,做网络的分流会方便很多,也更容易管理。
安装、配置 V2Ray
下载解压稳定的 v2ray 文件到安装目录,我这里用的是 /home/ubuntu/app/install/v2ray
。为了获取稳定的新版本,我使用的是从 github 仓库下载的最后一版,仓库地址
| cd /home/ubuntu/app/install wget https://github.com/v2fly/v2ray-core/releases/download/v4.33.0/v2ray-linux-64.zip unzip -d v2ray v2ray-linux-64.zip
|
解压之后目录内容如下:
/home/ubuntu/app/install/v2ray
:
| ├── config.json ├── geoip.dat ├── geosite.dat ├── systemd │ └── system │ ├── v2ray.service │ └── [email protected] ├── v2ctl ├── v2ray ├── vpoint_socks_vmess.json └── vpoint_vmess_freedom.json
|
接下来准备 systemd 的服务注册文件(用于将 v2ray 注册称一个服务以便自启动),
修改文件 /home/ubuntu/app/install/v2ray/systemd/system/v2ray.service
, 原内容如下:
| [Unit] Description=V2Ray Service Documentation=https://www.v2fly.org/ After=network.target nss-lookup.target
[Service] User=nobody CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE NoNewPrivileges=true ExecStart=/usr/local/bin/v2ray -config /usr/local/etc/v2ray/config.json Restart=on-failure RestartPreventExitStatus=23
[Install] WantedBy=multi-user.target
|
有两处需要修改:
| # ExecStart... 启动命令,修改启动文件位置、配置文件位置: ExecStart=/home/ubuntu/app/install/v2ray/v2ray -config /home/ubuntu/app/install/v2ray/config.json
|
接下来将 v2ray 注册到 systemd,
(这里每次修改 service 文件之后都需要重新执行这个操作)
| # 将service文件复制到系统的service文件存放位置 cp /home/ubuntu/app/install/v2ray/systemd/system/v2ray.service /etc/systemd/system/v2ray.service # 更新service目录 sudo systemctl daemon-reload # 启动v2ray sudo systemctl start v2ray.service
|
查看 v2ray 运行状态:
sudo systemctl status v2ray.service
如下 log,当 Active 状态是 active 时,启动完成。
| ● v2ray.service - V2Ray Service Loaded: loaded (/etc/systemd/system/v2ray.service; enabled; vendor preset: enabled) Active: active (running) since Mon 2021-03-15 00:53:22 CST; 4h 5min ago Docs: https://www.v2ray.com/ https://www.v2fly.org/ Main PID: 56320 (v2ray) Tasks: 11 (limit: 4501) Memory: 27.7M CGroup: /system.slice/v2ray.service └─56320 /home/ubuntu/app/install/v2ray/v2ray -c /home/ubuntu/app/v2ray.json
|
配置 v2ray
记录一下简要的配置备忘:
为了可读性和维护性,我用了 yaml 记录配置文件。v2ray 实际并不支持 yaml 格式的配置文件,将 yaml 先转成 json 才能够正常使用。
yaml 转 json: yq -j eval my_config.yaml > my_config.json
| log: access: /dev/null # 输出到空设备(丢弃),留空时将输出到 stdout error: /home/ubuntu/app/log/v2ray/error.log # 留空时将输出到 stdout logLevel: warning # debug|info|warning|error|none # 默认waring inbounds: 入口 - tag: in_transparent # dokodemo-door 协议的inbound,用于透明代理流量 port: 1081 # 使用环境变量: env:MY_V2RAY_PORT listen: 192.68.1.1 # 默认 0.0.0.0 protocol: dokodemo-door # blackhole|dokodemo-door|freedom|http|shadowsocks|socks|vmess settings: # 具体的配置内容,视协议而定 network: tcp,udp followRedirect: true sniffing: # 探测流量,根据目的地址重制连接的目标 enabled: true destOverride: - http - tls streamSettings: # 底层传输配置,优先于全局的传输配置 sockopt: tproxy: redirect outbounds: # rules没有匹配到的流量默认走第一个outbound - tag: out_direct protocol: freedom - tag: &my_server_tag my_server_tag protocol: vmess sendThrough: 0.0.0.0 settings: vnext: # 以下是服务器信息 - address: my_server.com port: 2048 users: - id: aaaaaaaa-aaaa-aaaa-aaaaa-aaaaaaaaaaaaa alterId: 64 streamSettings: network: tcp # 默认tcp, tcp|kcp|ws|http|domainsocket, sockopt: mark: 0 # 非0时,在传出连接上标记 SO_MARK tcpFastOpen: false mux: # 用于在一条TCP数据连接上承载多条逻辑TCP链路,可以加速握手 enabled: true concurrency: 4 # 默认8,范围:[1,1024],-1 表示加载Mux模块 routing: domainStrategy: IPIfNonMatch rules: - type: field # 通过域名匹配国外流量: 常用的网站集合 domain: - geosite:google - geosite:facebook - geosite:geolocation-!cn outboundTag: *my_server_tag - type: field # 通过域名匹配国外流量:自定义域名 domain: # 可以添加自己的域名: - firecore.com # infuse 官网 - thetvdb.com # jellyfin 刷新元数据用 - themoviedb.org # jellyfin 刷新元数据用 - omdbapi.com # jellyfin 刷新元数据用 outboundTag: *my_server_tag transport: # 传输设置,暂留空 policy: # 本地策略,暂留空
|
之后重启 v2ray 即可生效: sudo systemctl restart v2ray.service
。
配置 iptables
v2ray 已经运行起来,还需要将路由器收到的流量转发至 v2ray 监听的端口,让 v2ray 来接管需要代理的流量:
这里用一条明叫 V2RAY 的链来过滤需要被接管的流量,过滤不通过的流量会按照默认规则路由,不会走到 V2ray:
| # 首先清空这条链(不存在会报错) sudo iptables -t nat -F V2RAY # 新建链 sudo iptables -t nat -N V2RAY
# 私有IP处理,RETURN: 过滤不通过,返回 sudo iptables -t nat -A V2RAY -d 0/8 -j RETURN sudo iptables -t nat -A V2RAY -d 10/8 -j RETURN sudo iptables -t nat -A V2RAY -d 127/8 -j RETURN sudo iptables -t nat -A V2RAY -d 169.254/16 -j RETURN sudo iptables -t nat -A V2RAY -d 172.16/12 -j RETURN sudo iptables -t nat -A V2RAY -d 192.168/16 -j RETURN sudo iptables -t nat -A V2RAY -d 224/4 -j RETURN sudo iptables -t nat -A V2RAY -d 240/4 -j RETURN sudo iptables -t nat -A V2RAY -d 255.255.255/32 -j RETURN
# 其他不想要代理的IP: # 这里一定需要将代理服务器的IP加进来(如果服务器是域名参考后面的说明): sudo iptables -t nat -A V2RAY -s my_v2ray_remote_server_ip -j RETURN sudo iptables -t nat -A V2RAY -s 10.10.20.11 -j RETURN sudo iptables -t nat -A V2RAY -s 10.10.20.12 -j RETURN
# 需要代理的流量转发至V2ray的端口:1081,以下两行分别设置通过单个IP匹配、通过网络号匹配: sudo iptables -t nat -A V2RAY -s 10.10.21.0/24 -p tcp -j REDIRECT --to-ports 1081 sudo iptables -t nat -A V2RAY -s 10.10.22.2 -p tcp -j REDIRECT --to-ports 1081
# 也可以直接设置剩下的所有流量全部转发,需要谨慎使用: # sudo iptables -t nat -A V2RAY -p tcp -j REDIRECT --to-ports 1081
# 将 POSTROUTING & OUTPUT 链的流量转发到V2RAY,具体只是搜索:iptable三表五链 sudo iptables -t nat -A PREROUTING -p tcp -j V2RAY sudo iptables -t nat -A OUTPUT -p tcp -j V2RAY
|
备份修改后的 iptables
| sudo /bin/bash /home/root/myipset.bash backup
|
具体参考上一篇 blog.
至此,被代理的主机已经可以无感穿过防火墙了。
iptables 规则过滤域名
iptables 仅能够过滤 IP,但是可以通过曲线救国手段过滤某些域名。
这个曲线救国的工具就是 ipset ubuntu 默认不带,需要先安装:
| sudo apt-get install ipset -y
# 创建一个ipset(本质就是一个ip的列表) sudo ipset create my-v2ray-ip-list hash:ip
|
编辑 dnsmasq 的配置文件:sudo vim /etc/dnsmasq.conf
追加写入:
| # 用于将域名 v2ray_server_host 匹配到的域名的ip写入 my-v2ray-ip-list 中 # 距离 baidu.com 可以匹配到 baidu.com, pan.baidu.com 等。 ipset=/v2ray_server_host/my-v2ray-ip-list
|
之后重启 dnsmasq 服务即可生效 systemctl restart dnsmasq.service
。
持久化 ipset 的配置
由于 ipset 关机会丢失,这里为它写一个自动保存和加载的脚本,参考上一篇中 iptables 的脚本。
service 文件路径 /etc/systemd/system/myipset.service
处理 ipset 的脚本路径 /home/root/ipset.bash
ipset 备份文件保存路径 /home/root/backup.ipset.ipv4
创建文件 service 文件,内容如下:
| [Unit] Description=backup ipset when shutdown & restore ipset when boot Before=myiptables.service
[Service] Type=oneshot RemainAfterExit=true ExecStart=/bin/bash /home/root/ipset.bash restore ExecStop=/bin/bash /home/root/ipset.bash backup
[Install] WantedBy=multi-user.target
|
上面用到的保存 ipset 数据的脚本 ipset.bash 内容如下,
| default_backup_file="/home/root/backup.ipset.ipv4" # 关机时备份文件的位置,需要自定义 echo "$default_backup_file"
action=$1 backup_file=${2:-$default_backup_file}
if [ ! "${backup_file}" ]; then echo "param 2 error: should not empty." exit 1 fi if [ "$action" == 'restore' ]; then /sbin/ipset restore <"${backup_file}" exit 0 fi if [ "$action" == 'backup' ]; then ensure_dir_exist "$(dirname "$backup_file")" /sbin/ipset save >"$backup_file" exit 0 fi echo backup_file path: "${default_backup_file}" echo "user param: 'backup' or 'restore'" exit 1
|
保存好脚本
之后手动保存一次 ipset 的数据: ipset save > /home/root/backup.ipset.ipv4
接下来开始激活 ipset.service:
| sudo systemctl daemon-reload # systemd刷新service文件 sudo systemctl enable myipset # 启用开机自启动 myipset sudo systemctl start myipset # 运行 myipset
|
重新开关机之后也可以正常运行了。