Răsfoiți Sursa

Fix vision read

世界 2 ani în urmă
părinte
comite
5b3b74bd0f
8 a modificat fișierele cu 224 adăugiri și 23 ștergeri
  1. 1 1
      go.mod
  2. 2 2
      go.sum
  3. 51 0
      test/config/vless-tls-client.json
  4. 2 2
      test/go.mod
  5. 4 4
      test/go.sum
  6. 1 0
      test/shadowsocks_test.go
  7. 140 4
      test/vless_test.go
  8. 23 10
      transport/vless/vision.go

+ 1 - 1
go.mod

@@ -26,7 +26,7 @@ require (
 	github.com/sagernet/gomobile v0.0.0-20221130124640-349ebaa752ca
 	github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32
 	github.com/sagernet/reality v0.0.0-20230228045158-d3e085a8e5d1
-	github.com/sagernet/sing v0.1.8-0.20230303052048-c875a4ffab1a
+	github.com/sagernet/sing v0.1.8-0.20230305055148-e16845727f76
 	github.com/sagernet/sing-dns v0.1.4
 	github.com/sagernet/sing-shadowsocks v0.1.2-0.20230221080503-769c01d6bba9
 	github.com/sagernet/sing-shadowtls v0.1.0

+ 2 - 2
go.sum

@@ -133,8 +133,8 @@ github.com/sagernet/reality v0.0.0-20230228045158-d3e085a8e5d1 h1:8mSzchN6DkM26J
 github.com/sagernet/reality v0.0.0-20230228045158-d3e085a8e5d1/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
 github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
 github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
-github.com/sagernet/sing v0.1.8-0.20230303052048-c875a4ffab1a h1:NvhI/8DMFt2yV3eoYhw6P/XyWzzIKkMiGvFglJbWHWg=
-github.com/sagernet/sing v0.1.8-0.20230303052048-c875a4ffab1a/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
+github.com/sagernet/sing v0.1.8-0.20230305055148-e16845727f76 h1:JCZ4tpEuT6U6oC87EaDBMsPg7+NxesIwESs4dzAGgJo=
+github.com/sagernet/sing v0.1.8-0.20230305055148-e16845727f76/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
 github.com/sagernet/sing-dns v0.1.4 h1:7VxgeoSCiiazDSaXXQVcvrTBxFpOePPq/4XdgnUDN+0=
 github.com/sagernet/sing-dns v0.1.4/go.mod h1:1+6pCa48B1AI78lD+/i/dLgpw4MwfnsSpZo0Ds8wzzk=
 github.com/sagernet/sing-shadowsocks v0.1.2-0.20230221080503-769c01d6bba9 h1:qS39eA4C7x+zhEkySbASrtmb6ebdy5v0y2M6mgkmSO0=

+ 51 - 0
test/config/vless-tls-client.json

@@ -0,0 +1,51 @@
+{
+  "log": {
+    "loglevel": "debug"
+  },
+  "inbounds": [
+    {
+      "listen": "0.0.0.0",
+      "port": "1080",
+      "protocol": "socks",
+      "settings": {
+        "auth": "noauth",
+        "udp": true,
+        "ip": "127.0.0.1"
+      }
+    }
+  ],
+  "outbounds": [
+    {
+      "protocol": "vless",
+      "settings": {
+        "vnext": [
+          {
+            "address": "host.docker.internal",
+            "port": 1234,
+            "users": [
+              {
+                "id": "",
+                "encryption": "none",
+                "flow": ""
+              }
+            ]
+          }
+        ]
+      },
+      "streamSettings": {
+        "network": "tcp",
+        "security": "tls",
+        "tlsSettings": {
+          "serverName": "example.org",
+          "certificates": [
+            {
+              "certificateFile": "/path/to/certificate.crt",
+              "keyFile": "/path/to/private.key"
+            }
+          ],
+          "fingerprint": "chrome"
+        }
+      }
+    }
+  ]
+}

+ 2 - 2
test/go.mod

@@ -10,7 +10,7 @@ require (
 	github.com/docker/docker v20.10.18+incompatible
 	github.com/docker/go-connections v0.4.0
 	github.com/gofrs/uuid v4.4.0+incompatible
-	github.com/sagernet/sing v0.1.8-0.20230303052048-c875a4ffab1a
+	github.com/sagernet/sing v0.1.8-0.20230305055148-e16845727f76
 	github.com/sagernet/sing-shadowsocks v0.1.2-0.20230221080503-769c01d6bba9
 	github.com/spyzhov/ajson v0.7.1
 	github.com/stretchr/testify v1.8.1
@@ -71,7 +71,7 @@ require (
 	github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32 // indirect
 	github.com/sagernet/reality v0.0.0-20230228045158-d3e085a8e5d1 // indirect
 	github.com/sagernet/sing-dns v0.1.4 // indirect
-	github.com/sagernet/sing-shadowtls v0.0.0-20230221123345-78e50cd7b587 // indirect
+	github.com/sagernet/sing-shadowtls v0.1.0 // indirect
 	github.com/sagernet/sing-tun v0.1.2-0.20230226091124-0cdb0eed74d9 // indirect
 	github.com/sagernet/sing-vmess v0.1.3-0.20230303082804-627cc46ae68b // indirect
 	github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 // indirect

+ 4 - 4
test/go.sum

@@ -146,14 +146,14 @@ github.com/sagernet/reality v0.0.0-20230228045158-d3e085a8e5d1 h1:8mSzchN6DkM26J
 github.com/sagernet/reality v0.0.0-20230228045158-d3e085a8e5d1/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
 github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
 github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
-github.com/sagernet/sing v0.1.8-0.20230303052048-c875a4ffab1a h1:NvhI/8DMFt2yV3eoYhw6P/XyWzzIKkMiGvFglJbWHWg=
-github.com/sagernet/sing v0.1.8-0.20230303052048-c875a4ffab1a/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
+github.com/sagernet/sing v0.1.8-0.20230305055148-e16845727f76 h1:JCZ4tpEuT6U6oC87EaDBMsPg7+NxesIwESs4dzAGgJo=
+github.com/sagernet/sing v0.1.8-0.20230305055148-e16845727f76/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
 github.com/sagernet/sing-dns v0.1.4 h1:7VxgeoSCiiazDSaXXQVcvrTBxFpOePPq/4XdgnUDN+0=
 github.com/sagernet/sing-dns v0.1.4/go.mod h1:1+6pCa48B1AI78lD+/i/dLgpw4MwfnsSpZo0Ds8wzzk=
 github.com/sagernet/sing-shadowsocks v0.1.2-0.20230221080503-769c01d6bba9 h1:qS39eA4C7x+zhEkySbASrtmb6ebdy5v0y2M6mgkmSO0=
 github.com/sagernet/sing-shadowsocks v0.1.2-0.20230221080503-769c01d6bba9/go.mod h1:f3mHTy5shnVM9l8UocMlJgC/1G/zdj5FuEuVXhDinGU=
-github.com/sagernet/sing-shadowtls v0.0.0-20230221123345-78e50cd7b587 h1:OjIXlHT2bblZfp+ciupM4xY9+Ccpj9FsuHRtKRBv+Pg=
-github.com/sagernet/sing-shadowtls v0.0.0-20230221123345-78e50cd7b587/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc=
+github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ=
+github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc=
 github.com/sagernet/sing-tun v0.1.2-0.20230226091124-0cdb0eed74d9 h1:tq1kc0HFj/jfhLfVC1NJI6lex2g6w2W+gVsFu6H2Kis=
 github.com/sagernet/sing-tun v0.1.2-0.20230226091124-0cdb0eed74d9/go.mod h1:KnRkwaDHbb06zgeNPu0LQ8A+vA9myMxKEgHN1brCPHg=
 github.com/sagernet/sing-vmess v0.1.3-0.20230303082804-627cc46ae68b h1:NZeF0ATeJwe4W3gTJNeIfTB6yBxai665q1HvDOaWmmU=

+ 1 - 0
test/shadowsocks_test.go

@@ -19,6 +19,7 @@ const (
 	clientPort
 	testPort
 	otherPort
+	otherClientPort
 )
 
 func TestShadowsocks(t *testing.T) {

+ 140 - 4
test/vless_test.go

@@ -9,6 +9,7 @@ import (
 	"github.com/sagernet/sing-box/option"
 	"github.com/sagernet/sing-box/transport/vless"
 
+	"github.com/gofrs/uuid"
 	"github.com/spyzhov/ajson"
 	"github.com/stretchr/testify/require"
 )
@@ -65,17 +66,17 @@ func TestVLESS(t *testing.T) {
 
 func TestVLESSXRay(t *testing.T) {
 	t.Run("origin", func(t *testing.T) {
-		testVLESSXray(t, "", "")
+		testVLESSXrayOutbound(t, "", "")
 	})
 	t.Run("xudp", func(t *testing.T) {
-		testVLESSXray(t, "xudp", "")
+		testVLESSXrayOutbound(t, "xudp", "")
 	})
 	t.Run("vision", func(t *testing.T) {
-		testVLESSXray(t, "", vless.FlowVision)
+		testVLESSXrayOutbound(t, "xudp", vless.FlowVision)
 	})
 }
 
-func testVLESSXray(t *testing.T, packetEncoding string, flow string) {
+func testVLESSXrayOutbound(t *testing.T, packetEncoding string, flow string) {
 	_, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
 
 	content, err := os.ReadFile("config/vless-tls-server.json")
@@ -397,3 +398,138 @@ func testVLESSSelfTLS(t *testing.T, flow string) {
 	})
 	testSuit(t, clientPort, testPort)
 }
+
+func TestVLESSXrayInbound(t *testing.T) {
+	testVLESSXrayInbound(t, vless.FlowVision)
+}
+
+func testVLESSXrayInbound(t *testing.T, flow string) {
+	userId, err := uuid.DefaultGenerator.NewV4()
+	require.NoError(t, err)
+	_, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
+
+	startInstance(t, option.Options{
+		Inbounds: []option.Inbound{
+			{
+				Type: C.TypeVLESS,
+				VLESSOptions: option.VLESSInboundOptions{
+					ListenOptions: option.ListenOptions{
+						Listen:     option.ListenAddress(netip.IPv4Unspecified()),
+						ListenPort: serverPort,
+					},
+					Users: []option.VLESSUser{
+						{
+							Name: "sekai",
+							UUID: userId.String(),
+							Flow: flow,
+						},
+					},
+					TLS: &option.InboundTLSOptions{
+						Enabled:         true,
+						ServerName:      "example.org",
+						CertificatePath: certPem,
+						KeyPath:         keyPem,
+					},
+				},
+			},
+			{
+				Type: C.TypeTrojan,
+				Tag:  "trojan",
+				TrojanOptions: option.TrojanInboundOptions{
+					ListenOptions: option.ListenOptions{
+						Listen:     option.ListenAddress(netip.IPv4Unspecified()),
+						ListenPort: otherPort,
+					},
+					Users: []option.TrojanUser{
+						{
+							Name:     "sekai",
+							Password: userId.String(),
+						},
+					},
+					TLS: &option.InboundTLSOptions{
+						Enabled:         true,
+						ServerName:      "example.org",
+						CertificatePath: certPem,
+						KeyPath:         keyPem,
+					},
+				},
+			},
+		},
+	})
+
+	startInstance(t, option.Options{
+		Inbounds: []option.Inbound{
+			{
+				Type: C.TypeMixed,
+				Tag:  "mixed-in",
+				MixedOptions: option.HTTPMixedInboundOptions{
+					ListenOptions: option.ListenOptions{
+						Listen:     option.ListenAddress(netip.IPv4Unspecified()),
+						ListenPort: otherClientPort,
+					},
+				},
+			},
+		},
+		Outbounds: []option.Outbound{
+			{
+				Type: C.TypeTrojan,
+				Tag:  "trojan-out",
+				TrojanOptions: option.TrojanOutboundOptions{
+					ServerOptions: option.ServerOptions{
+						Server:     "127.0.0.1",
+						ServerPort: otherPort,
+					},
+					Password: userId.String(),
+					TLS: &option.OutboundTLSOptions{
+						Enabled:         true,
+						ServerName:      "example.org",
+						CertificatePath: certPem,
+					},
+					DialerOptions: option.DialerOptions{
+						Detour: "vless-out",
+					},
+				},
+			},
+			{
+				Type: C.TypeSocks,
+				Tag:  "vless-out",
+				SocksOptions: option.SocksOutboundOptions{
+					ServerOptions: option.ServerOptions{
+						Server:     "127.0.0.1",
+						ServerPort: clientPort,
+					},
+				},
+			},
+		},
+	})
+
+	content, err := os.ReadFile("config/vless-tls-client.json")
+	require.NoError(t, err)
+	config, err := ajson.Unmarshal(content)
+	require.NoError(t, err)
+
+	config.MustKey("inbounds").MustIndex(0).MustKey("port").SetNumeric(float64(clientPort))
+	outbound := config.MustKey("outbounds").MustIndex(0)
+	settings := outbound.MustKey("settings").MustKey("vnext").MustIndex(0)
+	settings.MustKey("port").SetNumeric(float64(serverPort))
+	user := settings.MustKey("users").MustIndex(0)
+	user.MustKey("id").SetString(userId.String())
+	user.MustKey("flow").SetString(flow)
+	content, err = ajson.Marshal(config)
+	require.NoError(t, err)
+
+	content, err = ajson.Marshal(config)
+	require.NoError(t, err)
+
+	startDockerContainer(t, DockerOptions{
+		Image:      ImageXRayCore,
+		Ports:      []uint16{clientPort},
+		EntryPoint: "xray",
+		Stdin:      content,
+		Bind: map[string]string{
+			certPem: "/path/to/certificate.crt",
+			keyPem:  "/path/to/private.key",
+		},
+	})
+	testTCP(t, otherClientPort, testPort)
+}

+ 23 - 10
transport/vless/vision.go

@@ -32,8 +32,11 @@ func init() {
 	})
 }
 
+const xrayChunkSize = 8192
+
 type VisionConn struct {
 	net.Conn
+	reader   *bufio.ChunkReader
 	writer   N.VectorisedWriter
 	input    *bytes.Reader
 	rawInput *bytes.Buffer
@@ -78,6 +81,7 @@ func NewVisionConn(conn net.Conn, userUUID [16]byte, logger logger.Logger) (*Vis
 	rawInput, _ := reflectType.FieldByName("rawInput")
 	return &VisionConn{
 		Conn:     conn,
+		reader:   bufio.NewChunkReader(conn, xrayChunkSize),
 		writer:   bufio.NewVectorisedWriter(conn),
 		input:    (*bytes.Reader)(unsafe.Pointer(reflectPointer + input.Offset)),
 		rawInput: (*bytes.Buffer)(unsafe.Pointer(reflectPointer + rawInput.Offset)),
@@ -100,22 +104,31 @@ func (c *VisionConn) Read(p []byte) (n int, err error) {
 		n, err = c.remainingReader.Read(p)
 		if err == io.EOF {
 			c.remainingReader = nil
-			if n > 0 {
-				err = nil
-				return
-			}
+		}
+		if n > 0 {
+			return
 		}
 	}
 	if c.directRead {
 		return c.netConn.Read(p)
 	}
-	n, err = c.Conn.Read(p)
-	if err != nil {
-		return
+	var bufferBytes []byte
+	if len(p) > xrayChunkSize {
+		n, err = c.Conn.Read(p)
+		if err != nil {
+			return
+		}
+		bufferBytes = p[:n]
+	} else {
+		buffer, err := c.reader.ReadChunk()
+		if err != nil {
+			return 0, err
+		}
+		defer buffer.FullReset()
+		bufferBytes = buffer.Bytes()
 	}
-	buffer := p[:n]
 	if c.withinPaddingBuffers || c.numberOfPacketToFilter > 0 {
-		buffers := c.unPadding(buffer)
+		buffers := c.unPadding(bufferBytes)
 		if c.remainingContent == 0 && c.remainingPadding == 0 {
 			if c.currentCommand == 1 {
 				c.withinPaddingBuffers = false
@@ -156,7 +169,7 @@ func (c *VisionConn) Read(p []byte) (n int, err error) {
 		return c.remainingReader.Read(p)
 	} else {
 		if c.numberOfPacketToFilter > 0 {
-			c.filterTLS([][]byte{buffer})
+			c.filterTLS([][]byte{bufferBytes})
 		}
 		return
 	}