UDP-over-TCP(UoT)
源码:common/uot/router.go
概述
UoT(UDP-over-TCP)通过 TCP 连接隧道传输 UDP 流量。它拦截目标为魔术哨兵地址的连接,并使用 github.com/sagernet/sing/common/uot 将其转换为基于数据包的连接。
魔术地址
两个哨兵地址用于标识 UoT 连接:
uot.MagicAddress—— 当前 UoT 协议,带请求头uot.LegacyMagicAddress—— 旧版 UoT,无请求头
Router
Router 包装现有的 ConnectionRouterEx,按目标 FQDN 拦截连接:
go
type Router struct {
router adapter.ConnectionRouterEx
logger logger.ContextLogger
}
func NewRouter(router adapter.ConnectionRouterEx, logger logger.ContextLogger) *Router {
return &Router{router, logger}
}连接处理(Ex 变体)
go
func (r *Router) RouteConnectionEx(ctx context.Context, conn net.Conn,
metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
switch metadata.Destination.Fqdn {
case uot.MagicAddress:
request, err := uot.ReadRequest(conn)
if err != nil {
N.CloseOnHandshakeFailure(conn, onClose, err)
return
}
if request.IsConnect {
r.logger.InfoContext(ctx, "inbound UoT connect connection to ", request.Destination)
} else {
r.logger.InfoContext(ctx, "inbound UoT connection to ", request.Destination)
}
metadata.Domain = metadata.Destination.Fqdn
metadata.Destination = request.Destination
r.router.RoutePacketConnectionEx(ctx, uot.NewConn(conn, *request), metadata, onClose)
return
case uot.LegacyMagicAddress:
r.logger.InfoContext(ctx, "inbound legacy UoT connection")
metadata.Domain = metadata.Destination.Fqdn
metadata.Destination = M.Socksaddr{Addr: netip.IPv4Unspecified()}
r.RoutePacketConnectionEx(ctx, uot.NewConn(conn, uot.Request{}), metadata, onClose)
return
}
r.router.RouteConnectionEx(ctx, conn, metadata, onClose)
}UoT 请求头
对于当前协议(uot.MagicAddress),从连接中读取请求头:
- Destination:实际的 UDP 目标地址
- IsConnect:布尔标志,指示 connect 模式还是普通模式
在 connect 模式下,连接表现为到单一目标的已连接 UDP 套接字。在普通模式下,每个数据包携带自己的目标地址。
旧版协议
旧版协议(uot.LegacyMagicAddress)没有请求头。目标设置为 0.0.0.0(IPv4 未指定),使用空的 Request{}。
透传
不匹配任何魔术地址的连接直接透传到底层路由器:
go
r.router.RouteConnectionEx(ctx, conn, metadata, onClose)数据包连接转换
uot.NewConn(conn, request) 将 TCP 连接包装为 N.PacketConn。UoT 协议在 TCP 流中对单个 UDP 数据包进行帧处理,包括:
- 数据包长度帧
- 每数据包目标寻址(非 connect 模式)
- 双向数据包流
生成的数据包连接随后通过 RoutePacketConnectionEx 路由,进行标准 UDP 处理。