Go与TUN/TAP:基于YAML配置的UDP中继构建
Go开发者可以轻松构建支持TUN接口和UDP隧道的网络中继。该架构通过YAML配置定义入站/出站链路,每个中继节点均能处理双向流量——在TUN与UDP之间来回转发,实现复杂路由而无需硬编码逻辑。
核心实现采用 io.ReadWriteCloser 接口统一所有节点。逻辑清晰明了:从入站读取数据包,转发至出站,并处理反向流量。
YAML配置结构
配置文件以数组形式定义多个入站/出站对。参数涵盖接口类型、IP地址分配、NAT规则及认证机制。
示例:TUN到TUN中继
relays:
- ingress:
type: tun
name: tun10
cidr: "10.0.0.2/24"
peer: "10.0.0.1"
egress:
type: tun
name: tun11
cidr: "10.0.1.2/24"
peer: "10.0.1.1"
nat:
forward:
src: "10.0.1.1"
backward:
dst: "10.0.0.2"
若需构建UDP中继,只需添加客户端与服务端端点:
relays:
- ingress:
type: tun
name: tun10
cidr: "10.0.0.2/24"
peer: "10.0.0.1"
egress:
type: udp
dial: "localhost:4000"
password: "pass"
- ingress:
type: udp
listen: "localhost:4000"
password: "pass"
egress:
type: tun
name: tun11
cidr: "10.0.1.2/24"
peer: "10.0.1.1"
nat:
forward:
src: "10.0.1.1"
backward:
dst: "10.0.0.2"
此配置形成完整链路:tun10 → UDP客户端 → UDP服务器 → tun11,所有通信均在本地完成。
UDP隧道协议
每个IP数据包附加一个头部:4字节时间戳(uint32大端序)+ 16字节MD5哈希值。哈希由密码 + 时间戳 + 数据包前64字节计算得出。
接收端进行三项校验:
- 数据包长度 ≥ 20字节(头部大小)
- 时间戳与当前时间相差不超过10秒
- 哈希值匹配
解包代码如下:
func (i *Ingress) Read(b []byte) (int, error) {
n, raddr, err := i.conn.ReadFrom(b)
if err != nil {
return 0, err
}
data, err := unpack(b[:n:n], i.pass)
if err != nil {
return 0, err
}
i.raddr = raddr
copy(b, data)
return len(data), nil
}
func unpack(packet []byte, pass string) ([]byte, error) {
if len(packet) < HeaderSize {
return nil, ErrSmallPacket
}
rtimestamp := binary.BigEndian.Uint32(packet[0:4])
rhash := [HashSize]byte(packet[4 : 4+HashSize])
payload := packet[HeaderSize:]
timestamp := uint32(time.Now().Unix())
if timestamp-rtimestamp > MaxTimeDiff && rtimestamp-timestamp > MaxTimeDiff {
return nil, ErrStalePacket
}
hash, err := calcHash(pass, payload, rtimestamp)
if err != nil {
return nil, fmt.Errorf("calc hash: %w", err)
}
if rhash != hash {
return nil, ErrWrongPass
}
return payload, nil
}
打包过程对称:计算哈希值后,按大端序写入并发送。
性能测试
使用 iperf3 在 tun10 与 tun11 间进行本地测试:
服务端:
iperf3 -s -B 10.0.1.2
客户端:
iperf3 -c 10.0.1.2 -B 10.0.0.2
测试结果(持续10秒):
| 区间 | 传输量 | 吞吐率 |
|----------|----------|---------|
| 0-1s | 113 MB | 941 Mbit/s |
| 1-2s | 109 MB | 921 Mbit/s |
| ... | ... | ... |
| 总计 | 1.08 GB | 925 Mbit/s(发送端) |
接收端实测约 922 Mbit/s。CPU占用情况:中继进程约250%(M1芯片),iperf3为10–30%。可通过批量处理、零拷贝或SIMD哈希进一步优化性能。
关键指标分析:
- 吞吐量:平均达925 Mbit/s
- CPU负载:单线程占用高,存在瓶颈
- 延迟:10秒时间窗口,适用于本地测试场景
- 可靠性:结合时间戳与哈希,有效防止重放攻击与数据注入
核心要点
- YAML配置:无需重新编译即可灵活混合TUN与UDP接口
- 协议极简:仅增加20字节开销,依赖MD5与时间戳保障安全
- 性能表现:本地可达900+ Mbit/s,但受限于CPU性能
- 扩展性强:基于
io.ReadWriteCloser接口,可轻松集成WireGuard、QUIC等协议 - NAT规则内嵌:配置中直接定义,简化点对点连接部署流程
— Editorial Team
暂无评论。