Add: document level-1&2

This commit is contained in:
JimhHan
2021-03-25 22:33:41 +08:00
parent d0627944b2
commit c58fabe474
44 changed files with 3343 additions and 217 deletions
+18
View File
@@ -0,0 +1,18 @@
# 进阶文档
**这个章节包含进阶级的Xray使用心得分享, 如果您已经熟悉Xray, 那么这里的经验可以让您更加发挥Xray的威力**
[透明代理入门](./transparent_proxy/transparent_proxy.md) by <img src="https://avatars2.githubusercontent.com/u/57820613?s=32" width="32px" height="32px" alt="a"/> [@kirin](https://github.com/kirin10000)</font>
透明代理(TProxy)的入门篇章。
[透明代理(TProxy)配置教程 ](./tproxy.md) by <img src="https://avatars2.githubusercontent.com/u/41363844?s=32" width="32px" height="32px" alt="a"/> [@BioniCosmos](https://github.com/BioniCosmos)</font>
基于Xray的透明代理(TProxy)配置完整教程。
[[透明代理]通过gid规避Xray流量](./iptables_gid.md) by <img src="https://avatars2.githubusercontent.com/u/57820613?s=32" width="32px" height="32px" alt="a"/> [@kirin](https://github.com/kirin10000)</font>
在iptables/nftables实现的透明代理中,一种新的规避Xray流量的方式。
+197
View File
@@ -0,0 +1,197 @@
# 透明代理通过gid规避Xray流量
在现有的iptables透明代理白话文(**[新 V2Ray 白话文指南-透明代理](https://guide.v2fly.org/app/transparent_proxy.html)** 、 **[新 V2Ray 白话文指南-透明代理(TPROXY)](https://guide.v2fly.org/app/tproxy.html)** 、 **[透明代理(TProxy)配置教程](./tproxy)**)教程中,对Xray流量的规避处理是打mark实现的。即对Xray出站流量打mark,通过设置iptables规则对对应mark的流量直连,来规避Xray流量,防止回环。
这么做有以下几个问题:
1. **[莫名流量进入PREROUTING链](https://github.com/v2ray/v2ray-core/issues/2621)**
2. 安卓系统有自己的mark机制,该方案在安卓上不可用
本教程的方案不需要设置mark,理论性能更高,同时也不存在上述问题。
## 思路
tproxy流量只能被root权限用户(uid==0)或其他有CAP_NET_ADMIN权限的用户接收。
iptables规则可以通过uid(用户id)和gid(用户组id)分流。
让Xray运行在一个uid==0但gid!=0的用户上,设置iptables规则不代理该gid的流量来规避Xray流量。
## 配置过程
### 1. 前期准备
**安卓系统**
1. 系统已root
2. 安装 **[busybox](https://play.google.com/store/apps/details?id=stericson.busybox)**
3. 有一个可以执行命令的终端,可以使用adb shell,termux等。
**其它Linux系统**
需要依赖sudo,iptables的tproxy模块和extra模块。
一般系统都有自带,openwrt运行:
```bash
opkg install sudo iptables-mod-tproxy iptables-mod-extra
```
另附上一些openwrt常用的依赖,缺少可能导致Xray无法运行
```bash
opkg install libopenssl ca-certificates
```
### 2. 添加用户(安卓用户请忽略)
安卓系统不支持/etc/passwd文件来管理用户,请忽略,直接下一步。
```bash
grep -qw xray_tproxy /etc/passwd || echo "xray_tproxy:x:0:23333:::" >> /etc/passwd
```
其中xray_tproxy是用户名,0是uid,23333是gid,用户名和gid可以自己定,uid必须为0。
检查用户是否添加成功,运行
```bash
sudo -u xray_tproxy id
```
显示的结果应该是uid为0,gid为23333
### 3. 配置运行Xray,配置iptables规则
在现有的iptables透明代理白话文(**[新 V2Ray 白话文指南-透明代理](https://guide.v2fly.org/app/transparent_proxy.html)** 、 **[新 V2Ray 白话文指南-透明代理(TPROXY)](https://guide.v2fly.org/app/tproxy.html)** 、 **[透明代理(TProxy)配置教程](./tproxy)**)教程的基础上修改:
1. 修改json配置文件,删除mark相关内容
2. 修改iptables规则,删除mark相关内容,并在OUTPUT链应用规则处添加选项"-m owner ! --gid-owner 23333"。
如:
```bash
iptables -t mangle -A OUTPUT -j XRAY_SELF
```
改为
```bash
iptables -t mangle -A OUTPUT -m owner ! --gid-owner 23333 -j XRAY_SELF
```
3. 修改运行Xray的方式,使其运行在uid为0,gid为23333的用户上,参考[这里](#3-配置最大文件大开数运行xray客户端)。
## 下面提供一个实现tproxy全局代理的完整配置过程
### 1. 完成 **[前期准备](#1-前期准备)** 和 **[添加用户](#2-添加用户安卓用户请忽略)**
### 2. 准备Xray配置文件
配置Xray任意门监听12345,开启followRedirect和tproxy,不需要设置sniffing:
```json
{
"inbounds": [
{
"port": 12345,
"protocol": "dokodemo-door",
"settings": {
"network": "tcp,udp",
"followRedirect": true
},
"streamSettings": {
"sockopt": {
"tproxy": "tproxy"
}
}
}
],
"outbounds": [
{
你的服务器配置
}
]
}
```
### 3. 配置最大文件大开数&运行Xray客户端
关于最大文件大开数问题见: **[too many open files 问题](https://guide.v2fly.org/app/tproxy.html#解决-too-many-open-files-问题)**
目前Xray服务端使用官方脚本安装的已经自动配置了最大文件大开数,无需再修改。
**安卓系统**
```bash
ulimit -SHn 1000000
setuidgid 0:23333 "运行Xray的命令"&
```
**其它Linux系统**
```bash
ulimit -SHn 1000000
sudo -u xray_tproxy "运行Xray的命令"&
```
*第一条命令:*
改变最大打开文件数,只对当前终端有效,每次启动Xray前都要运行,该命令是设置客户端的最大文件大开数
*第二条命令:*
以uid为0,gid不为0的用户来运行Xray客户端,后面加&代表放在后台运行
**检查最大文件大开数是否设置成功**
```bash
cat /proc/Xray的pid/limits
```
找到max open files一项,应该是你设置的数值。pid的获取方法为运行`ps`或`ps -aux`或`ps -a`
服务端和客户端都要检查
### 4. 设置iptables规则
**代理ipv4**
```bash
ip rule add fwmark 1 table 100
ip route add local 0.0.0.0/0 dev lo table 100
# 代理局域网设备
iptables -t mangle -N XRAY
# "网关所在ipv4网段" 通过运行命令"ip address | grep -w inet | awk '{print $2}'"获得,一般有多个
iptables -t mangle -A XRAY -d 网关所在ipv4网段1 -j RETURN
iptables -t mangle -A XRAY -d 网关所在ipv4网段2 -j RETURN
...
# 组播地址直连
iptables -t mangle -A XRAY -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A XRAY -d 255.255.255.255/32 -j RETURN
#如果网关作为主路由,则加上这一句,见:https://xtls.github.io/documents/level-2/transparent_proxy/transparent_proxy.md#iptables透明代理的其它注意事项
#网关LAN_IPv4地址段,运行命令"ip address | grep -w "inet" | awk '{print $2}'"获得,是其中的一个
iptables -t mangle -A XRAY ! -s 网关LAN_IPv4地址段 -j RETURN
# 给 TCP 打标记 1,转发至 12345 端口
# mark只有设置为1,流量才能被Xray任意门接受
iptables -t mangle -A XRAY -p tcp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A XRAY -p udp -j TPROXY --on-port 12345 --tproxy-mark 1
# 应用规则
iptables -t mangle -A PREROUTING -j XRAY
# 代理网关本机
iptables -t mangle -N XRAY_MASK
iptables -t mangle -A XRAY_MASK -m owner --gid-owner 23333 -j RETURN
iptables -t mangle -A XRAY_MASK -d 网关所在ipv4网段1 -j RETURN
iptables -t mangle -A XRAY_MASK -d 网关所在ipv4网段2 -j RETURN
...
iptables -t mangle -A XRAY_MASK -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A XRAY_MASK -d 255.255.255.255/32 -j RETURN
iptables -t mangle -A XRAY_MASK -j MARK --set-mark 1
iptables -t mangle -A OUTPUT -p tcp -j XRAY_MASK
iptables -t mangle -A OUTPUT -p udp -j XRAY_MASK
```
**代理ipv6(可选)**
```bash
ip -6 rule add fwmark 1 table 106
ip -6 route add local ::/0 dev lo table 106
# 代理局域网设备
ip6tables -t mangle -N XRAY6
# "网关所在ip6网段" 通过运行命令"ip address | grep -w inet6 | awk '{print $2}'"获得。
ip6tables -t mangle -A XRAY6 -d 网关所在ipv6网段1 -j RETURN
ip6tables -t mangle -A XRAY6 -d 网关所在ipv6网段2 -j RETURN
...
# 如果网关作为主路由,则加上这一句,见:https://xtls.github.io/documents/level-2/transparent_proxy/transparent_proxy.md#iptables透明代理的其它注意事项
# 网关LAN_IPv6地址段,运行命令"ip address | grep -w "inet6" | awk '{print $2}'"获得,是其中的一个
ip6tables -t mangle -A XRAY6 ! -s 网关LAN_IPv6地址段 -j RETURN
ip6tables -t mangle -A XRAY6 -p udp -j TPROXY --on-port 12345 --tproxy-mark 1
ip6tables -t mangle -A XRAY6 -p tcp -j TPROXY --on-port 12345 --tproxy-mark 1
ip6tables -t mangle -A PREROUTING -j XRAY6
# 代理网关本机
ip6tables -t mangle -N XRAY6_MASK
ip6tables -t mangle -A XRAY6_MASK -m owner --gid-owner 23333 -j RETURN
ip6tables -t mangle -A XRAY6_MASK -d 网关所在ipv6网段1 -j RETURN
ip6tables -t mangle -A XRAY6_MASK -d 网关所在ipv6网段2 -j RETURN
...
ip6tables -t mangle -A XRAY6_MASK -j MARK --set-mark 1
ip6tables -t mangle -A OUTPUT -p tcp -j XRAY6_MASK
ip6tables -t mangle -A OUTPUT -p udp -j XRAY6_MASK
```
+371
View File
@@ -0,0 +1,371 @@
# 透明代理(TProxy)配置教程
本配置基于[TProxy 透明代理的新 V2Ray 白话文教程](https://guide.v2fly.org/app/tproxy.html),加入了 Xray 的新特性,使用 VLESS + XTLS Splice 方案,并将旧教程中默认出站代理的分流方式改为默认出站直连,使用者请按照实际情况进行修改。
本文中所有配置已在 Raspberry Pi 2B、Ubuntu 20.04 环境下测试成功,如在其它环境中使用请自行调整配置。
## 开始之前
请检查您的设备是否有可用的网络连接,且服务端已经配置成功,客户端已经安装完毕。
需注意的是,目前很多透明代理教程都会将 Linux 系统的 IP 转发打开,但这样会导致 Splice 性能下降。详情请参考[大案牍术破案纪实第三篇--我们是如何破解 Splice 性能下降甚至低于 Direct 之谜的](https://github.com/XTLS/Xray-core/discussions/59)。
这里我想要补充的是,很多透明代理教程会使用 Netfilter 进行分流,使直连流量直接发出而不经过 Xray,这时必须开启 IP 转发;也有的教程,如本文,会将所有流量导入 Xray 之中,由 Xray 的路由模块进行分流,这时无需开启 IP 转发。
## Xray 配置
为了更好的分流体验,请替换默认路由规则文件为 [Loyalsoldier/v2ray-rules-dat](https://github.com/Loyalsoldier/v2ray-rules-dat),否则 Xray-core 将无法加载本配置。
```bash
sudo curl -oL /usr/local/share/xray/geoip.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
sudo curl -oL /usr/local/share/xray/geosite.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat
```
```json
{
"log": {
"loglevel": "warning",
"error": "/var/log/xray/error.log",
"access": "/var/log/xray/access.log"
},
"inbounds": [
{
"tag": "all-in",
"port": 12345,
"protocol": "dokodemo-door",
"settings": {
"network": "tcp,udp",
"followRedirect": true
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
},
"streamSettings": {
"sockopt": {
"tproxy": "tproxy"
}
}
}
],
"outbounds": [
{
"tag": "direct",
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIPv4"
},
"streamSettings": {
"sockopt": {
"mark": 2
}
}
},
{
"tag": "proxy",
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "服务端域名",
"port": 443,
"users": [
{
"id": "UUID",
"flow": "xtls-rprx-splice",
"encryption": "none"
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "xtls",
"sockopt": {
"mark": 2
}
}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {
"response": {
"type": "http"
}
}
},
{
"tag": "dns-out",
"protocol": "dns",
"settings": {
"address": "8.8.8.8"
},
"proxySettings": {
"tag": "proxy"
},
"streamSettings": {
"sockopt": {
"mark": 2
}
}
}
],
"dns": {
"hosts": {
"服务端域名": "服务端 IP"
},
"servers": [
{
"address": "119.29.29.29",
"port": 53,
"domains": [
"geosite:cn"
],
"expectIPs": [
"geoip:cn"
]
},
{
"address": "223.5.5.5",
"port": 53,
"domains": [
"geosite:cn"
],
"expectIPs": [
"geoip:cn"
]
},
"8.8.8.8",
"1.1.1.1",
"https+local://doh.dns.sb/dns-query"
]
},
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"inboundTag": [
"all-in"
],
"port": 53,
"outboundTag": "dns-out"
},
{
"type": "field",
"ip": [
"8.8.8.8",
"1.1.1.1"
],
"outboundTag": "proxy"
},
{
"type": "field",
"domain": [
"geosite:category-ads-all"
],
"outboundTag": "block"
},
{
"type": "field",
"domain": [
"geosite:geolocation-!cn"
],
"outboundTag": "proxy"
},
{
"type": "field",
"ip": [
"geoip:telegram"
],
"outboundTag": "proxy"
}
]
}
}
```
::: tip TIP
本配置会劫持所有发往 53 端口的流量以解决 DNS 污染问题,所以客户端和本机的 DNS 服务器的地址可以随意配置。
:::
## 策略路由配置
```
sudo ip route add local default dev lo table 100 # 添加路由表 100
sudo ip rule add fwmark 1 table 100 # 为路由表 100 设定规则
```
## Netfilter 配置
::: warning 注意
nftables 配置与 iptables 配置二选一,不可同时使用。
:::
<tabs title="netfilter">
<tab title="nftables">
```nftables
#!/usr/sbin/nft -f
flush ruleset
define RESERVED_IP = {
10.0.0.0/8,
100.64.0.0/10,
127.0.0.0/8,
169.254.0.0/16,
172.16.0.0/12,
192.0.0.0/24,
224.0.0.0/4,
240.0.0.0/4,
255.255.255.255/32
}
table ip xray {
chain prerouting {
type filter hook prerouting priority mangle; policy accept;
ip daddr $RESERVED_IP return
ip daddr 192.168.0.0/16 tcp dport != 53 return
ip daddr 192.168.0.0/16 udp dport != 53 return
ip protocol tcp tproxy to 127.0.0.1:12345 meta mark set 1
ip protocol udp tproxy to 127.0.0.1:12345 meta mark set 1
}
chain output {
type route hook output priority mangle; policy accept;
ip daddr $RESERVED_IP return
ip daddr 192.168.0.0/16 tcp dport != 53 return
ip daddr 192.168.0.0/16 udp dport != 53 return
meta mark 2 return
ip protocol tcp meta mark set 1
ip protocol udp meta mark set 1
}
}
```
::: tip
**使用方法**
将上述配置写入一个文件(如 `nft.conf`),之后将该文件赋予可执行权限,最后使用 root 权限执行该文件即可(`# ./nft.conf`)。
:::
</tab>
<tab title="iptables">
```bash
iptables -t mangle -N XRAY
iptables -t mangle -A XRAY -d 10.0.0.0/8 -j RETURN
iptables -t mangle -A XRAY -d 100.64.0.0/10 -j RETURN
iptables -t mangle -A XRAY -d 127.0.0.0/8 -j RETURN
iptables -t mangle -A XRAY -d 169.254.0.0/16 -j RETURN
iptables -t mangle -A XRAY -d 172.16.0.0/12 -j RETURN
iptables -t mangle -A XRAY -d 192.0.0.0/24 -j RETURN
iptables -t mangle -A XRAY -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A XRAY -d 240.0.0.0/4 -j RETURN
iptables -t mangle -A XRAY -d 255.255.255.255/32 -j RETURN
iptables -t mangle -A XRAY -d 192.168.0.0/16 -p tcp ! --dport 53 -j RETURN
iptables -t mangle -A XRAY -d 192.168.0.0/16 -p udp ! --dport 53 -j RETURN
iptables -t mangle -A XRAY -p tcp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A XRAY -p udp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A PREROUTING -j XRAY
iptables -t mangle -N XRAY_SELF
iptables -t mangle -A XRAY_SELF -d 10.0.0.0/8 -j RETURN
iptables -t mangle -A XRAY_SELF -d 100.64.0.0/10 -j RETURN
iptables -t mangle -A XRAY_SELF -d 127.0.0.0/8 -j RETURN
iptables -t mangle -A XRAY_SELF -d 169.254.0.0/16 -j RETURN
iptables -t mangle -A XRAY_SELF -d 172.16.0.0/12 -j RETURN
iptables -t mangle -A XRAY_SELF -d 192.0.0.0/24 -j RETURN
iptables -t mangle -A XRAY_SELF -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A XRAY_SELF -d 240.0.0.0/4 -j RETURN
iptables -t mangle -A XRAY_SELF -d 255.255.255.255/32 -j RETURN
iptables -t mangle -A XRAY_SELF -d 192.168.0.0/16 -p tcp ! --dport 53 -j RETURN
iptables -t mangle -A XRAY_SELF -d 192.168.0.0/16 -p udp ! --dport 53 -j RETURN
iptables -t mangle -A XRAY_SELF -m mark --mark 2 -j RETURN
iptables -t mangle -A XRAY_SELF -p tcp -j MARK --set-mark 1
iptables -t mangle -A XRAY_SELF -p udp -j MARK --set-mark 1
iptables -t mangle -A OUTPUT -j XRAY_SELF
```
</tab>
</tabs>
配置完成后,将局域网内其它设备的默认网关改为该设备 IP,就可以直接翻墙了。在其它主机和本机皆测试成功后,可进行下一步配置。
## 配置永久化与开机自启
<br/>
<tabs title="netfilter">
<tab title="nftables">
首先将已经编辑好的 nftables 配置文件移动到 `/etc` 目录下,并重命名为 `nftables.conf`。然后编辑 `/lib/systemd/system/nftables.service`。
``` ini
[Unit]
Description=nftables
Documentation=man:nft(8) http://wiki.nftables.org
Wants=network-pre.target
Before=network-pre.target shutdown.target
Conflicts=shutdown.target
DefaultDependencies=no
[Service]
Type=oneshot
RemainAfterExit=yes
StandardInput=null
ProtectSystem=full
ProtectHome=true
ExecStart=/usr/sbin/nft -f /etc/nftables.conf ; /usr/sbin/ip route add local default dev lo table 100 ; /usr/sbin/ip rule add fwmark 1 table 100
ExecReload=/usr/sbin/nft -f /etc/nftables.conf
ExecStop=/usr/sbin/nft flush ruleset ; /usr/sbin/ip route del local default dev lo table 100 ; /usr/sbin/ip rule del table 100
[Install]
WantedBy=sysinit.target
```
最后 enable 即可。
</tab>
<tab title="iptables">
关于 iptables 的永久化,建议直接安装 `iptables-persistent`。
安装过程中会提示你选择“是否保存配置”,如果已经将 iptables 配置写入系统,那么此时选择“是”即可;如果尚未写入也没有关系,安装完毕后将配置写入,然后执行 `netfilter-persistent save` 即可(需要 root 权限)。
之后编辑 `/lib/systemd/system/netfilter-persistent.service`。
``` ini
[Unit]
Description=netfilter persistent configuration
DefaultDependencies=no
Wants=network-pre.target systemd-modules-load.service local-fs.target
Before=network-pre.target shutdown.target
After=systemd-modules-load.service local-fs.target
Conflicts=shutdown.target
Documentation=man:netfilter-persistent(8)
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/sbin/netfilter-persistent start ; /usr/sbin/ip route add local default dev lo table 100 ; /usr/sbin/ip rule add fwmark 1 table 100
ExecStop=/usr/sbin/netfilter-persistent stop ; /usr/sbin/ip route del local default dev lo table 100 ; /usr/sbin/ip rule del table 100
[Install]
WantedBy=multi-user.target
```
</tab>
</tabs>
Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

@@ -0,0 +1,249 @@
# 透明代理入门
## 什么是透明代理
透明代理简单地说就是不让被代理的设备感觉到自己被代理了。简单地说就是,被代理的设备上不需要运行任何代理软件(比如Xray、V2RayNG等),当你连接上网络时,你的设备已经被代理了。
这也意味着,代理的软件运行在别的地方,比如运行在路由器中,通过路由器上网的设备就自动被代理了。
## 透明代理的实现
透明代理的实现目前主要有两种方式:
### tun2socks
可用Windows/Linux(包括安卓)实现。因为实现过程比较简单,很少有教程,我这里简单描述一下。
**Windows**
1. 安装 **[Netch](https://github.com/NetchX/Netch/releases)** ,使用模式`[3] [TUN/TAP] 绕过局域网`启动。
2. 开启热点
3. 打开`控制面板`->`网络和 Internet`->`网络和共享中心`->`更改适配器设置`,找到`TAP-Windows Adapter`和`Microsoft Wi-Fi Direct Virtual Adapter`。
4. 鼠标右键点击`TAP-Windows Adapter`,`属性`->`共享`,勾选`允许其他网络用户通过此计算机的 Internet 连接来连接`,在`家庭网络连接`中选择`Microsoft Wi-Fi Direct Virtual Adapter`的那个网络连接,点击确定。
**Android**
1. 配置连接V2RayNG
2. 开启热点
3. 热点设置 -> 允许热点使用VPN(部分安卓系统可能没有这个选项)
### iptables/nftables
iptables与nftables实现透明代理的原理相同,下文统一使用iptables。
基于iptables的透明代理实现只能用于Linux系统(包括openwrt/安卓)。由于其比tun2socks更高效率以及适合在路由器中配置而广泛使用。
现存的三篇白话文透明代理教程其实讲的都是基于这种方案的透明代理实现,它们是: **[新 V2Ray 白话文指南-透明代理](https://guide.v2fly.org/app/transparent_proxy.html)** 、 **[新 V2Ray 白话文指南-透明代理(TPROXY)](https://guide.v2fly.org/app/tproxy.html)** 、 **[透明代理(TProxy)配置教程](../tproxy.md)** 。其中第一篇是基于iptables-redirect模式,已经过时了,不建议使用,仅供参考。第二篇和第三篇讲的都是基于iptables-tproxy模式的透明代理实现。
## iptables实现透明代理原理
Linux使用`Netfilter`来管理网络,`Netfilter`模型如下:
![Netfilter](./netfilter.png)
**假设使用路由器作为网关(即我们平时的上网方式),那么:**
局域网设备通过路由器访问互联网的流量方向:
`PREROUTING链->FORWARD链->POSTINGROUTING链`
局域网设备访问路由器的流量(如登陆路由器web管理界面/ssh连接路由器/访问路由器的dns服务器等)方向:
`PREROUTING链->INPUT链->网关本机`
路由器访问互联网的流量方向:
`网关本机->OUTPUT链->POSTINGROUTING链`
**通过使用iptables操控`PREROUTING链`和`OUTPUT链`的流量走向,转发到Xray,就可以代理局域网设备和网关本机。**
## 透明代理难在哪里
透明代理的难点就在于路由,所谓路由,就是区分哪些流量是直连的,哪些该被代理,所以我个人认为叫做**分流**更加合适。
我们可以把路由由易到难分为以下几个阶段:
1. 代理全部请求
2. 本地局域网IP/组播IP请求直连,其它请求代理
3. 在2的基础上直连Xray发起的连接请求
4. 在3的基础上直连指向中国大陆IP的连接请求,并对国内外域名选择国内外DNS服务器解析。
上面说的三篇教程,都是在第四阶段。所以新手直接阅读可能显得有点难懂。
## 从零开始一步步实现基于iptables-tproxy的透明代理
### 在开始之前,你需要有一定的基础知识:
1. 大概知道什么是TCP/IP协议、域名和DNS服务器
2. 知道什么是WAN口,LAN口,LAN_IP,WAN_IP以及DHCP服务器。对于旁路由,只有一个网口,这里称其为LAN口
3. 对Linux系统有最基础的了解(知道怎么运行命令)
4. 能够手写客户端json文件配置,至少要能看懂
### 前期准备工作
**1. 准备一个运行Linux系统的网关**
比如,刷了OpenWRT的路由器
**2. 在网关(路由器)准备好Xray可执行文件以及配置文件**
配置文件监听12345端口,开启tproxy:
```json
{
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"port": 12345,
"protocol": "dokodemo-door",
"settings": {
"network": "tcp,udp",
"followRedirect": true
},
"streamSettings": {
"sockopt": {
"tproxy": "tproxy"
}
}
}
],
"outbounds": [
{
你的服务器配置
}
]
}
```
我们由易到难,不写routing,只写一个inbound一个outbound。
### 首先,我们先试试做到第一阶段
将所有`PREROUTING链`的流量,都转发到Xray中。
运行Xray,执行以下指令:
```bash
ip rule add fwmark 1 table 100
ip route add local 0.0.0.0/0 dev lo table 100
iptables -t mangle -N XRAY
iptables -t mangle -A XRAY -p tcp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A XRAY -p udp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A PREROUTING -j XRAY
```
当你输入完之后,如果你是使用ssh连接到网关上的,你会发现ssh的连接断开了(不用紧张,断电重启即可恢复),并且透明代理无法上网;如果你是的网关是虚拟机,你会发现网关本身也无法上网,并且Xray日志access_log中出现许多源地址为目标地址,目标地址为WAN_IP的请求。
理论上网关本机访问公网只会经过`OUTPUT链`和`POSTROUTING链`,为什么操控`PREROUTING链`会导致网关无法上网呢?这是因为网络通讯往往是双向的,虽然网关访问公网IP不需要经过`PREROUTING链`,但被访问的服务器向网关返回信息时要经过`PREROUTING链`,且这部分被转发到Xray了,因此出现了日志中的反向请求。
我们修改一下规则,源IP不是来自局域网的则返回。重启网关,运行Xray,执行以下指令:
```bash
ip rule add fwmark 1 table 100
ip route add local 0.0.0.0/0 dev lo table 100
iptables -t mangle -N XRAY
# "网关LAN_IP地址段" 通过运行命令"ip address | grep -w "inet" | awk '{print $2}'"获得,是其中的一个
iptables -t mangle -A XRAY ! -s 网关LAN_IP地址段 -j RETURN
iptables -t mangle -A XRAY -p tcp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A XRAY -p udp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A PREROUTING -j XRAY
```
然后你会发现,虽然ssh连接断开了,但是透明代理已经可用了。只要我们修改系统dns为公共dns,就能正常上网了(因为现在网关访问不了,所以dns设置为网关是不行的)。
至此,第一阶段就完成了。之所以无法访问网关,是因为代理规则代理了全部流量,包括访问网关的流量。试想在VPS上访问你本地的网关,肯定是访问不了的,所以我们要对这部分流量直连,请看第二阶段:
### 第二阶段
重启网关,运行Xray,执行以下指令:
```bash
ip rule add fwmark 1 table 100
ip route add local 0.0.0.0/0 dev lo table 100
iptables -t mangle -N XRAY
# 所有目标地址在网关所在网段的请求直连
# 通过运行命令"ip address | grep -w "inet" | awk '{print $2}'"获得,一般来说有多个
iptables -t mangle -A XRAY -d 网关所在网段1 -j RETURN
iptables -t mangle -A XRAY -d 网关所在网段2 -j RETURN
...
# 目标地址为组播IP的请求直连
iptables -t mangle -A XRAY -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A XRAY -d 255.255.255.255/32 -j RETURN
iptables -t mangle -A XRAY -p tcp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A XRAY -p udp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A PREROUTING -j XRAY
```
使用这条规则后,上一条规则`iptables -t mangle -A XRAY ! -s 网关LAN_IP地址段 -j RETURN`便成为了多余规则,可以删去。
至此,第二阶段完成。网关已经可以访问,ssh不会断开。
### 第三阶段
我们平时用的DNS一般来自路由器,但这个iptables规则只代理了局域网中的设备,却没有代理网关本机,这样返回的DNS查询结果可能是错误的或者污染的。
iptables-tproxy不支持对`OUTPUT链`操作,但是`Netfilter`有个特性,在`OUTPUT链`给包打标记为`1`后相应的包会重路由到`PREROUTING链`上。所以我们就给网关本机需要代理的请求在`OUTPUT链`上标记`1`即可。
如果要代理网关本机发出的的全部请求,就会引入一个问题,Xray运行在网关,Xray向代理服务端发送请求,这个请求又被代理了,就形成了回环。
因此要代理网关本机,就要避免回环发生,即代理规则中规避Xray请求的流量。
**常见的方法有三种:**
1. 直连目标地址为VPS的流量
重启网关,运行Xray,执行以下指令:
```bash
#代理局域网设备
#继承上一个阶段的成果
ip rule add fwmark 1 table 100
ip route add local 0.0.0.0/0 dev lo table 100
iptables -t mangle -N XRAY
iptables -t mangle -A XRAY -d 网关所在网段1 -j RETURN
iptables -t mangle -A XRAY -d 网关所在网段2 -j RETURN
...
iptables -t mangle -A XRAY -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A XRAY -d 255.255.255.255/32 -j RETURN
iptables -t mangle -A XRAY -p tcp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A XRAY -p udp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A PREROUTING -j XRAY
#代理网关本机
iptables -t mangle -N XRAY_MASK
iptables -t mangle -A XRAY_MASK -d 网关所在网段1 -j RETURN
iptables -t mangle -A XRAY_MASK -d 网关所在网段2 -j RETURN
...
iptables -t mangle -A XRAY_MASK -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A XRAY_MASK -d 255.255.255.255/32 -j RETURN
iptables -t mangle -A XRAY_MASK -d VPS公网ip/32 -j RETURN
iptables -t mangle -A XRAY_MASK -j MARK --set-mark 1
iptables -t mangle -A OUTPUT -p tcp -j XRAY_MASK
iptables -t mangle -A OUTPUT -p udp -j XRAY_MASK
```
但是这么配置有个缺点,如果使用CDN或者VPS很多的话,就不好写规则了。
2. 通过mark规避
三个白话文教程都是使用这种方法规避,自行参考,这里不再赘述。
3. 通过gid规避(推荐)
参考 **[[透明代理]通过gid规避Xray流量](../iptables_gid.md)**
这样就完成了第三阶段的代理,也就是平时说的全局代理。但是记得把网关的DNS服务器设置为国外的DNS服务器,否则可能依然返回被污染的结果。
### 第四阶段
其实,并不是所有人都需要实现第四阶段。全局代理对于大部分情况已经适用。
特别是对于旁路由而言。需要代理时,将网关调成旁路由的IP,不需要代理时,将网关换回主路由IP。
至于第四阶段的具体实现,那三篇白话文教程讲的都是。在理解了上面的内容后,再去看那三篇白话文教程,就比较容易理解了。
### 代理ipv6
上面的规则只对ipv4生效,如果还想要代理ipv6请求,则使用ip6tables命令,用法与iptables基本相同。参考 **[[透明代理]通过gid规避Xray流量#4-设置iptables规则](../iptables_gid#4-设置iptables规则.md)**
# iptables透明代理的其它注意事项
1. 如果作为代理的网关作为主路由,要在`PREROUTING链`规则中加一条`iptables -t mangle -A XRAY ! -s 网关LAN_IP地址段 -j RETURN`,即在第一阶段使用、第二阶段被删除的指令。如果不写,WAN口中同网段的其它人可以将网关填写成你的WAN_IP,从而蹭你的透明代理用,还可能带来一定的危险性。
2. **[新 V2Ray 白话文指南-透明代理(TPROXY)#设置网关](https://guide.v2fly.org/app/tproxy.html#设置网关)** 中的第三条说:`手动配置 PC 的网络,将默认网关指向树莓派的地址即 192.168.1.22。此时 PC 应当能正常上网(由于还没设置代理,“正常”是指可以上国内的网站)`。实际上,Ubuntu、CentOS、debian等系统就算开启了IP转发,PC也不能正常上网,这是正常的。事实上只有OpenWRT能做到文中所描述的那样,据 **[@BioniCosmos](https://github.com/BioniCosmos)** 点拨,这是由于一般的Linux系统没有Masquery规则。
3. **[too many open files 问题](https://guide.v2fly.org/app/tproxy.html#解决-too-many-open-files-问题)** ,解决方法见 **[[透明代理]通过gid规避Xray流量-配置最大文件大开数&运行Xray客户端](../iptables_gid#3-配置最大文件大开数运行xray客户端)**
4. 关于开启ip_forward,待补充...
5. 避免已有连接的包二次通过 TPROXY ,待补充...
6. 主路由、单臂路由与旁路由,待补充...