Loopback outbound: Add sniffing (#6326)

Example: https://github.com/XTLS/Xray-core/pull/6326#issue-4659701786
This commit is contained in:
j2rong4cn
2026-06-19 07:17:01 +08:00
committed by GitHub
parent 986c512e0f
commit c815c2f2df
4 changed files with 51 additions and 17 deletions
+12 -2
View File
@@ -1,14 +1,24 @@
package conf package conf
import ( import (
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/proxy/loopback" "github.com/xtls/xray-core/proxy/loopback"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
) )
type LoopbackConfig struct { type LoopbackConfig struct {
InboundTag string `json:"inboundTag"` InboundTag string `json:"inboundTag"`
Sniffing *SniffingConfig `json:"sniffing"`
} }
func (l LoopbackConfig) Build() (proto.Message, error) { func (l LoopbackConfig) Build() (proto.Message, error) {
return &loopback.Config{InboundTag: l.InboundTag}, nil c := &loopback.Config{InboundTag: l.InboundTag}
if l.Sniffing != nil {
sc, err := l.Sniffing.Build()
if err != nil {
return nil, errors.New("failed to build sniffing config").Base(err)
}
c.Sniffing = sc
}
return c, nil
} }
+22 -10
View File
@@ -7,6 +7,7 @@
package loopback package loopback
import ( import (
proxyman "github.com/xtls/xray-core/app/proxyman"
protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl" protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect" reflect "reflect"
@@ -22,8 +23,9 @@ const (
) )
type Config struct { type Config struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
InboundTag string `protobuf:"bytes,1,opt,name=inbound_tag,json=inboundTag,proto3" json:"inbound_tag,omitempty"` InboundTag string `protobuf:"bytes,1,opt,name=inbound_tag,json=inboundTag,proto3" json:"inbound_tag,omitempty"`
Sniffing *proxyman.SniffingConfig `protobuf:"bytes,2,opt,name=sniffing,proto3" json:"sniffing,omitempty"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@@ -65,14 +67,22 @@ func (x *Config) GetInboundTag() string {
return "" return ""
} }
func (x *Config) GetSniffing() *proxyman.SniffingConfig {
if x != nil {
return x.Sniffing
}
return nil
}
var File_proxy_loopback_config_proto protoreflect.FileDescriptor var File_proxy_loopback_config_proto protoreflect.FileDescriptor
const file_proxy_loopback_config_proto_rawDesc = "" + const file_proxy_loopback_config_proto_rawDesc = "" +
"\n" + "\n" +
"\x1bproxy/loopback/config.proto\x12\x13xray.proxy.loopback\")\n" + "\x1bproxy/loopback/config.proto\x12\x13xray.proxy.loopback\x1a\x19app/proxyman/config.proto\"h\n" +
"\x06Config\x12\x1f\n" + "\x06Config\x12\x1f\n" +
"\vinbound_tag\x18\x01 \x01(\tR\n" + "\vinbound_tag\x18\x01 \x01(\tR\n" +
"inboundTagB[\n" + "inboundTag\x12=\n" +
"\bsniffing\x18\x02 \x01(\v2!.xray.app.proxyman.SniffingConfigR\bsniffingB[\n" +
"\x17com.xray.proxy.loopbackP\x01Z(github.com/xtls/xray-core/proxy/loopback\xaa\x02\x13Xray.Proxy.Loopbackb\x06proto3" "\x17com.xray.proxy.loopbackP\x01Z(github.com/xtls/xray-core/proxy/loopback\xaa\x02\x13Xray.Proxy.Loopbackb\x06proto3"
var ( var (
@@ -89,14 +99,16 @@ func file_proxy_loopback_config_proto_rawDescGZIP() []byte {
var file_proxy_loopback_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_proxy_loopback_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_proxy_loopback_config_proto_goTypes = []any{ var file_proxy_loopback_config_proto_goTypes = []any{
(*Config)(nil), // 0: xray.proxy.loopback.Config (*Config)(nil), // 0: xray.proxy.loopback.Config
(*proxyman.SniffingConfig)(nil), // 1: xray.app.proxyman.SniffingConfig
} }
var file_proxy_loopback_config_proto_depIdxs = []int32{ var file_proxy_loopback_config_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type 1, // 0: xray.proxy.loopback.Config.sniffing:type_name -> xray.app.proxyman.SniffingConfig
0, // [0:0] is the sub-list for method input_type 1, // [1:1] is the sub-list for method output_type
0, // [0:0] is the sub-list for extension type_name 1, // [1:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension extendee 1, // [1:1] is the sub-list for extension type_name
0, // [0:0] is the sub-list for field type_name 1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
} }
func init() { file_proxy_loopback_config_proto_init() } func init() { file_proxy_loopback_config_proto_init() }
+3
View File
@@ -6,6 +6,9 @@ option go_package = "github.com/xtls/xray-core/proxy/loopback";
option java_package = "com.xray.proxy.loopback"; option java_package = "com.xray.proxy.loopback";
option java_multiple_files = true; option java_multiple_files = true;
import "app/proxyman/config.proto";
message Config { message Config {
string inbound_tag = 1; string inbound_tag = 1;
xray.app.proxyman.SniffingConfig sniffing = 2;
} }
+14 -5
View File
@@ -3,6 +3,7 @@ package loopback
import ( import (
"context" "context"
proxyman "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/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
@@ -13,7 +14,8 @@ import (
) )
type Loopback struct { type Loopback struct {
config *Config inboundTag string
sniffingRequest session.SniffingRequest
dispatcherInstance routing.Dispatcher dispatcherInstance routing.Dispatcher
} }
@@ -29,6 +31,7 @@ func (l *Loopback) Process(ctx context.Context, link *transport.Link, _ internet
errors.LogInfo(ctx, "opening connection to ", destination) errors.LogInfo(ctx, "opening connection to ", destination)
content := new(session.Content) content := new(session.Content)
content.SkipDNSResolve = true content.SkipDNSResolve = true
content.SniffingRequest = l.sniffingRequest
ctx = session.ContextWithContent(ctx, content) ctx = session.ContextWithContent(ctx, content)
inbound := &session.Inbound{} inbound := &session.Inbound{}
@@ -37,20 +40,26 @@ func (l *Loopback) Process(ctx context.Context, link *transport.Link, _ internet
// get a shallow copy to avoid modifying the inbound tag in upstream context // get a shallow copy to avoid modifying the inbound tag in upstream context
*inbound = *originInbound *inbound = *originInbound
} }
inbound.Tag = l.config.InboundTag inbound.Tag = l.inboundTag
ctx = session.ContextWithInbound(ctx, inbound) ctx = session.ContextWithInbound(ctx, inbound)
err := l.dispatcherInstance.DispatchLink(ctx, destination, link) err := l.dispatcherInstance.DispatchLink(ctx, destination, link)
if err != nil { if err != nil {
errors.New(ctx, "failed to process loopback connection").Base(err) return errors.New(ctx, "failed to process loopback connection").Base(err)
return err
} }
return nil return nil
} }
func (l *Loopback) init(config *Config, dispatcherInstance routing.Dispatcher) error { func (l *Loopback) init(config *Config, dispatcherInstance routing.Dispatcher) error {
l.dispatcherInstance = dispatcherInstance l.dispatcherInstance = dispatcherInstance
l.config = config l.inboundTag = config.InboundTag
if config.Sniffing.GetEnabled() {
request, err := proxyman.BuildSniffingRequest(config.Sniffing)
if err != nil {
return errors.New("failed to build loopback sniffing request").Base(err).AtError()
}
l.sniffingRequest = request
}
return nil return nil
} }