浏览代码

Sniff: Routing “attrs” support non http inbound (#3808)

* Sniff: Support attrs route in non http inbound

* Add capability to sniff method and path

* Fix test

* Skip HTTP inbound PlainHTTP mode

* Fix test
again
风扇滑翔翼 1 年之前
父节点
当前提交
88ae774cce
共有 3 个文件被更改,包括 28 次插入4 次删除
  1. 1 1
      app/dispatcher/sniffer.go
  2. 25 2
      common/protocol/http/sniff.go
  3. 2 1
      common/protocol/http/sniff_test.go

+ 1 - 1
app/dispatcher/sniffer.go

@@ -35,7 +35,7 @@ type Sniffer struct {
 func NewSniffer(ctx context.Context) *Sniffer {
 	ret := &Sniffer{
 		sniffer: []protocolSnifferWithMetadata{
-			{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 http.SniffHTTP(b, c) }, 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 bittorrent.SniffBittorrent(b) }, false, net.Network_TCP},
 			{func(c context.Context, b []byte) (SniffResult, error) { return quic.SniffQUIC(b) }, false, net.Network_UDP},

+ 25 - 2
common/protocol/http/sniff.go

@@ -2,11 +2,13 @@ package http
 
 import (
 	"bytes"
+	"context"
 	"errors"
 	"strings"
 
 	"github.com/xtls/xray-core/common"
 	"github.com/xtls/xray-core/common/net"
+	"github.com/xtls/xray-core/common/session"
 )
 
 type version byte
@@ -56,7 +58,14 @@ func beginWithHTTPMethod(b []byte) error {
 	return errNotHTTPMethod
 }
 
-func SniffHTTP(b []byte) (*SniffHeader, error) {
+func SniffHTTP(b []byte, c context.Context) (*SniffHeader, error) {
+	content := session.ContentFromContext(c)
+	ShouldSniffAttr := true
+	// If content.Attributes have information, that means it comes from HTTP inbound PlainHTTP mode.
+	// It will set attributes, so skip it.
+	if content == nil || len(content.Attributes) != 0 {
+		ShouldSniffAttr = false
+	}
 	if err := beginWithHTTPMethod(b); err != nil {
 		return nil, err
 	}
@@ -76,8 +85,12 @@ func SniffHTTP(b []byte) (*SniffHeader, error) {
 			continue
 		}
 		key := strings.ToLower(string(parts[0]))
+		value := string(bytes.TrimSpace(parts[1]))
+		if ShouldSniffAttr {
+			content.SetAttribute(key, value) // Put header in attribute
+		}
 		if key == "host" {
-			rawHost := strings.ToLower(string(bytes.TrimSpace(parts[1])))
+			rawHost := strings.ToLower(value)
 			dest, err := ParseHost(rawHost, net.Port(80))
 			if err != nil {
 				return nil, err
@@ -85,6 +98,16 @@ func SniffHTTP(b []byte) (*SniffHeader, error) {
 			sh.host = dest.Address.String()
 		}
 	}
+	// Parse request line
+	// Request line is like this
+	// "GET /homo/114514 HTTP/1.1"
+	if len(headers) > 0 && ShouldSniffAttr {
+		RequestLineParts := bytes.Split(headers[0], []byte{' '})
+		if len(RequestLineParts) == 3 {
+			content.SetAttribute(":method", string(RequestLineParts[0]))
+			content.SetAttribute(":path", string(RequestLineParts[1]))
+		}
+	}
 
 	if len(sh.host) > 0 {
 		return sh, nil

+ 2 - 1
common/protocol/http/sniff_test.go

@@ -1,6 +1,7 @@
 package http_test
 
 import (
+	"context"
 	"testing"
 
 	. "github.com/xtls/xray-core/common/protocol/http"
@@ -88,7 +89,7 @@ first_name=John&last_name=Doe&action=Submit`,
 	}
 
 	for _, test := range cases {
-		header, err := SniffHTTP([]byte(test.input))
+		header, err := SniffHTTP([]byte(test.input), context.TODO())
 		if test.err {
 			if err == nil {
 				t.Errorf("Expect error but nil, in test: %v", test)