Browse Source

Add stun sniffer

世界 3 years ago
parent
commit
fe5618c35d
4 changed files with 54 additions and 1 deletions
  1. 24 0
      common/sniff/stun.go
  2. 28 0
      common/sniff/stun_test.go
  3. 1 0
      constant/protocol.go
  4. 1 1
      route/router.go

+ 24 - 0
common/sniff/stun.go

@@ -0,0 +1,24 @@
+package sniff
+
+import (
+	"context"
+	"encoding/binary"
+	"os"
+
+	"github.com/sagernet/sing-box/adapter"
+	C "github.com/sagernet/sing-box/constant"
+)
+
+func STUNMessage(ctx context.Context, packet []byte) (*adapter.InboundContext, error) {
+	pLen := len(packet)
+	if pLen < 20 {
+		return nil, os.ErrInvalid
+	}
+	if binary.BigEndian.Uint32(packet[4:8]) != 0x2112A442 {
+		return nil, os.ErrInvalid
+	}
+	if len(packet) < 20+int(binary.BigEndian.Uint16(packet[2:4])) {
+		return nil, os.ErrInvalid
+	}
+	return &adapter.InboundContext{Protocol: C.ProtocolSTUN}, nil
+}

+ 28 - 0
common/sniff/stun_test.go

@@ -0,0 +1,28 @@
+package sniff_test
+
+import (
+	"context"
+	"encoding/hex"
+	"testing"
+
+	"github.com/sagernet/sing-box/common/sniff"
+	C "github.com/sagernet/sing-box/constant"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestSniffSTUN(t *testing.T) {
+	packet, err := hex.DecodeString("000100002112a44224b1a025d0c180c484341306")
+	require.NoError(t, err)
+	metadata, err := sniff.STUNMessage(context.Background(), packet)
+	require.NoError(t, err)
+	require.Equal(t, metadata.Protocol, C.ProtocolSTUN)
+}
+
+func FuzzSniffSTUN(f *testing.F) {
+	f.Fuzz(func(t *testing.T, data []byte) {
+		if _, err := sniff.STUNMessage(context.Background(), data); err == nil {
+			t.Fail()
+		}
+	})
+}

+ 1 - 0
constant/protocol.go

@@ -5,4 +5,5 @@ const (
 	ProtocolHTTP = "http"
 	ProtocolQUIC = "quic"
 	ProtocolDNS  = "dns"
+	ProtocolSTUN = "stun"
 )

+ 1 - 1
route/router.go

@@ -457,7 +457,7 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
 		if err != nil {
 			return err
 		}
-		sniffMetadata, err := sniff.PeekPacket(ctx, buffer.Bytes(), sniff.QUICClientHello)
+		sniffMetadata, err := sniff.PeekPacket(ctx, buffer.Bytes(), sniff.QUICClientHello, sniff.STUNMessage)
 		originDestination := metadata.Destination
 		if err == nil {
 			metadata.Protocol = sniffMetadata.Protocol