mirror of
https://github.com/XTLS/Xray-core.git
synced 2024-11-14 20:53:18 +00:00
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
This commit is contained in:
parent
c259e4e4a6
commit
88ae774cce
|
@ -35,7 +35,7 @@ type Sniffer struct {
|
||||||
func NewSniffer(ctx context.Context) *Sniffer {
|
func NewSniffer(ctx context.Context) *Sniffer {
|
||||||
ret := &Sniffer{
|
ret := &Sniffer{
|
||||||
sniffer: []protocolSnifferWithMetadata{
|
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 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 bittorrent.SniffBittorrent(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 quic.SniffQUIC(b) }, false, net.Network_UDP},
|
||||||
|
|
|
@ -2,11 +2,13 @@ package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
|
"github.com/xtls/xray-core/common/session"
|
||||||
)
|
)
|
||||||
|
|
||||||
type version byte
|
type version byte
|
||||||
|
@ -56,7 +58,14 @@ func beginWithHTTPMethod(b []byte) error {
|
||||||
return errNotHTTPMethod
|
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 {
|
if err := beginWithHTTPMethod(b); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -76,8 +85,12 @@ func SniffHTTP(b []byte) (*SniffHeader, error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
key := strings.ToLower(string(parts[0]))
|
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" {
|
if key == "host" {
|
||||||
rawHost := strings.ToLower(string(bytes.TrimSpace(parts[1])))
|
rawHost := strings.ToLower(value)
|
||||||
dest, err := ParseHost(rawHost, net.Port(80))
|
dest, err := ParseHost(rawHost, net.Port(80))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -85,6 +98,16 @@ func SniffHTTP(b []byte) (*SniffHeader, error) {
|
||||||
sh.host = dest.Address.String()
|
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 {
|
if len(sh.host) > 0 {
|
||||||
return sh, nil
|
return sh, nil
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package http_test
|
package http_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
. "github.com/xtls/xray-core/common/protocol/http"
|
. "github.com/xtls/xray-core/common/protocol/http"
|
||||||
|
@ -88,7 +89,7 @@ first_name=John&last_name=Doe&action=Submit`,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range cases {
|
for _, test := range cases {
|
||||||
header, err := SniffHTTP([]byte(test.input))
|
header, err := SniffHTTP([]byte(test.input), context.TODO())
|
||||||
if test.err {
|
if test.err {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expect error but nil, in test: %v", test)
|
t.Errorf("Expect error but nil, in test: %v", test)
|
||||||
|
|
Loading…
Reference in a new issue