Fix UDP conn stuck on sniff

This change only avoids permanent hangs. We need to implement read deadlines for UDP conns in 1.10 for server inbounds.
This commit is contained in:
世界 2024-08-18 11:27:12 +08:00
parent 7fec8d842e
commit 21b1ac26b9
No known key found for this signature in database
GPG key ID: CD109927C34A63C4

View file

@ -951,34 +951,57 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
}*/ }*/
if metadata.InboundOptions.SniffEnabled || metadata.Destination.Addr.IsUnspecified() { if metadata.InboundOptions.SniffEnabled || metadata.Destination.Addr.IsUnspecified() {
buffer := buf.NewPacket() var (
destination, err := conn.ReadPacket(buffer) buffer = buf.NewPacket()
destination M.Socksaddr
done = make(chan struct{})
err error
)
go func() {
sniffTimeout := C.ReadPayloadTimeout
if metadata.InboundOptions.SniffTimeout > 0 {
sniffTimeout = time.Duration(metadata.InboundOptions.SniffTimeout)
}
conn.SetReadDeadline(time.Now().Add(sniffTimeout))
destination, err = conn.ReadPacket(buffer)
conn.SetReadDeadline(time.Time{})
close(done)
}()
select {
case <-done:
case <-ctx.Done():
conn.Close()
return ctx.Err()
}
if err != nil { if err != nil {
buffer.Release() buffer.Release()
return err if !errors.Is(err, os.ErrDeadlineExceeded) {
} return err
if metadata.Destination.Addr.IsUnspecified() { }
metadata.Destination = destination } else {
} if metadata.Destination.Addr.IsUnspecified() {
if metadata.InboundOptions.SniffEnabled { metadata.Destination = destination
sniffMetadata, _ := sniff.PeekPacket(ctx, buffer.Bytes(), sniff.DomainNameQuery, sniff.QUICClientHello, sniff.STUNMessage) }
if sniffMetadata != nil { if metadata.InboundOptions.SniffEnabled {
metadata.Protocol = sniffMetadata.Protocol sniffMetadata, _ := sniff.PeekPacket(ctx, buffer.Bytes(), sniff.DomainNameQuery, sniff.QUICClientHello, sniff.STUNMessage)
metadata.Domain = sniffMetadata.Domain if sniffMetadata != nil {
if metadata.InboundOptions.SniffOverrideDestination && M.IsDomainName(metadata.Domain) { metadata.Protocol = sniffMetadata.Protocol
metadata.Destination = M.Socksaddr{ metadata.Domain = sniffMetadata.Domain
Fqdn: metadata.Domain, if metadata.InboundOptions.SniffOverrideDestination && M.IsDomainName(metadata.Domain) {
Port: metadata.Destination.Port, metadata.Destination = M.Socksaddr{
Fqdn: metadata.Domain,
Port: metadata.Destination.Port,
}
}
if metadata.Domain != "" {
r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", domain: ", metadata.Domain)
} else {
r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol)
} }
} }
if metadata.Domain != "" {
r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", domain: ", metadata.Domain)
} else {
r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol)
}
} }
conn = bufio.NewCachedPacketConn(conn, buffer, destination)
} }
conn = bufio.NewCachedPacketConn(conn, buffer, destination)
} }
if r.dnsReverseMapping != nil && metadata.Domain == "" { if r.dnsReverseMapping != nil && metadata.Domain == "" {
domain, loaded := r.dnsReverseMapping.Query(metadata.Destination.Addr) domain, loaded := r.dnsReverseMapping.Query(metadata.Destination.Addr)