mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-06-13 21:54:13 +08:00
Introduce UDP Tracker Protocol sniffer
Signed-off-by: iosmanthus <myosmanthustree@gmail.com>
This commit is contained in:
parent
f97687e85f
commit
99601b49dd
@ -11,6 +11,18 @@ import (
|
|||||||
"github.com/sagernet/sing-box/constant"
|
"github.com/sagernet/sing-box/constant"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
trackerConnectFlag = iota
|
||||||
|
trackerAnnounceFlag
|
||||||
|
trackerScrapeFlag
|
||||||
|
|
||||||
|
trackerProtocolID = 0x41727101980
|
||||||
|
|
||||||
|
trackerConnectMinSize = 16
|
||||||
|
trackerAnnounceMinSize = 20
|
||||||
|
trackerScrapeMinSize = 8
|
||||||
|
)
|
||||||
|
|
||||||
// BitTorrent detects if the stream is a BitTorrent connection.
|
// BitTorrent detects if the stream is a BitTorrent connection.
|
||||||
// For the BitTorrent protocol specification, see https://www.bittorrent.org/beps/bep_0003.html
|
// For the BitTorrent protocol specification, see https://www.bittorrent.org/beps/bep_0003.html
|
||||||
func BitTorrent(_ context.Context, reader io.Reader) (*adapter.InboundContext, error) {
|
func BitTorrent(_ context.Context, reader io.Reader) (*adapter.InboundContext, error) {
|
||||||
@ -78,3 +90,24 @@ func UTP(_ context.Context, packet []byte) (*adapter.InboundContext, error) {
|
|||||||
Protocol: constant.ProtocolUTP,
|
Protocol: constant.ProtocolUTP,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UDPTracker detects if the packet is a UDP Tracker Protocol packet.
|
||||||
|
// For the UDP Tracker Protocol specification, see https://www.bittorrent.org/beps/bep_0015.html
|
||||||
|
func UDPTracker(_ context.Context, packet []byte) (*adapter.InboundContext, error) {
|
||||||
|
switch {
|
||||||
|
case len(packet) >= trackerConnectMinSize &&
|
||||||
|
binary.BigEndian.Uint64(packet[:8]) == trackerProtocolID &&
|
||||||
|
binary.BigEndian.Uint32(packet[8:12]) == trackerConnectFlag:
|
||||||
|
fallthrough
|
||||||
|
case len(packet) >= trackerAnnounceMinSize &&
|
||||||
|
binary.BigEndian.Uint32(packet[8:12]) == trackerAnnounceFlag:
|
||||||
|
fallthrough
|
||||||
|
case len(packet) >= trackerScrapeMinSize &&
|
||||||
|
binary.BigEndian.Uint32(packet[8:12]) == trackerScrapeFlag:
|
||||||
|
return &adapter.InboundContext{
|
||||||
|
Protocol: constant.ProtocolUDPTracker,
|
||||||
|
}, nil
|
||||||
|
default:
|
||||||
|
return nil, os.ErrInvalid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -49,3 +49,33 @@ func TestSniffUTP(t *testing.T) {
|
|||||||
require.Equal(t, constant.ProtocolUTP, metadata.Protocol)
|
require.Equal(t, constant.ProtocolUTP, metadata.Protocol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSniffUDPTracker(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
connectPackets := []string{
|
||||||
|
// connect packets
|
||||||
|
"00000417271019800000000078e90560",
|
||||||
|
"00000417271019800000000022c5d64d",
|
||||||
|
"000004172710198000000000b3863541",
|
||||||
|
|
||||||
|
// announce packets
|
||||||
|
"3d7592ead4b8c9e300000001b871a3820000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002092f616e6e6f756e6365",
|
||||||
|
"3d7592ead4b8c9e30000000188deed1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002092f616e6e6f756e6365",
|
||||||
|
"3d7592ead4b8c9e300000001ceb948ad0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a3362cdb7020ff920e5aa642c3d4066950dd1f01f4d00000000000000000000000000000000000000000000000000000000000000000000000000000000000002092f616e6e6f756e6365",
|
||||||
|
|
||||||
|
// scrape packets
|
||||||
|
"3d7592ead4b8c9e300000002d2f4bba5a94a8fe5ccb19ba61c4c0873d391e987982fbbd3",
|
||||||
|
"3d7592ead4b8c9e300000002441243292aae6c35c94fcfb415dbe95f408b9ce91ee846ed",
|
||||||
|
"3d7592ead4b8c9e300000002b2aa461b1ad1fa9661cf3fe45fb2504ad52ec6c67758e294",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pkt := range connectPackets {
|
||||||
|
pkt, err := hex.DecodeString(pkt)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
metadata, err := sniff.UDPTracker(context.TODO(), pkt)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, constant.ProtocolUDPTracker, metadata.Protocol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -8,4 +8,5 @@ const (
|
|||||||
ProtocolSTUN = "stun"
|
ProtocolSTUN = "stun"
|
||||||
ProtocolBitTorrent = "bittorrent"
|
ProtocolBitTorrent = "bittorrent"
|
||||||
ProtocolUTP = "utp"
|
ProtocolUTP = "utp"
|
||||||
|
ProtocolUDPTracker = "udp-tracker"
|
||||||
)
|
)
|
||||||
|
@ -924,6 +924,7 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
|
|||||||
sniff.QUICClientHello,
|
sniff.QUICClientHello,
|
||||||
sniff.STUNMessage,
|
sniff.STUNMessage,
|
||||||
sniff.UTP,
|
sniff.UTP,
|
||||||
|
sniff.UDPTracker,
|
||||||
)
|
)
|
||||||
if sniffMetadata != nil {
|
if sniffMetadata != nil {
|
||||||
metadata.Protocol = sniffMetadata.Protocol
|
metadata.Protocol = sniffMetadata.Protocol
|
||||||
|
Loading…
x
Reference in New Issue
Block a user