组网架构

在内网穿透、远程办公等场景中,我们经常需要将外部客户端的TCP请求转发到内网服务。
entry.py可以连接上target ip。我使用大模型,实现基于TUN设备的TCP流量转发系统。
客户端运行usera.go程序,通过tun设备读取目的地为target_ip的tcp流量,使用UDP将数据转发到linux server。
inux server 中的 proxy sock会监听在一个非本地的ip:port (10.0.0.1:5560)。linux server收到数据包之后,写入tun设备,内核路由到 Fake Proxy (10.0.0.1:5560)。linux server 与 entry 建立tcp链接,中转应用层payload数据。从未实现usera.go的主机也可以连接到target ip的主机。
usera.go
UserAgent 是一个运行在Windows上的轻量级程序,其核心功能是TUN设备与UDP隧道之间的双向数据转发。
关键设计原则:无状态
- 不解析IP/TCP包头
- 不维护任何连接状态
- 纯粹的字节流转发
数据流向
TUN设备 → 读取IP包 → UDP发送 → LinuxServer
LinuxServer → UDP接收 → 写入TUN设备
代码片段:
go
// TUN → UDP 转发
func tunToUDP(udpConn *net.UDPConn) {
for running {
pkt := session.ReceivePacket() // 从TUN读取
udpConn.Write(pkt) // 直接UDP发送
}
}
// UDP → TUN 转发
func udpToTUN(udpConn *net.UDPConn) {
for running {
n := udpConn.Read(buf) // UDP接收
session.SendPacket(buf[:n]) // 直接写入TUN
}
}
可以在config.json配置ip_whitelist。系统会为每个白名单条目添加静态路由,将流量导向TUN设备。
json
{
"ip_whitelist": [
"192.168.1.10",
"10.0.0.5",
"203.0.113.0/24",
"8.8.8.8"
]
}
config.json需要配置linux_server.py的服务ip和port.
text
"server": {
"ip": "x.x.x.x",
"udp_port": 9999
},
linux_server.py
linux_server.py运行在公网服务器。收到的udp数据,linux server 写入了tun设备。LinuxServer的proxy截获了应用层数据(TCP payload),然后通过EntryProxy转发。
路由表配置
linux server 上的路由表配置。linux_server.py的代码已经包含。
text
# 1. TUN设备配置
ip addr add 10.255.255.1/24 dev tun0
ip link set tun0 up
# 2. 添加目标IP到本地
ip addr add 10.0.0.1/32 dev lo
ip route add 10.0.0.1/32 dev lo
# 3. iptables规则
# 标记来自fake_proxy的包
iptables -t mangle -A OUTPUT -p tcp --sport 5560 -j MARK --set-mark 1
# REDIRECT规则
iptables -t nat -A PREROUTING -d 10.0.0.1 -p tcp --dport 5560 -j REDIRECT --to-port 5560
# 4. 策略路由
ip rule add fwmark 1 lookup mytable priority 100
ip route add default dev tun0 table mytable
数据包处理流程
场景:客户端访问 target_ip:target_port
text
客户端应用 → target_ip:target_port
│
▼
[路由表] → 指向TUN设备 (10.10.0.2)
│
▼
UserAgent读取IP包 → 通过UDP发送到linux server (server_ip:9999)
│
▼
LinuxServer接收UDP → 解析IP包 → 分配fake端口
│
▼
重写IP包: 目标变为 10.0.0.1:5560 → 写入TUN设备
│
▼
内核处理 → 连接到达 10.0.0.1:5560 (Proxy监听)
│
▼
LinuxServer接收连接 → 分配flow_id → 通知EntryProxy
│
▼
EntryProxy连接目标服务器 → 开始双向数据转发
修改IP和端口后,必须重新计算校验和。
python
def rewrite_ip_packet(ip_packet, new_src_ip, new_src_port, new_dst_ip, new_dst_port):
# 1. 修改IP头中的源/目标地址
# 2. 修改TCP头中的源/目标端口
# 3. 重新计算IP头校验和
# 4. 重新计算TCP校验和(包含伪头部)
测试
服务拉起
linux_server.py, 服务ip 为 x.x.x.x
shell
python3 linux_server.py --log_level DEBUG
第一种模式:
shell
python3 entry.py --log_level DEBUG --server_ip x.x.x.x
第二种模式:
使用echo_server.py 模拟target ip的主机。entry.py 和 echo_server.py 使用同一台主机。
shell
python3 entry.py --log_level DEBUG --echo_server_port 3456 --server_ip x.x.x.x
拉起echo server
shell
python3 echo_server.py
客户端运行
管理者模式打开powershell。
shell
./usea.exe
测试echo_client.py
shell
python echo_client.py --log_level DEBUG --server_ip 203.0.113.8
Reference