Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/dispatcher/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
7 changes: 7 additions & 0 deletions app/proxyman/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
59 changes: 35 additions & 24 deletions app/proxyman/config.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions app/proxyman/config.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions common/session/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 15 additions & 8 deletions infra/conf/xray.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 21 additions & 0 deletions infra/conf/xray_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand All @@ -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
Expand All @@ -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) {
Expand Down