diff --git a/app/dispatcher/sniffer.go b/app/dispatcher/sniffer.go index 8fe61049a..72ba883cc 100644 --- a/app/dispatcher/sniffer.go +++ b/app/dispatcher/sniffer.go @@ -37,7 +37,8 @@ func NewSniffer(ctx context.Context) *Sniffer { {func(c context.Context, b []byte) (SniffResult, error) { return http.SniffHTTP(b) }, false, net.Network_TCP}, {func(c context.Context, b []byte) (SniffResult, error) { return tls.SniffTLS(b) }, false, net.Network_TCP}, {func(c context.Context, b []byte) (SniffResult, error) { return quic.SniffQUIC(b) }, false, net.Network_UDP}, - {func(c context.Context, b []byte) (SniffResult, error) { return bittorrent.SniffBittorrent(b) }, false, net.Network_UDP}, + {func(c context.Context, b []byte) (SniffResult, error) { return bittorrent.SniffBittorrent(b) }, false, net.Network_TCP}, + {func(c context.Context, b []byte) (SniffResult, error) { return bittorrent.SniffUTP(b) }, false, net.Network_UDP}, }, } if sniffer, err := newFakeDNSSniffer(ctx); err == nil { diff --git a/common/protocol/bittorrent/bittorrent.go b/common/protocol/bittorrent/bittorrent.go index 248c10f67..b3c8e4ed4 100644 --- a/common/protocol/bittorrent/bittorrent.go +++ b/common/protocol/bittorrent/bittorrent.go @@ -1,7 +1,12 @@ package bittorrent import ( + "encoding/binary" "errors" + "math" + "time" + + "github.com/v2fly/v2ray-core/v4/common/buf" "github.com/v2fly/v2ray-core/v4/common" ) @@ -29,3 +34,58 @@ func SniffBittorrent(b []byte) (*SniffHeader, error) { return nil, errNotBittorrent } + +func SniffUTP(b []byte) (*SniffHeader, error) { + if len(b) < 20 { + return nil, common.ErrNoClue + } + + buffer := buf.As(b) + + var typeAndVersion uint8 + + if binary.Read(buffer, binary.BigEndian, &typeAndVersion) != nil { + return nil, common.ErrNoClue + } else if b[0]>>4&0xF > 4 || b[0]&0xF != 1 { + return nil, errNotBittorrent + } + + var extension uint8 + + if binary.Read(buffer, binary.BigEndian, &extension) != nil { + return nil, common.ErrNoClue + } else if extension != 0 && extension != 1 { + return nil, errNotBittorrent + } + + for extension != 0 { + if extension != 1 { + return nil, errNotBittorrent + } + if binary.Read(buffer, binary.BigEndian, &extension) != nil { + return nil, common.ErrNoClue + } + + var length uint8 + if err := binary.Read(buffer, binary.BigEndian, &length); err != nil { + return nil, common.ErrNoClue + } + if common.Error2(buffer.ReadBytes(int32(length))) != nil { + return nil, common.ErrNoClue + } + } + + if common.Error2(buffer.ReadBytes(2)) != nil { + return nil, common.ErrNoClue + } + + var timestamp uint32 + if err := binary.Read(buffer, binary.BigEndian, ×tamp); err != nil { + return nil, common.ErrNoClue + } + if math.Abs(float64(time.Now().UnixMicro()-int64(timestamp))) > float64(24*time.Hour) { + return nil, errNotBittorrent + } + + return &SniffHeader{}, nil +}