mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-05-08 14:13:22 +00:00
Sniffing: Add ipsExcluded (supports IP, CIDR, "geoip:", "ext:") (#5929)
https://github.com/XTLS/Xray-core/pull/5927#issuecomment-4238197075 https://github.com/XTLS/Xray-core/pull/5929#issuecomment-4238550443
This commit is contained in:
@@ -237,6 +237,9 @@ func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResu
|
||||
if request.ExcludeForDomain != nil && request.ExcludeForDomain.MatchAny(strings.ToLower(domain)) {
|
||||
return false
|
||||
}
|
||||
if request.ExcludeForIP != nil && destination.Address.Family().IsIP() && request.ExcludeForIP.Match(destination.Address.IP()) {
|
||||
return false
|
||||
}
|
||||
protocolString := result.Protocol()
|
||||
if resComp, ok := result.(SnifferResultComposite); ok {
|
||||
protocolString = resComp.ProtocolForDomainResult()
|
||||
|
||||
@@ -23,5 +23,12 @@ func BuildSniffingRequest(config *SniffingConfig) (session.SniffingRequest, erro
|
||||
}
|
||||
request.ExcludeForDomain = excludeForDomain
|
||||
}
|
||||
if len(config.IpsExcluded) > 0 {
|
||||
excludeForIP, err := geodata.IPReg.BuildIPMatcher(config.IpsExcluded)
|
||||
if err != nil {
|
||||
return session.SniffingRequest{}, err
|
||||
}
|
||||
request.ExcludeForIP = excludeForIP
|
||||
}
|
||||
return request, nil
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ type SniffingConfig struct {
|
||||
// Supported values are "http", "tls", "fakedns".
|
||||
DestinationOverride []string `protobuf:"bytes,2,rep,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"`
|
||||
DomainsExcluded []*geodata.DomainRule `protobuf:"bytes,3,rep,name=domains_excluded,json=domainsExcluded,proto3" json:"domains_excluded,omitempty"`
|
||||
IpsExcluded []*geodata.IPRule `protobuf:"bytes,6,rep,name=ips_excluded,json=ipsExcluded,proto3" json:"ips_excluded,omitempty"`
|
||||
// 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
|
||||
// message.
|
||||
@@ -129,6 +130,13 @@ func (x *SniffingConfig) GetDomainsExcluded() []*geodata.DomainRule {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SniffingConfig) GetIpsExcluded() []*geodata.IPRule {
|
||||
if x != nil {
|
||||
return x.IpsExcluded
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SniffingConfig) GetMetadataOnly() bool {
|
||||
if x != nil {
|
||||
return x.MetadataOnly
|
||||
@@ -479,11 +487,12 @@ var File_app_proxyman_config_proto protoreflect.FileDescriptor
|
||||
const file_app_proxyman_config_proto_rawDesc = "" +
|
||||
"\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\"\xed\x01\n" +
|
||||
"\rInboundConfig\"\xad\x02\n" +
|
||||
"\x0eSniffingConfig\x12\x18\n" +
|
||||
"\aenabled\x18\x01 \x01(\bR\aenabled\x121\n" +
|
||||
"\x14destination_override\x18\x02 \x03(\tR\x13destinationOverride\x12J\n" +
|
||||
"\x10domains_excluded\x18\x03 \x03(\v2\x1f.xray.common.geodata.DomainRuleR\x0fdomainsExcluded\x12#\n" +
|
||||
"\x10domains_excluded\x18\x03 \x03(\v2\x1f.xray.common.geodata.DomainRuleR\x0fdomainsExcluded\x12>\n" +
|
||||
"\fips_excluded\x18\x06 \x03(\v2\x1b.xray.common.geodata.IPRuleR\vipsExcluded\x12#\n" +
|
||||
"\rmetadata_only\x18\x04 \x01(\bR\fmetadataOnly\x12\x1d\n" +
|
||||
"\n" +
|
||||
"route_only\x18\x05 \x01(\bR\trouteOnly\"\xe5\x02\n" +
|
||||
@@ -534,31 +543,33 @@ var file_app_proxyman_config_proto_goTypes = []any{
|
||||
(*SenderConfig)(nil), // 5: xray.app.proxyman.SenderConfig
|
||||
(*MultiplexingConfig)(nil), // 6: xray.app.proxyman.MultiplexingConfig
|
||||
(*geodata.DomainRule)(nil), // 7: xray.common.geodata.DomainRule
|
||||
(*net.PortList)(nil), // 8: xray.common.net.PortList
|
||||
(*net.IPOrDomain)(nil), // 9: xray.common.net.IPOrDomain
|
||||
(*internet.StreamConfig)(nil), // 10: xray.transport.internet.StreamConfig
|
||||
(*serial.TypedMessage)(nil), // 11: xray.common.serial.TypedMessage
|
||||
(*internet.ProxyConfig)(nil), // 12: xray.transport.internet.ProxyConfig
|
||||
(internet.DomainStrategy)(0), // 13: xray.transport.internet.DomainStrategy
|
||||
(*geodata.IPRule)(nil), // 8: xray.common.geodata.IPRule
|
||||
(*net.PortList)(nil), // 9: xray.common.net.PortList
|
||||
(*net.IPOrDomain)(nil), // 10: xray.common.net.IPOrDomain
|
||||
(*internet.StreamConfig)(nil), // 11: xray.transport.internet.StreamConfig
|
||||
(*serial.TypedMessage)(nil), // 12: xray.common.serial.TypedMessage
|
||||
(*internet.ProxyConfig)(nil), // 13: xray.transport.internet.ProxyConfig
|
||||
(internet.DomainStrategy)(0), // 14: xray.transport.internet.DomainStrategy
|
||||
}
|
||||
var file_app_proxyman_config_proto_depIdxs = []int32{
|
||||
7, // 0: xray.app.proxyman.SniffingConfig.domains_excluded:type_name -> xray.common.geodata.DomainRule
|
||||
8, // 1: xray.app.proxyman.ReceiverConfig.port_list:type_name -> xray.common.net.PortList
|
||||
9, // 2: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain
|
||||
10, // 3: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
||||
1, // 4: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig
|
||||
11, // 5: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage
|
||||
11, // 6: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
|
||||
9, // 7: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain
|
||||
10, // 8: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
||||
12, // 9: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
|
||||
6, // 10: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
|
||||
13, // 11: xray.app.proxyman.SenderConfig.target_strategy:type_name -> xray.transport.internet.DomainStrategy
|
||||
12, // [12:12] is the sub-list for method output_type
|
||||
12, // [12:12] is the sub-list for method input_type
|
||||
12, // [12:12] is the sub-list for extension type_name
|
||||
12, // [12:12] is the sub-list for extension extendee
|
||||
0, // [0:12] is the sub-list for field type_name
|
||||
8, // 1: xray.app.proxyman.SniffingConfig.ips_excluded:type_name -> xray.common.geodata.IPRule
|
||||
9, // 2: xray.app.proxyman.ReceiverConfig.port_list:type_name -> xray.common.net.PortList
|
||||
10, // 3: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain
|
||||
11, // 4: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
||||
1, // 5: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig
|
||||
12, // 6: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage
|
||||
12, // 7: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
|
||||
10, // 8: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain
|
||||
11, // 9: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
||||
13, // 10: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
|
||||
6, // 11: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
|
||||
14, // 12: xray.app.proxyman.SenderConfig.target_strategy:type_name -> xray.transport.internet.DomainStrategy
|
||||
13, // [13:13] is the sub-list for method output_type
|
||||
13, // [13:13] is the sub-list for method input_type
|
||||
13, // [13:13] is the sub-list for extension type_name
|
||||
13, // [13:13] is the sub-list for extension extendee
|
||||
0, // [0:13] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_app_proxyman_config_proto_init() }
|
||||
|
||||
@@ -24,6 +24,8 @@ message SniffingConfig {
|
||||
|
||||
repeated xray.common.geodata.DomainRule domains_excluded = 3;
|
||||
|
||||
repeated xray.common.geodata.IPRule ips_excluded = 6;
|
||||
|
||||
// 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
|
||||
// message.
|
||||
|
||||
@@ -80,6 +80,7 @@ type Outbound struct {
|
||||
// SniffingRequest controls the behavior of content sniffing. They are from inbound config. Read-only
|
||||
type SniffingRequest struct {
|
||||
ExcludeForDomain geodata.DomainMatcher
|
||||
ExcludeForIP geodata.IPMatcher
|
||||
OverrideDestinationForProtocol []string
|
||||
Enabled bool
|
||||
MetadataOnly bool
|
||||
|
||||
@@ -55,37 +55,44 @@ type SniffingConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
DestOverride StringList `json:"destOverride"`
|
||||
DomainsExcluded StringList `json:"domainsExcluded"`
|
||||
IPsExcluded StringList `json:"ipsExcluded"`
|
||||
MetadataOnly bool `json:"metadataOnly"`
|
||||
RouteOnly bool `json:"routeOnly"`
|
||||
}
|
||||
|
||||
// Build implements Buildable.
|
||||
func (c *SniffingConfig) Build() (*proxyman.SniffingConfig, error) {
|
||||
var p []string
|
||||
var protocols []string
|
||||
for _, protocol := range c.DestOverride {
|
||||
switch strings.ToLower(protocol) {
|
||||
case "http":
|
||||
p = append(p, "http")
|
||||
protocols = append(protocols, "http")
|
||||
case "tls", "https", "ssl":
|
||||
p = append(p, "tls")
|
||||
protocols = append(protocols, "tls")
|
||||
case "quic":
|
||||
p = append(p, "quic")
|
||||
protocols = append(protocols, "quic")
|
||||
case "fakedns", "fakedns+others":
|
||||
p = append(p, "fakedns")
|
||||
protocols = append(protocols, "fakedns")
|
||||
default:
|
||||
return nil, errors.New("unknown protocol: ", protocol)
|
||||
}
|
||||
}
|
||||
|
||||
d, err := geodata.ParseDomainRules(c.DomainsExcluded, geodata.Domain_Substr)
|
||||
domains, err := geodata.ParseDomainRules(c.DomainsExcluded, geodata.Domain_Substr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ips, err := geodata.ParseIPRules(c.IPsExcluded)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &proxyman.SniffingConfig{
|
||||
Enabled: c.Enabled,
|
||||
DestinationOverride: p,
|
||||
DomainsExcluded: d,
|
||||
DestinationOverride: protocols,
|
||||
DomainsExcluded: domains,
|
||||
IpsExcluded: ips,
|
||||
MetadataOnly: c.MetadataOnly,
|
||||
RouteOnly: c.RouteOnly,
|
||||
}, nil
|
||||
|
||||
@@ -163,6 +163,7 @@ func TestSniffingConfig_Build(t *testing.T) {
|
||||
Enabled: true,
|
||||
DestOverride: StringList{"http", "tls"},
|
||||
DomainsExcluded: StringList{"full:api.example.com", "domain:blocked.example", "regexp:^test[0-9]+\\.internal$"},
|
||||
IPsExcluded: StringList{"192.168.1.1", "2001:db8::/32"},
|
||||
MetadataOnly: true,
|
||||
RouteOnly: true,
|
||||
}
|
||||
@@ -181,6 +182,9 @@ func TestSniffingConfig_Build(t *testing.T) {
|
||||
if len(built.DomainsExcluded) != 3 {
|
||||
t.Fatalf("SniffingConfig.Build() produced %d domain rules", len(built.DomainsExcluded))
|
||||
}
|
||||
if len(built.IpsExcluded) != 2 {
|
||||
t.Fatalf("SniffingConfig.Build() produced %d ip rules", len(built.IpsExcluded))
|
||||
}
|
||||
|
||||
want := []struct {
|
||||
ruleType geodata.Domain_Type
|
||||
@@ -199,6 +203,23 @@ func TestSniffingConfig_Build(t *testing.T) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
wantIPs := []struct {
|
||||
ip []byte
|
||||
prefix uint32
|
||||
}{
|
||||
{ip: []byte(net.ParseAddress("192.168.1.1").IP()), prefix: 32},
|
||||
{ip: []byte(net.ParseAddress("2001:db8::").IP()), prefix: 32},
|
||||
}
|
||||
for i, tc := range wantIPs {
|
||||
rule := built.IpsExcluded[i].GetCustom()
|
||||
if rule == nil {
|
||||
t.Fatalf("SniffingConfig.Build() produced a non-custom ip rule at index %d", i)
|
||||
}
|
||||
if !reflect.DeepEqual(rule.Ip, tc.ip) || rule.Prefix != tc.prefix {
|
||||
t.Fatalf("SniffingConfig.Build() produced wrong ip rule at index %d: got (%v, %d), want (%v, %d)", i, rule.Ip, rule.Prefix, tc.ip, tc.prefix)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMuxConfig_Build(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user