diff --git a/README.md b/README.md index 965ffff..e78285d 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ## 拓扑模型 -XProxy部署在内网Linux主机上,通过 `macvlan` 网络创建独立MAC地址的虚拟网关,劫持内网设备的网络流量并进行透明代理;宿主机一般以单臂旁路由的方式接入,虚拟网关运行时不会干扰宿主机网络,且宿主机系统的流量也可被网关代理。 +XProxy 部署在内网 Linux 主机上,通过 `macvlan` 网络创建独立 MAC 地址的虚拟网关,劫持内网设备的网络流量进行透明代理;宿主机一般以单臂旁路由的方式接入,虚拟网关运行时不会干扰宿主机网络,同时宿主机系统的流量也可被网关代理。
@@ -26,15 +26,15 @@ XProxy部署在内网Linux主机上,通过 `macvlan` 网络创建独立MAC地
-XProxy运行以后,内网流量将被收集到代理内核上,目前内置了 `xray` ,`v2ray` ,`sagray` 三种内核,支持 `Shadowsocks` ,`ShadowsocksR` ,`VMess` ,`VLESS` ,`Trojan` ,`WireGuard` ,`SSH` ,`PingTunnel` 等多种代理协议,支持 `XTLS` ,`WebSocket` ,`QUIC` ,`gRPC` 等多种传输方式。同时,得益于V2ray的路由设计,代理的网络流量可被精确地分流,可以依据内网设备、目标地址、访问端口、连接域名、流量类型等多种方式进行路由。 +XProxy 运行以后,内网流量将被收集到代理内核上,目前内置了 `xray` ,`v2ray` ,`sagray` 三种内核,支持 `Shadowsocks` ,`ShadowsocksR` ,`VMess` ,`VLESS` ,`Trojan` ,`WireGuard` ,`SSH` ,`PingTunnel` 等多种代理协议,支持 `XTLS` ,`WebSocket` ,`QUIC` ,`gRPC` 等多种传输方式。同时,得益于V2ray的路由设计,代理的网络流量可被精确地分流,可以依据内网设备、目标地址、访问端口、连接域名、流量类型等多种方式进行路由。 -由于 XProxy 与宿主机网络完全解耦,一台主机上可运行多个虚拟网关,它们拥有不同的MAC地址,在网络模型上是多台独立的主机;因此各个虚拟网关能负责不同的功能,甚至它们之间还能互为上下级路由的关系,灵活实现多种网络功能。 +由于 XProxy 与宿主机网络完全解耦,一台主机上可运行多个虚拟网关,它们拥有不同的 MAC 地址,在网络模型上是多台独立的主机;因此各个虚拟网关能负责不同的功能,甚至它们之间还能互为上下级路由的关系,灵活实现多种网络功能。 ## 配置格式 -> 所有 `.json` 后缀的文件将视为JSON格式文件,其余将以YAML格式进行解析 +> 所有 `.json` 后缀的文件将视为 JSON 格式文件,其余将以 YAML 格式进行解析 -XProxy使用YAML或JSON格式的配置文件,包含以下部分: +XProxy 使用 YAML 或 JSON 格式的配置文件,包含以下部分: ```yaml proxy: @@ -89,9 +89,9 @@ proxy: + `core` :代理内核类型,可选 `xray` 、`v2ray` 、`sagray`,默认为 `xray` -+ `http` 与 `socks` :配置 http 与 socks5 入站代理,使用 `key: value` 格式,前者指定入站标志(路由配置中的inboundTag),后者指定监听端口,默认为空 ++ `http` 与 `socks` :配置 http 与 socks5 入站代理,使用 `key: value` 格式,前者指定入站标志(路由配置中的 inboundTag),后者指定监听端口,默认为空 -+ `addon` :自定义入站配置,每一项为单个内核inbound接口,具体格式可见[内核文档](https://xtls.github.io/config/inbound.html#inboundobject),默认为空 ++ `addon` :自定义入站配置,每一项为单个内核 inbound 接口,具体格式可见[内核文档](https://xtls.github.io/config/inbound.html#inboundobject),默认为空 + `sniff` :嗅探选项,用于获取透明代理中的连接域名: @@ -130,21 +130,21 @@ network: + `ipv4` 与 `ipv6` :指定 IPv4 与 IPv6 的网络信息,其中 `gateway` 为上游网关地址,`address` 为虚拟网关地址(CIDR格式,包含子网长度),不填写时保持不变,默认为空 -+ `bypass` :绕过代理的目标网段或IP,默认为空,建议绕过以下5个网段: ++ `bypass` :绕过代理的目标网段或 IP,默认为空,建议绕过以下5个网段: - + `169.254.0.0/16` :IPv4链路本地地址 + + `169.254.0.0/16` :IPv4 链路本地地址 + `224.0.0.0/3` :D类多点播送地址,E类保留地址 - + `fc00::/7` :IPv6唯一本地地址 + + `fc00::/7` :IPv6 唯一本地地址 - + `fe80::/10` :IPv6链路本地地址 + + `fe80::/10` :IPv6 链路本地地址 - + `ff00::/8` :IPv6组播地址 + + `ff00::/8` :IPv6 组播地址 -+ `exclude` :不代理的来源网段或IP; ++ `exclude` :不代理的来源网段或 IP -> `bypass` 与 `exclude` 中指定的IP或CIDR,在运行时将不会被TProxy捕获,即不进入用户态的代理路由,相当于无损耗的直连 +> `bypass` 与 `exclude` 中指定的 IP 或 CIDR,在运行时将不会被 TProxy 捕获,即不进入用户态的代理路由,相当于无损耗的直连 ### 路由资源 @@ -178,7 +178,7 @@ custom: - "ip6tables -t nat -A POSTROUTING -d fc00::3 -p tcp --dport 5353 -j SNAT --to fc00::4" ``` -自定义脚本命令,在启动代理前将依次执行,用于注入一些其他功能,默认为空 +自定义脚本命令,在启动代理前将依次执行,用于注入额外功能,默认为空 ### IPv6路由广播 @@ -226,17 +226,17 @@ radvd: + `AdvSendAdvert` :是否开启 RA 报文广播,启用 IPv6 时必须打开,默认为 `off` - + `AdvManagedFlag` :指示 IPv6 管理地址配置,即M位,默认为 `off` + + `AdvManagedFlag` :指示 IPv6 管理地址配置,即 M 位,默认为 `off` - + `AdvOtherConfigFlag` :指示 IPv6 其他有状态配置,即O位,默认为 `off` + + `AdvOtherConfigFlag` :指示 IPv6 其他有状态配置,即 O 位,默认为 `off` - + > M位与O位的详细定义在 [RFC4862](https://www.rfc-editor.org/rfc/rfc4862) 中给出: + + > M 位与 O 位的详细定义在 [RFC4862](https://www.rfc-editor.org/rfc/rfc4862) 中给出: - + `M=off` 且 `O=off` :使用 `Stateless` 模式,设备通过RA广播的前缀,配合 `EUI-64` 算法直接得到接口地址,即 `SLAAC` 方式 + + `M=off` 且 `O=off` :使用 `Stateless` 模式,设备通过 RA 广播的前缀,配合 `EUI-64` 算法直接得到接口地址,即 `SLAAC` 方式 - + `M=off` 且 `O=on` :使用 `Stateless DHCPv6` 模式,设备通过RA广播前缀与 `EUI-64` 计算接口地址,同时从 `DHCPv6` 获取DNS等其他配置 + + `M=off` 且 `O=on` :使用 `Stateless DHCPv6` 模式,设备通过 RA 广播前缀与 `EUI-64` 计算接口地址,同时从 `DHCPv6` 获取 DNS 等其他配置 - + `M=on` 且 `O=on` :使用 `Stateful DHCPv6` 模式,设备通过 `DHCPv6` 获取地址以及DNS等其他配置 + + `M=on` 且 `O=on` :使用 `Stateful DHCPv6` 模式,设备通过 `DHCPv6` 获取地址以及 DNS 等其他配置 + `M=on` 且 `O=off` :理论上不存在此配置 @@ -244,13 +244,13 @@ radvd: + `prefix` :IPv6 地址前缀配置,`cidr` 指定分配的前缀及掩码长度,`option` 指定[前缀选项](https://code.tools/man/5/radvd.conf/#lbAE) - + `route` :IPv6 路由定义,`cidr` 指定通告的路由 CIDR(注意客户端仅将RA报文来源链路地址设置为IPv6网关,此处设置并不能更改路由网关地址),`option` 指定[路由选项](https://code.tools/man/5/radvd.conf/#lbAF) + + `route` :指定 IPv6 路由,`cidr` 为通告的路由 CIDR(注意客户端仅将 RA 报文来源链路地址设置为 IPv6 网关,此处设置并不能更改路由网关地址),`option` 指定[路由选项](https://code.tools/man/5/radvd.conf/#lbAF) - + `rdnss` :递归 DNS 服务器地址,`ip` 指定 IPv6 下的 DNS 服务器列表,`option` 指定 [RDNSS 选项](https://code.tools/man/5/radvd.conf/#lbAG) + + `rdnss` :递归 DNS 服务器地址,`ip` 指定 IPv6 下的 DNS 服务器列表,`option` 指定[RDNSS选项](https://code.tools/man/5/radvd.conf/#lbAG) - + `dnssl` :DNS 搜寻域名,`suffix` 指定DNS解析的搜寻后缀列表,`option` 指定 [DNSSL 选项](https://code.tools/man/5/radvd.conf/#lbAH) + + `dnssl` :DNS 搜寻域名,`suffix` 指定 DNS 解析的搜寻后缀列表,`option` 指定[DNSSL选项](https://code.tools/man/5/radvd.conf/#lbAH) -> `RDNSS` 与 `DNSSL` 在 [RFC6106](https://www.rfc-editor.org/rfc/rfc6106) 中定义,将 DNS 配置信息直接放置在 RA 报文中发送,使用 `SLAAC` 时无需 `DHCPv6` 即可获取 DNS 服务器,但是旧版本 Windows 与 Android 等系统不支持该功能。 +> `RDNSS` 与 `DNSSL` 在 [RFC6106](https://www.rfc-editor.org/rfc/rfc6106) 中定义,将 DNS 配置信息直接放置在 RA 报文中发送,使用 `SLAAC` 时无需 `DHCPv6` 即可获取 DNS 服务器,但旧版本 Windows 与 Android 等系统不支持该功能。 ### DHCP服务选项 @@ -260,8 +260,10 @@ WIP... ### 1. 初始配置 +> XProxy 基于 macvlan 网络,开启混杂模式可以捕获非本机物理网卡的数据包,以此模拟出不同 MAC 地址的网卡 + ``` -# 开启网卡混杂模式 +# 开启混杂模式,网卡按实际情况指定 shell> ip link set eth0 promisc on # 启用IPv6内核模块 @@ -273,10 +275,8 @@ shell> modprobe ip6table_filter ``` # 网络配置按实际情况指定 shell> docker network create -d macvlan \ - --subnet=192.168.2.0/24 \ - --gateway=192.168.2.1 \ - --subnet=fc00::/64 \ - --gateway=fc00::1 \ + --subnet={IPv4网段} --gateway={IPv4网关} \ + --subnet={IPv6网段} --gateway={IPv6网关} \ --ipv6 -o parent=eth0 macvlan # 此处指定eth0网卡,需按实际调整 ``` @@ -386,12 +386,13 @@ shell> docker logs -f xproxy > 这一步旨在让宿主机能够使用虚拟网关,若无此需求可以跳过 -由于macvlan方式的限制,宿主机上开启macvlan的网卡无法直接与虚拟网关通讯,需要另外配置网桥才可连接 +由于 macvlan 限制,宿主机网卡无法直接与虚拟网关通讯,需要另外配置网桥才可连接 > 以下为配置基于 Debian,基于 RH、Arch 等的发行版配置略有不同 +编辑网卡配置文件 + ``` -# 编辑网卡配置文件 shell> vim /etc/network/interfaces ``` @@ -433,12 +434,18 @@ shell> /etc/init.d/networking restart ## 演示实例 -实例1. [使用XProxy绕过校园网认证登录](./docs/example_1.md) +> 由于 XProxy 涉及较为复杂的网络配置,这里准备了两个详细的实例供您理解 + ++ 实例1. [使用XProxy绕过校园网认证登录](./docs/example_1.md) -实例2. [家庭网络的IPv4与IPv6透明代理](./docs/example_2.md) ++ 实例2. [家庭网络的IPv4与IPv6透明代理](./docs/example_2.md) ## 开发相关 +### 运行参数 + +XProxy 默认使用 `/xproxy` 作为存储文件夹,该文件夹映射到外部主机作为持久存储,您可以使用 `EXPOSE_DIR` 环境变量修改该文件夹路径;同时,XProxy将默认读取该文件夹下的 `xproxy.yml` 作为配置文件,在运行时添加 `--config ...` 参数将读取指定配置文件;启动 XProxy 时若添加 `--debug` 参数,将进入调试模式,输出日志切换到 DEBUG 级别。 + ### TProxy配置 XProxy 默认使用以下配置: @@ -451,13 +458,9 @@ XProxy 默认使用以下配置: + IPv6 透明代理端口:`7289`,使用 `IPV6_TPROXY` 环境变量修改 -### 运行参数 - -XProxy 默认使用 `/xproxy` 作为存储文件夹,该文件夹映射到外部主机作为持久存储,您可以使用 `EXPOSE_DIR` 环境变量修改该文件夹路径;同时,XProxy将默认读取该文件夹下的 `xproxy.yml` 作为配置文件,在运行时添加 `--config custom.yml` 参数将读取指定配置文件;启动 XProxy 时若添加 `--debug` 参数,将进入调试模式,输出日志切换到 `DEBUG` 级别。 - ### 容器构建 -> XProxy 针对 buildkit 进行优化,使用 buildx 命令将会加快构建速度 +> XProxy 针对 buildkit 进行优化,使用 buildx 命令可加快构建速度 **本地构建** diff --git a/docs/example_1.md b/docs/example_1.md index c21580d..e6278cd 100644 --- a/docs/example_1.md +++ b/docs/example_1.md @@ -1 +1,191 @@ ## 使用XProxy绕过校园网认证登录 + +部分校园网在登录认证时需要 DNS 解析,因而在防火墙上允许 `TCP/53` 或 `UDP/53` 端口通行,借助这个漏洞,可将内网流量用 XProxy 代理并转发到公网服务器上,实现免认证、无限速的上网。 + +以下为一般情况下的网络拓扑: + +![Network](./img/example_1.png) + +为了方便讲解,我们假设以下典型情况: + ++ 校园网交换机无IPv6支持,同时存在QoS + ++ 无认证时允许53端口通行,ICMP流量无法通过 + ++ 使用三台公网服务器负载均衡,其53端口上运行有代理服务 + ++ 三台服务器只有一台支持 IPv4 与 IPv6 双栈,其余只支持 IPv4 + +### 代理协议 + +首先,从速度上考虑,我们应该选用socks层面的代理,它在代理服务器上的部署更方便,且CPU负载较低,缺点则是ICMP流量无法被代理,不过绝大多数情况下并不会用到公网ICMP流量(例如PING命令);其次,由于存在高峰期QoS,应使用基于TCP的代理协议,此外,为了避开校园网的流量审查,我们应该将流量加密传输;最后,由于软路由性能一般较差,而代理服务器无需考虑协议兼容性问题,我们可以考虑基于 XTLS 的传输方式,它可以显著降低代理 https 流量时的性能开销。 + +综上,选择 VLESS + XTLS 或者 Trojan + XTLS 代理是当前网络环境下的最优解。 + +### 初始化配置 + +> 分配 `192.168.2.0/24` 和 `fc00::/64` 给内网使用 + +路由器 WAN 口接入学校交换机,构建一个 NAT 转换,代理流量在路由器转发后送到公网服务器的53端口上;假设内网中路由器地址为 `192.168.2.1` ,配置虚拟网关 IPv4 地址为 `192.168.2.2` ,IPv6 地址为 `fc00::2` ;在网关中,无论 IPv4 还是 IPv6 流量都会被透明代理,由于校园网无 IPv6 支持,数据被封装后只通过 IPv4 网络发送,代理服务器接收以后再将其解开,对于 IPv6 流量,这里相当于一个 6to4 隧道。 + +``` +# 宿主机网卡假定为 eth0 +shell> ip link set eth0 promisc on +shell> modprobe ip6table_filter +shell> docker network create -d macvlan \ + --subnet=192.168.2.0/24 \ # 此处指定的参数为容器的默认网络配置 + --gateway=192.168.2.1 \ + --subnet=fc00::/64 \ + --gateway=fc00::1 \ + --ipv6 -o parent=eth0 macvlan +``` + +我们将配置文件保存在 `/etc/scutweb` 目录下,使用以下命令开启 XProxy 服务: + +``` +shell> docker run --restart always \ + --privileged --network macvlan -dt \ + --name scutweb --hostname scutweb \ + --volume /etc/scutweb/:/xproxy/ \ + --volume /etc/timezone:/etc/timezone:ro \ + --volume /etc/localtime:/etc/localtime:ro \ + dnomd343/xproxy:latest +``` + +### 参数配置 + +我们将三台服务器分别称为 `nodeA` ,`nodeB` 与 `nodeC` ,其中只有 `nodeC` 支持IPv6网络;此外,我们在内网分别暴露3个 socks 服务端口,用于检测三台服务器的可用性。 + +由于校园网无 IPv6 支持,这里 IPv6 上游网关可以不填写;虚拟网关对内网发布 RA 通告,让内网设备使用 SLAAC 配置网络地址,同时将其作为 IPv6 网关;此外,如果路由器开启了 DHCP 服务,需要将默认网关改为 `192.168.2.2` ,也可以启用 XProxy 自带的 DHCPv4 服务。 + +修改 `xproxy.yml` ,写入以下配置: + +```yaml +proxy: + log: debug + core: xray + socks: + nodeA: 1081 + nodeB: 1082 + nodeC: 1083 + +network: + dns: + - 192.168.2.1 + ipv4: + gateway: 192.168.2.1 + address: 192.168.2.2/24 + ipv6: + gateway: null + address: fc00::2/64 + bypass: + - 169.254.0.0/16 + - 224.0.0.0/3 + - fc00::/7 + - fe80::/10 + - ff00::/8 + +radvd: + log: 5 + enable: true + option: + AdvSendAdvert: on + prefix: + cidr: fc00::/64 + +custom: + - "iptables -t nat -N FAKE_PING" + - "iptables -t nat -A FAKE_PING -j DNAT --to-destination 192.168.2.2" + - "iptables -t nat -A PREROUTING -i eth0 -p icmp -j FAKE_PING" + - "ip6tables -t nat -N FAKE_PING" + - "ip6tables -t nat -A FAKE_PING -j DNAT --to-destination fc00::2" + - "ip6tables -t nat -A PREROUTING -i eth0 -p icmp -j FAKE_PING" + +update: + cron: "0 0 4 * * *" + url: + geoip.dat: "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat" + geosite.dat: "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat" +``` + +在开始代理前,我们使用 `custom` 注入了一段脚本配置:由于这里我们只代理 TCP 与 UDP 流量,ICMP 数据包不走代理,内网设备 ping 外网时会一直无响应,加入这段脚本可以创建一个 NAT,假冒远程主机返回成功回复,但实际上 ICMP 数据包并未实际到达,效果上表现为 ping 成功且延迟为内网访问时间。 + +> 这段脚本并无实质作用,只是演示 `custom` 功能 + +### 代理配置 + +接下来,我们应该配置出站代理,修改 `config/outbounds.json` 文件,填入公网代理服务器参数: + +```json +{ + "outbounds": [ + { + "tag": "nodeA", + ··· + }, + { + "tag": "nodeB", + ··· + }, + { + "tag": "nodeC", + ··· + }, + ] +} +``` + +接着配置路由部分,让暴露的三个 socks5 接口对接到三台服务器上,并分别配置IPv4与IPv6的负载均衡;路由核心在这里接管所有流量,IPv4 流量应将随机转发到三台服务器,而 IPv6 流量只送往 `nodeC` 服务器;创建 `config/routing.json` 文件,写入以下配置: + +```json +{ + "routing": { + "domainStrategy": "AsIs", + "rules": [ + { + "type": "field", + "inboundTag": ["nodeA"], + "outboundTag": "nodeA" + }, + { + "type": "field", + "inboundTag": ["nodeB"], + "outboundTag": "nodeB" + }, + { + "type": "field", + "inboundTag": ["nodeC"], + "outboundTag": "nodeC" + }, + { + "type": "field", + "ip": ["0.0.0.0/0"], + "balancerTag": "ipv4" + }, + { + "type": "field", + "ip": ["::/0"], + "balancerTag": "ipv6" + } + ], + "balancers": [ + { + "tag": "ipv4", + "selector": [ "nodeA", "nodeB", "nodeC" ] + }, + { + "tag": "ipv6", + "selector": [ "nodeC" ] + } + ] + } +} +``` + +重启 XProxy 容器让配置生效: + +``` +shell> docker restart scutweb +``` + +最后,验证代理服务是否正常工作,若出现问题可以查看 XProxy 以及 `/etc/scutweb/log` 文件夹下的日志,定位错误原因。 diff --git a/docs/example_2.md b/docs/example_2.md index f042f88..b6fa935 100644 --- a/docs/example_2.md +++ b/docs/example_2.md @@ -1 +1,3 @@ -## 家庭网络的IPv4与IPv6透明代理 \ No newline at end of file +## 家庭网络的IPv4与IPv6透明代理 + +WIP... diff --git a/docs/img/example_1.png b/docs/img/example_1.png new file mode 100644 index 0000000..7a5b7a8 Binary files /dev/null and b/docs/img/example_1.png differ