透明代理实现
参考资料
https://guide.v2fly.org/app/tproxy.html
https://xtls.github.io/document/level-2/transparent_proxy/transparent_proxy.html
开启IP转发
-
echo net.ipv4.ip_forward=1 >> /etc/sysctl.conf
:echo net.ipv4.ip_forward=1
:这部分的作用是输出net.ipv4.ip_forward=1
这个字符串。net.ipv4.ip_forward=1
是一个设置项,表示启用IPv4的IP转发。IP转发是指系统接收到一个网络接口上的数据包,并将其转发到另一个网络接口的能力,这对于路由器和网关设备来说是必要的功能。>> /etc/sysctl.conf
:这部分的作用是将前面echo
命令的输出追加到/etc/sysctl.conf
文件的末尾。/etc/sysctl.conf
是一个系统配置文件,用于在系统启动时设置内核参数。通过将net.ipv4.ip_forward=1
添加到这个文件,你可以确保每次系统启动时IP转发都会被启用。
-
&&
:这是一个逻辑运算符,用于连接两个命令。它的作用是如果前一个命令(即echo net.ipv4.ip_forward=1 >> /etc/sysctl.conf
)执行成功(即返回状态为0),则执行后一个命令(即sysctl -p
)。 -
sysctl -p
:sysctl
是一个用于运行时修改内核参数的工具。-p
参数表示加载/etc/sysctl.conf
文件中的设置。这意味着在/etc/sysctl.conf
文件被修改后,通过执行sysctl -p
可以立即应用这些更改,而无需重启系统。
综上所述,这条命令的整体作用是将IP转发的设置添加到系统配置中,并立即应用这一更改,从而启用系统的IP转发功能。这对于设置路由器、防火墙或执行网络地址转换(NAT)等网络相关任务非常重要。
nftables 配置
lsmod | grep nft 的目的是在Linux系统中查找已加载的模块(Kernel modules),特别是那些与nft(即nftables)相关的模块。lsmod命令用于显示当前已加载的内核模块列表,而grep nft用于从这个列表中过滤出包含字符串“nft”的行。这可以帮助你确认是否已经加载了nftables相关的内核模块。
如果nftables已经在系统上被使用,你可能会看到一些像是nft_counter、nft_chain_nat_ipv4等与nftables功能相关的模块名字。
nft_compat:提供了对旧iptables/xtables规则的兼容性支持。
nft_tproxy、nf_tproxy_ipv4、nf_tproxy_ipv6:用于透明代理功能的支持,允许nftables重定向流量到本地的代理服务器。
nft_fib_inet、nft_fib_ipv4、nft_fib_ipv6:用于实现基于FIB(Forwarding Information Base)的路由决策。
nft_fib:提供了FIB查找功能。
nft_reject_ipv4、nft_reject:用于生成拒绝流量的规则,例如ICMP回应。
nf_reject_ipv4:为IPv4提供拒绝流量的能力。
nft_ct:允许使用连接跟踪信息进行规则匹配。
nft_masq:提供了NAT的MASQUERADE(伪装)功能,常用于共享上网。
nft_chain_nat:用于定义NAT规则的链。
nf_tables:nftables的核心模块,提供了框架和基础功能。
nfnetlink:为nftables提供了与用户空间通信的能力。
nf_nat:提供了网络地址转换的核心功能。
nf_conntrack:提供了连接跟踪的核心功能,是实现NAT和防火墙规则的基础。
nf_defrag_ipv6、nf_defrag_ipv4:处理IPv4和IPv6数据包碎片重组的功能。
x_tables:提供了iptables使用的基础架构,nft_compat模块通过它提供对旧iptables规则的兼容性支持。
测试以下命令,如果可以达成,则加入开机自动执行。
'''shell
ip rule add fwmark 1 table 100
ip route add local 0.0.0.0/0 dev lo table 100
nft add table v2ray
nft add chain v2ray prerouting { type filter hook prerouting priority 0 ; }
nft add rule v2ray prerouting ip daddr {127.0.0.1/32, 224.0.0.0/4, 255.255.255.255/32} return
nft add rule v2ray prerouting meta l4proto tcp ip daddr 192.168.0.0/16 return
nft add rule v2ray prerouting ip daddr 192.168.0.0/16 udp dport != 53 return
nft add rule v2ray prerouting mark 0xff return # 直连 0xff 流量
nft add rule v2ray prerouting meta l4proto {tcp, udp} mark set 1 tproxy to 127.0.0.1:12345 accept # 转发至 V2Ray 12345 端口
nft add chain v2ray output { type route hook output priority 0 ; }
nft add rule v2ray output ip daddr {127.0.0.1/32, 224.0.0.0/4, 255.255.255.255/32} return
nft add rule v2ray output meta l4proto tcp ip daddr 192.168.0.0/16 return
nft add rule v2ray output ip daddr 192.168.0.0/16 udp dport != 53 return
nft add rule v2ray output mark 0xff return # 直连 0xff 流量
nft add rule v2ray output meta l4proto {tcp, udp} mark set 1 accept # 重路由至 prerouting
#DIVERT 规则
nft add table filter
nft add chain filter divert { type filter hook prerouting priority -150 ; }
nft add rule filter divert meta l4proto tcp socket transparent 1 meta mark set 1 accept
'''
这组命令配置了策略路由、代理局域网设备以及代理网关本机的网络流量,并使用nftables设置了DIVERT规则。这里分步骤解释每个命令的作用:
设置策略路由
-
ip rule add fwmark 1 table 100
:- 这条命令添加一条策略路由规则,指定所有标记为1(
fwmark 1
)的数据包使用路由表100。
- 这条命令添加一条策略路由规则,指定所有标记为1(
-
ip route add local 0.0.0.0/0 dev lo table 100
:- 将所有目标地址为0.0.0.0/0(即任意地址)的数据包路由到本地回环接口(
dev lo
),并指定这条路由规则在表100中。这通常用于TProxy(透明代理)配置,使得标记的流量可以被本地捕获和处理。
- 将所有目标地址为0.0.0.0/0(即任意地址)的数据包路由到本地回环接口(
代理局域网设备
以下命令创建一个名为v2ray
的nftables表,并在其中设置规则以处理局域网设备的流量:
-
nft add table v2ray
:- 创建一个新的nftables表
v2ray
。
- 创建一个新的nftables表
-
nft add chain v2ray prerouting { type filter hook prerouting priority 0 \; }
:- 在
v2ray
表中添加一个名为prerouting
的链,这个链在预路由阶段被触发,用于处理进入的流量。
- 在
-
nft add rule v2ray prerouting ip daddr {...} return
:- 添加几条规则,指定某些目的地址的流量直接返回,不经过代理。这包括本地回环地址、多播地址和广播地址,以及局域网地址(192.168.0.0/16)和非DNS(端口53)UDP流量。
-
nft add rule v2ray prerouting mark 0xff return
:- 对于已经标记为
0xff
的流量(通常表示直连流量),直接返回,不做处理。
- 对于已经标记为
-
nft add rule v2ray prerouting meta l4proto {tcp, udp} mark set 1 tproxy to 127.0.0.1:12345 accept
:- 对于TCP和UDP流量,设置标记为1,并通过TProxy转发到本地的12345端口(假设这是V2Ray等代理软件监听的端口)。
代理网关本机
以下命令设置规则以处理网关本机的流量:
-
nft add chain v2ray output { type route hook output priority 0 \; }
:- 在
v2ray
表中添加一个名为output
的链,这个链在输出阶段被触发,用于处理从本机发出的流量。
- 在
-
nft add rule v2ray output ...
:- 类似于
prerouting
链的规则,这里设置了一系列规则来处理输出流量。特别是,将TCP和UDP流量的标记设置为1,允许它们通过prerouting
链重新路由。
- 类似于
DIVERT 规则
-
nft add table filter
:- 创建一个新的nftables表
filter
。
- 创建一个新的nftables表
-
nft add chain filter divert { type filter hook prerouting priority -150 \; }
:- 在
filter
表中添加一个名为divert
的链,这个链在预路由阶段被触发,优先级为-150,用于处理特定的转发逻辑。
- 在
-
nft add rule filter divert meta l4proto tcp socket transparent 1 meta mark set 1 accept
:- 对于TCP流量,如果是透明套接字的一部分,则设置标记为1并接受。这条规则用于DIVERT链,配合TProxy使用,允许透明地拦截和重定向TCP流量。
开机自动运行透明代理规则
由于策略路由以及 iptables/nftables 有重启会失效的特性,所以当测试配置没有问题之后,需要再弄个服务在开机时自动配置策略路由和 iptables,否则每次开机的时候就要手动执行一遍。
1、由于 iptables 命令有点多,所以先将 iptables 规则保存到 /etc/iptables/rules.v4 中:
mkdir -p /etc/nftables && nft list ruleset > /etc/nftables/rules.v4
2、在 /etc/systemd/system/ 目录下创建一个名为 tproxyrule.service 的文件,然后添加以下内容并保存。
'''shell
[Unit]
Description=Tproxy rule
After=network.target
Wants=network.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/sbin/ip rule add fwmark 1 table 100 ; /sbin/ip route add local 0.0.0.0/0 dev lo table 100 ; /sbin/nft -f /etc/nftables/rules.v4
ExecStop=/sbin/ip rule del fwmark 1 table 100 ; /sbin/ip route del local 0.0.0.0/0 dev lo table 100 ; /sbin/nft flush ruleset
[Install]
WantedBy=multi-user.target
'''
3、最后执行 systemctl enable tproxyrule
如果使用V2raya
已经自动帮忙配好透明代理上网
执行 nft list ruleset ,得到:
'''config
table inet v2raya {
set whitelist {
type ipv4_addr
flags interval
auto-merge
elements = { 0.0.0.0, 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, 192.0.2.0/24,
192.88.99.0/24, 192.168.0.0/16,
198.51.100.0/24, 203.0.113.0/24,
224.0.0.0/3 }
}
set whitelist6 {
type ipv6_addr
flags interval
auto-merge
elements = { ::/127,
64:ff9b::/96,
100::/64,
2001::/32,
2001:20::/28,
fe80::/10,
ff00::/8 }
}
set interface {
type ipv4_addr
flags interval
auto-merge
elements = { 127.0.0.0/8, 172.17.0.0/16,
192.168.0.0/16 }
}
set interface6 {
type ipv6_addr
flags interval
auto-merge
elements = { ::1,
fe80::/64 }
}
chain tp_out {
meta mark & 0x00000080 == 0x00000080 return
meta l4proto { tcp, udp } fib saddr type local fib daddr type != local jump tp_rule
}
chain tp_pre {
iifname "lo" meta mark & 0x000000c0 != 0x00000040 return
meta l4proto { tcp, udp } fib saddr type != local fib daddr type != local jump tp_rule
meta l4proto { tcp, udp } meta mark & 0x000000c0 == 0x00000040 tproxy ip to 127.0.0.1:52345
meta l4proto { tcp, udp } meta mark & 0x000000c0 == 0x00000040 tproxy ip6 to [::1]:52345
}
chain output {
type route hook output priority mangle - 5; policy accept;
meta nfproto { ipv4, ipv6 } jump tp_out
}
chain prerouting {
type filter hook prerouting priority mangle - 5; policy accept;
meta nfproto { ipv4, ipv6 } jump tp_pre
}
chain tp_rule {
meta mark set ct mark
meta mark & 0x000000c0 == 0x00000040 return
iifname "br-" return
iifname "docker" return
iifname "veth*" return
iifname "wg*" return
iifname "ppp*" return
meta l4proto { tcp, udp } th dport 53 jump tp_mark
meta mark & 0x000000c0 == 0x00000040 return
ip daddr @interface return
ip daddr @whitelist return
ip6 daddr @interface6 return
ip6 daddr @whitelist6 return
jump tp_mark
}
chain tp_mark {
tcp flags syn / fin,syn,rst,ack meta mark set meta mark | 0x00000040
meta l4proto udp ct state new meta mark set meta mark | 0x00000040
ct mark set meta mark
}
}
'''
V2RayA 通过 nftables
为你自动设置的规则主要是为了实现透明代理,使得局域网内的设备(包括旁路由自身)可以通过V2RayA代理上网。这些规则包括了对流量的拦截、标记、以及重定向到V2RayA监听的端口(在这里是127.0.0.1:52345
)。下面是对这些规则的简要分析:
设置和集合
- whitelist 和 whitelist6:定义了不需要被代理的IPv4和IPv6地址集合,这通常包括局域网地址、特殊用途地址以及广播和多播地址。
- interface 和 interface6:定义了需要被代理的网络接口的IPv4和IPv6地址集合,主要是局域网和本地接口。
链
- tp_out:处理从本机发出的流量。如果流量已被标记(表示它已被处理或不需处理),则返回;否则,根据源地址和目的地址的类型(本地或非本地)来决定是否跳转到
tp_rule
链处理。 - tp_pre:处理进入的流量。这里主要处理非本地到非本地的流量和已标记流量的重定向。
- output 和 prerouting:分别处理本机发出的和进入的流量,并跳转到相应的处理链(
tp_out
或tp_pre
)。 - tp_rule:具体处理规则,包括返回(不处理)的情况和跳转到
tp_mark
的情况。这里考虑了接口、白名单地址、DNS查询(端口53)等。 - tp_mark:设置流量标记,用于后续的流量控制和重定向。这里对TCP的SYN包和UDP的新连接进行标记。
透明代理的实现
- TProxy:在
tp_pre
链中,对满足条件的TCP和UDP流量使用TProxy
重定向到V2RayA监听的端口。这使得V2RayA可以处理这些流量,实现透明代理。
结论
基于以上规则,你的V2RayA设置已经可以作为旁路由代理上网了。这套规则通过拦截、标记和重定向流量到V2RayA,使得局域网内的设备无需单独配置代理就可以通过V2RayA访问互联网,同时避免了对特定地址和服务的干扰(例如DNS查询和局域网通信)。注意,还需要启动 nftables 服务。
确认以下几点:
确保 nftables 服务正在运行:可以通过 sudo systemctl status nftables 来检查服务状态。
确保内核支持:透明代理(特别是 TProxy 功能)需要内核支持。请确保你的内核配置(通常是 /boot/config-$(uname -r) 文件)包含了对 TProxy 的支持(例如,配置项 CONFIG_NETFILTER_XT_TARGET_TPROXY)。
确保 V2RayA 或其他代理软件正确配置:代理软件需要监听上述 nftables 规则中指定的端口(如 127.0.0.1:52345),并正确配置以处理透明代理的流量。
检查防火墙规则冲突:确保没有其他防火墙规则(无论是 nftables 还是 iptables 的)阻止了代理流量的正确处理。
目前查到的内核配置:CONFIG_NETFILTER_XT_TARGET_TPROXY=m
是被当成TProxy模块了,没有进内核:
如果内核配置项 CONFIG_NETFILTER_XT_TARGET_TPROXY
设置为 m
,这意味着 TProxy(透明代理目标)支持被编译为模块,而不是直接编入内核。这种设置允许你按需加载或卸载 TProxy 功能,而不需要在每次启动时都启用它。
要确保 TProxy 功能正常工作,你需要确保相应的内核模块已经被加载到系统中。你可以使用 modprobe
命令手动加载模块,例如:
sudo modprobe xt_TPROXY
加载模块后,你应该能够使用 nftables
配置的 TProxy 规则进行透明代理。
自动加载模块
如果你希望在系统启动时自动加载 xt_TPROXY
模块,可以将模块名称添加到 /etc/modules
文件中。这样,每次系统启动时,xt_TPROXY
模块就会被自动加载。只需执行以下命令:
echo "xt_TPROXY" | sudo tee -a /etc/modules
验证模块是否加载
加载模块后,你可以使用 lsmod
命令来检查模块是否已经被加载:
lsmod | grep xt_TPROXY
如果输出中显示了 xt_TPROXY
,这意味着模块已成功加载。
总结
在你的设置中,由于 CONFIG_NETFILTER_XT_TARGET_TPROXY
被设置为模块,你需要确保在尝试设置或使用 TProxy 功能之前,相应的模块已被加载到系统中。这是实现旁路由透明代理功能的先决条件之一。