Meow
2026-04-14 01:39:53 +08:00
committed by GitHub
parent 05a11910d4
commit f17fabfff5
11 changed files with 157 additions and 130 deletions

View File

@@ -2,7 +2,6 @@ package dispatcher
import ( import (
"context" "context"
"regexp"
"strings" "strings"
"sync" "sync"
"time" "time"
@@ -235,22 +234,8 @@ func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResu
if domain == "" { if domain == "" {
return false return false
} }
for _, d := range request.ExcludeForDomain { if request.ExcludeForDomain != nil && request.ExcludeForDomain.MatchAny(strings.ToLower(domain)) {
if strings.HasPrefix(d, "regexp:") { return false
pattern := d[7:]
re, err := regexp.Compile(pattern)
if err != nil {
errors.LogInfo(ctx, "Unable to compile regex")
continue
}
if re.MatchString(domain) {
return false
}
} else {
if strings.ToLower(domain) == d {
return false
}
}
} }
protocolString := result.Protocol() protocolString := result.Protocol()
if resComp, ok := result.(SnifferResultComposite); ok { if resComp, ok := result.(SnifferResultComposite); ok {

View File

@@ -1 +1,27 @@
package proxyman package proxyman
import (
"github.com/xtls/xray-core/common/geodata"
"github.com/xtls/xray-core/common/session"
)
func BuildSniffingRequest(config *SniffingConfig) (session.SniffingRequest, error) {
if config == nil {
return session.SniffingRequest{}, nil
}
request := session.SniffingRequest{
Enabled: config.Enabled,
OverrideDestinationForProtocol: config.DestinationOverride,
MetadataOnly: config.MetadataOnly,
RouteOnly: config.RouteOnly,
}
if len(config.DomainsExcluded) > 0 {
excludeForDomain, err := geodata.DomainReg.BuildDomainMatcher(config.DomainsExcluded)
if err != nil {
return session.SniffingRequest{}, err
}
request.ExcludeForDomain = excludeForDomain
}
return request, nil
}

View File

@@ -7,6 +7,7 @@
package proxyman package proxyman
import ( import (
geodata "github.com/xtls/xray-core/common/geodata"
net "github.com/xtls/xray-core/common/net" net "github.com/xtls/xray-core/common/net"
serial "github.com/xtls/xray-core/common/serial" serial "github.com/xtls/xray-core/common/serial"
internet "github.com/xtls/xray-core/transport/internet" internet "github.com/xtls/xray-core/transport/internet"
@@ -66,8 +67,8 @@ type SniffingConfig struct {
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
// Override target destination if sniff'ed protocol is in the given list. // Override target destination if sniff'ed protocol is in the given list.
// Supported values are "http", "tls", "fakedns". // Supported values are "http", "tls", "fakedns".
DestinationOverride []string `protobuf:"bytes,2,rep,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"` DestinationOverride []string `protobuf:"bytes,2,rep,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"`
DomainsExcluded []string `protobuf:"bytes,3,rep,name=domains_excluded,json=domainsExcluded,proto3" json:"domains_excluded,omitempty"` DomainsExcluded []*geodata.DomainRule `protobuf:"bytes,3,rep,name=domains_excluded,json=domainsExcluded,proto3" json:"domains_excluded,omitempty"`
// Whether should only try to sniff metadata without waiting for client input. // Whether should only try to sniff metadata without waiting for client input.
// Can be used to support SMTP like protocol where server send the first // Can be used to support SMTP like protocol where server send the first
// message. // message.
@@ -121,7 +122,7 @@ func (x *SniffingConfig) GetDestinationOverride() []string {
return nil return nil
} }
func (x *SniffingConfig) GetDomainsExcluded() []string { func (x *SniffingConfig) GetDomainsExcluded() []*geodata.DomainRule {
if x != nil { if x != nil {
return x.DomainsExcluded return x.DomainsExcluded
} }
@@ -477,12 +478,12 @@ var File_app_proxyman_config_proto protoreflect.FileDescriptor
const file_app_proxyman_config_proto_rawDesc = "" + const file_app_proxyman_config_proto_rawDesc = "" +
"\n" + "\n" +
"\x19app/proxyman/config.proto\x12\x11xray.app.proxyman\x1a\x18common/net/address.proto\x1a\x15common/net/port.proto\x1a\x1ftransport/internet/config.proto\x1a!common/serial/typed_message.proto\"\x0f\n" + "\x19app/proxyman/config.proto\x12\x11xray.app.proxyman\x1a\x18common/net/address.proto\x1a\x15common/net/port.proto\x1a\x1ftransport/internet/config.proto\x1a!common/serial/typed_message.proto\x1a\x1bcommon/geodata/geodat.proto\"\x0f\n" +
"\rInboundConfig\"\xcc\x01\n" + "\rInboundConfig\"\xed\x01\n" +
"\x0eSniffingConfig\x12\x18\n" + "\x0eSniffingConfig\x12\x18\n" +
"\aenabled\x18\x01 \x01(\bR\aenabled\x121\n" + "\aenabled\x18\x01 \x01(\bR\aenabled\x121\n" +
"\x14destination_override\x18\x02 \x03(\tR\x13destinationOverride\x12)\n" + "\x14destination_override\x18\x02 \x03(\tR\x13destinationOverride\x12J\n" +
"\x10domains_excluded\x18\x03 \x03(\tR\x0fdomainsExcluded\x12#\n" + "\x10domains_excluded\x18\x03 \x03(\v2\x1f.xray.common.geodata.DomainRuleR\x0fdomainsExcluded\x12#\n" +
"\rmetadata_only\x18\x04 \x01(\bR\fmetadataOnly\x12\x1d\n" + "\rmetadata_only\x18\x04 \x01(\bR\fmetadataOnly\x12\x1d\n" +
"\n" + "\n" +
"route_only\x18\x05 \x01(\bR\trouteOnly\"\xe5\x02\n" + "route_only\x18\x05 \x01(\bR\trouteOnly\"\xe5\x02\n" +
@@ -532,30 +533,32 @@ var file_app_proxyman_config_proto_goTypes = []any{
(*OutboundConfig)(nil), // 4: xray.app.proxyman.OutboundConfig (*OutboundConfig)(nil), // 4: xray.app.proxyman.OutboundConfig
(*SenderConfig)(nil), // 5: xray.app.proxyman.SenderConfig (*SenderConfig)(nil), // 5: xray.app.proxyman.SenderConfig
(*MultiplexingConfig)(nil), // 6: xray.app.proxyman.MultiplexingConfig (*MultiplexingConfig)(nil), // 6: xray.app.proxyman.MultiplexingConfig
(*net.PortList)(nil), // 7: xray.common.net.PortList (*geodata.DomainRule)(nil), // 7: xray.common.geodata.DomainRule
(*net.IPOrDomain)(nil), // 8: xray.common.net.IPOrDomain (*net.PortList)(nil), // 8: xray.common.net.PortList
(*internet.StreamConfig)(nil), // 9: xray.transport.internet.StreamConfig (*net.IPOrDomain)(nil), // 9: xray.common.net.IPOrDomain
(*serial.TypedMessage)(nil), // 10: xray.common.serial.TypedMessage (*internet.StreamConfig)(nil), // 10: xray.transport.internet.StreamConfig
(*internet.ProxyConfig)(nil), // 11: xray.transport.internet.ProxyConfig (*serial.TypedMessage)(nil), // 11: xray.common.serial.TypedMessage
(internet.DomainStrategy)(0), // 12: xray.transport.internet.DomainStrategy (*internet.ProxyConfig)(nil), // 12: xray.transport.internet.ProxyConfig
(internet.DomainStrategy)(0), // 13: xray.transport.internet.DomainStrategy
} }
var file_app_proxyman_config_proto_depIdxs = []int32{ var file_app_proxyman_config_proto_depIdxs = []int32{
7, // 0: xray.app.proxyman.ReceiverConfig.port_list:type_name -> xray.common.net.PortList 7, // 0: xray.app.proxyman.SniffingConfig.domains_excluded:type_name -> xray.common.geodata.DomainRule
8, // 1: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain 8, // 1: xray.app.proxyman.ReceiverConfig.port_list:type_name -> xray.common.net.PortList
9, // 2: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig 9, // 2: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain
1, // 3: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig 10, // 3: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
10, // 4: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage 1, // 4: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig
10, // 5: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage 11, // 5: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage
8, // 6: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain 11, // 6: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
9, // 7: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig 9, // 7: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain
11, // 8: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig 10, // 8: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
6, // 9: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig 12, // 9: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
12, // 10: xray.app.proxyman.SenderConfig.target_strategy:type_name -> xray.transport.internet.DomainStrategy 6, // 10: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
11, // [11:11] is the sub-list for method output_type 13, // 11: xray.app.proxyman.SenderConfig.target_strategy:type_name -> xray.transport.internet.DomainStrategy
11, // [11:11] is the sub-list for method input_type 12, // [12:12] is the sub-list for method output_type
11, // [11:11] is the sub-list for extension type_name 12, // [12:12] is the sub-list for method input_type
11, // [11:11] is the sub-list for extension extendee 12, // [12:12] is the sub-list for extension type_name
0, // [0:11] is the sub-list for field type_name 12, // [12:12] is the sub-list for extension extendee
0, // [0:12] is the sub-list for field type_name
} }
func init() { file_app_proxyman_config_proto_init() } func init() { file_app_proxyman_config_proto_init() }

View File

@@ -10,6 +10,7 @@ import "common/net/address.proto";
import "common/net/port.proto"; import "common/net/port.proto";
import "transport/internet/config.proto"; import "transport/internet/config.proto";
import "common/serial/typed_message.proto"; import "common/serial/typed_message.proto";
import "common/geodata/geodat.proto";
message InboundConfig {} message InboundConfig {}
@@ -20,7 +21,8 @@ message SniffingConfig {
// Override target destination if sniff'ed protocol is in the given list. // Override target destination if sniff'ed protocol is in the given list.
// Supported values are "http", "tls", "fakedns". // Supported values are "http", "tls", "fakedns".
repeated string destination_override = 2; repeated string destination_override = 2;
repeated string domains_excluded = 3;
repeated xray.common.geodata.DomainRule domains_excluded = 3;
// Whether should only try to sniff metadata without waiting for client input. // Whether should only try to sniff metadata without waiting for client input.
// Can be used to support SMTP like protocol where server send the first // Can be used to support SMTP like protocol where server send the first

View File

@@ -53,18 +53,17 @@ type AlwaysOnInboundHandler struct {
} }
func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*AlwaysOnInboundHandler, error) { func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*AlwaysOnInboundHandler, error) {
sniffingRequest, err := proxyman.BuildSniffingRequest(receiverConfig.SniffingSettings)
if err != nil {
return nil, err
}
// Set tag and sniffing config in context before creating proxy // Set tag and sniffing config in context before creating proxy
// This allows proxies like TUN to access these settings // This allows proxies like TUN to access these settings
ctx = session.ContextWithInbound(ctx, &session.Inbound{Tag: tag}) ctx = session.ContextWithInbound(ctx, &session.Inbound{Tag: tag})
if receiverConfig.SniffingSettings != nil { if receiverConfig.SniffingSettings != nil {
ctx = session.ContextWithContent(ctx, &session.Content{ ctx = session.ContextWithContent(ctx, &session.Content{
SniffingRequest: session.SniffingRequest{ SniffingRequest: sniffingRequest,
Enabled: receiverConfig.SniffingSettings.Enabled,
OverrideDestinationForProtocol: receiverConfig.SniffingSettings.DestinationOverride,
ExcludeForDomain: receiverConfig.SniffingSettings.DomainsExcluded,
MetadataOnly: receiverConfig.SniffingSettings.MetadataOnly,
RouteOnly: receiverConfig.SniffingSettings.RouteOnly,
},
}) })
} }
rawProxy, err := common.CreateObject(ctx, proxyConfig) rawProxy, err := common.CreateObject(ctx, proxyConfig)
@@ -117,7 +116,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
stream: mss, stream: mss,
tag: tag, tag: tag,
dispatcher: h.mux, dispatcher: h.mux,
sniffingConfig: receiverConfig.SniffingSettings, sniffingRequest: sniffingRequest,
uplinkCounter: uplinkCounter, uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter, downlinkCounter: downlinkCounter,
ctx: ctx, ctx: ctx,
@@ -139,7 +138,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
recvOrigDest: receiverConfig.ReceiveOriginalDestination, recvOrigDest: receiverConfig.ReceiveOriginalDestination,
tag: tag, tag: tag,
dispatcher: h.mux, dispatcher: h.mux,
sniffingConfig: receiverConfig.SniffingSettings, sniffingRequest: sniffingRequest,
uplinkCounter: uplinkCounter, uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter, downlinkCounter: downlinkCounter,
ctx: ctx, ctx: ctx,
@@ -154,7 +153,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
address: address, address: address,
port: net.Port(port), port: net.Port(port),
dispatcher: h.mux, dispatcher: h.mux,
sniffingConfig: receiverConfig.SniffingSettings, sniffingRequest: sniffingRequest,
uplinkCounter: uplinkCounter, uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter, downlinkCounter: downlinkCounter,
stream: mss, stream: mss,

View File

@@ -6,7 +6,6 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
c "github.com/xtls/xray-core/common/ctx" c "github.com/xtls/xray-core/common/ctx"
@@ -43,7 +42,7 @@ type tcpWorker struct {
recvOrigDest bool recvOrigDest bool
tag string tag string
dispatcher routing.Dispatcher dispatcher routing.Dispatcher
sniffingConfig *proxyman.SniffingConfig sniffingRequest session.SniffingRequest
uplinkCounter stats.Counter uplinkCounter stats.Counter
downlinkCounter stats.Counter downlinkCounter stats.Counter
@@ -118,13 +117,7 @@ func (w *tcpWorker) callback(conn stat.Connection) {
}) })
content := new(session.Content) content := new(session.Content)
if w.sniffingConfig != nil { content.SniffingRequest = w.sniffingRequest
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
}
ctx = session.ContextWithContent(ctx, content) ctx = session.ContextWithContent(ctx, content)
if err := w.proxy.Process(ctx, net.Network_TCP, conn, w.dispatcher); err != nil { if err := w.proxy.Process(ctx, net.Network_TCP, conn, w.dispatcher); err != nil {
@@ -275,7 +268,7 @@ type udpWorker struct {
tag string tag string
stream *internet.MemoryStreamConfig stream *internet.MemoryStreamConfig
dispatcher routing.Dispatcher dispatcher routing.Dispatcher
sniffingConfig *proxyman.SniffingConfig sniffingRequest session.SniffingRequest
uplinkCounter stats.Counter uplinkCounter stats.Counter
downlinkCounter stats.Counter downlinkCounter stats.Counter
@@ -365,13 +358,7 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
Tag: w.tag, Tag: w.tag,
}) })
content := new(session.Content) content := new(session.Content)
if w.sniffingConfig != nil { content.SniffingRequest = w.sniffingRequest
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
}
ctx = session.ContextWithContent(ctx, content) ctx = session.ContextWithContent(ctx, content)
if err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil { if err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil {
errors.LogInfoInner(ctx, err, "connection ends") errors.LogInfoInner(ctx, err, "connection ends")
@@ -487,7 +474,7 @@ type dsWorker struct {
stream *internet.MemoryStreamConfig stream *internet.MemoryStreamConfig
tag string tag string
dispatcher routing.Dispatcher dispatcher routing.Dispatcher
sniffingConfig *proxyman.SniffingConfig sniffingRequest session.SniffingRequest
uplinkCounter stats.Counter uplinkCounter stats.Counter
downlinkCounter stats.Counter downlinkCounter stats.Counter
@@ -517,13 +504,7 @@ func (w *dsWorker) callback(conn stat.Connection) {
}) })
content := new(session.Content) content := new(session.Content)
if w.sniffingConfig != nil { content.SniffingRequest = w.sniffingRequest
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
}
ctx = session.ContextWithContent(ctx, content) ctx = session.ContextWithContent(ctx, content)
if err := w.proxy.Process(ctx, net.Network_UNIX, conn, w.dispatcher); err != nil { if err := w.proxy.Process(ctx, net.Network_UNIX, conn, w.dispatcher); err != nil {

View File

@@ -7,6 +7,7 @@ import (
c "github.com/xtls/xray-core/common/ctx" c "github.com/xtls/xray-core/common/ctx"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/geodata"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/signal" "github.com/xtls/xray-core/common/signal"
@@ -78,7 +79,7 @@ type Outbound struct {
// SniffingRequest controls the behavior of content sniffing. They are from inbound config. Read-only // SniffingRequest controls the behavior of content sniffing. They are from inbound config. Read-only
type SniffingRequest struct { type SniffingRequest struct {
ExcludeForDomain []string ExcludeForDomain geodata.DomainMatcher
OverrideDestinationForProtocol []string OverrideDestinationForProtocol []string
Enabled bool Enabled bool
MetadataOnly bool MetadataOnly bool

View File

@@ -118,26 +118,17 @@ func (FakeDNSPostProcessingStage) Process(config *Config) error {
} }
} }
found := false // Check if there is a Inbound with necessary sniffer on
// Check if there is a Outbound with necessary sniffer on for _, v := range config.InboundConfigs {
var inbounds []InboundDetourConfig if v.SniffingConfig != nil && v.SniffingConfig.Enabled {
for _, d := range v.SniffingConfig.DestOverride {
if len(config.InboundConfigs) > 0 { if strings.EqualFold(d, "fakedns") || strings.EqualFold(d, "fakedns+others") {
inbounds = append(inbounds, config.InboundConfigs...) return nil
}
for _, v := range inbounds {
if v.SniffingConfig != nil && v.SniffingConfig.Enabled && v.SniffingConfig.DestOverride != nil {
for _, dov := range *v.SniffingConfig.DestOverride {
if strings.EqualFold(dov, "fakedns") || strings.EqualFold(dov, "fakedns+others") {
found = true
break
} }
} }
} }
} }
if !found { errors.LogWarning(context.Background(), "Defined FakeDNS but haven't enabled FakeDNS destOverride at any inbound.")
errors.LogWarning(context.Background(), "Defined FakeDNS but haven't enabled FakeDNS destOverride at any inbound.")
}
} }
return nil return nil

View File

@@ -10,6 +10,7 @@ import (
"github.com/xtls/xray-core/app/proxyman" "github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/app/stats" "github.com/xtls/xray-core/app/stats"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/geodata"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
core "github.com/xtls/xray-core/core" core "github.com/xtls/xray-core/core"
@@ -51,38 +52,34 @@ var (
) )
type SniffingConfig struct { type SniffingConfig struct {
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
DestOverride *StringList `json:"destOverride"` DestOverride StringList `json:"destOverride"`
DomainsExcluded *StringList `json:"domainsExcluded"` DomainsExcluded StringList `json:"domainsExcluded"`
MetadataOnly bool `json:"metadataOnly"` MetadataOnly bool `json:"metadataOnly"`
RouteOnly bool `json:"routeOnly"` RouteOnly bool `json:"routeOnly"`
} }
// Build implements Buildable. // Build implements Buildable.
func (c *SniffingConfig) Build() (*proxyman.SniffingConfig, error) { func (c *SniffingConfig) Build() (*proxyman.SniffingConfig, error) {
var p []string var p []string
if c.DestOverride != nil { for _, protocol := range c.DestOverride {
for _, protocol := range *c.DestOverride { switch strings.ToLower(protocol) {
switch strings.ToLower(protocol) { case "http":
case "http": p = append(p, "http")
p = append(p, "http") case "tls", "https", "ssl":
case "tls", "https", "ssl": p = append(p, "tls")
p = append(p, "tls") case "quic":
case "quic": p = append(p, "quic")
p = append(p, "quic") case "fakedns", "fakedns+others":
case "fakedns", "fakedns+others": p = append(p, "fakedns")
p = append(p, "fakedns") default:
default: return nil, errors.New("unknown protocol: ", protocol)
return nil, errors.New("unknown protocol: ", protocol)
}
} }
} }
var d []string d, err := geodata.ParseDomainRules(c.DomainsExcluded, geodata.Domain_Substr)
if c.DomainsExcluded != nil { if err != nil {
for _, domain := range *c.DomainsExcluded { return nil, err
d = append(d, strings.ToLower(domain))
}
} }
return &proxyman.SniffingConfig{ return &proxyman.SniffingConfig{

View File

@@ -158,6 +158,49 @@ func TestXrayConfig(t *testing.T) {
}) })
} }
func TestSniffingConfig_Build(t *testing.T) {
config := &SniffingConfig{
Enabled: true,
DestOverride: StringList{"http", "tls"},
DomainsExcluded: StringList{"full:api.example.com", "domain:blocked.example", "regexp:^test[0-9]+\\.internal$"},
MetadataOnly: true,
RouteOnly: true,
}
built, err := config.Build()
if err != nil {
t.Fatalf("SniffingConfig.Build() failed: %v", err)
}
if !built.Enabled || !built.MetadataOnly || !built.RouteOnly {
t.Fatalf("SniffingConfig.Build() lost sniffing flags: %+v", built)
}
if len(built.DestinationOverride) != 2 {
t.Fatalf("SniffingConfig.Build() lost destination overrides: %+v", built.DestinationOverride)
}
if len(built.DomainsExcluded) != 3 {
t.Fatalf("SniffingConfig.Build() produced %d domain rules", len(built.DomainsExcluded))
}
want := []struct {
ruleType geodata.Domain_Type
value string
}{
{ruleType: geodata.Domain_Full, value: "api.example.com"},
{ruleType: geodata.Domain_Domain, value: "blocked.example"},
{ruleType: geodata.Domain_Regex, value: "^test[0-9]+\\.internal$"},
}
for i, tc := range want {
rule := built.DomainsExcluded[i].GetCustom()
if rule == nil {
t.Fatalf("SniffingConfig.Build() produced a non-custom rule at index %d", i)
}
if rule.Type != tc.ruleType || rule.Value != tc.value {
t.Fatalf("SniffingConfig.Build() produced wrong rule at index %d: got (%v, %q), want (%v, %q)", i, rule.Type, rule.Value, tc.ruleType, tc.value)
}
}
}
func TestMuxConfig_Build(t *testing.T) { func TestMuxConfig_Build(t *testing.T) {
tests := []struct { tests := []struct {
name string name string

View File

@@ -12,6 +12,7 @@ import (
"unsafe" "unsafe"
utls "github.com/refraction-networking/utls" utls "github.com/refraction-networking/utls"
proxymanConfig "github.com/xtls/xray-core/app/proxyman"
proxyman "github.com/xtls/xray-core/app/proxyman/outbound" proxyman "github.com/xtls/xray-core/app/proxyman/outbound"
"github.com/xtls/xray-core/app/reverse" "github.com/xtls/xray-core/app/reverse"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
@@ -102,14 +103,12 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
User: handler.server.User, // TODO: email User: handler.server.User, // TODO: email
}) })
if sc := a.Reverse.Sniffing; sc != nil && sc.Enabled { if sc := a.Reverse.Sniffing; sc != nil && sc.Enabled {
request, err := proxymanConfig.BuildSniffingRequest(sc)
if err != nil {
return nil, errors.New("failed to build reverse sniffing request").Base(err).AtError()
}
rvsCtx = session.ContextWithContent(rvsCtx, &session.Content{ rvsCtx = session.ContextWithContent(rvsCtx, &session.Content{
SniffingRequest: session.SniffingRequest{ SniffingRequest: request,
Enabled: sc.Enabled,
OverrideDestinationForProtocol: sc.DestinationOverride,
ExcludeForDomain: sc.DomainsExcluded,
MetadataOnly: sc.MetadataOnly,
RouteOnly: sc.RouteOnly,
},
}) })
} }
handler.reverse = &Reverse{ handler.reverse = &Reverse{