From 7cf25970ded96df6ce3c6557c4e4deaac6f43989 Mon Sep 17 00:00:00 2001 From: Meow <197331664+Meo597@users.noreply.github.com> Date: Sun, 26 Apr 2026 00:07:04 +0800 Subject: [PATCH] IPMatcher: Fix full CIDR issue (#5971) Fixes https://github.com/XTLS/Xray-core/issues/5977 --- common/geodata/ip_matcher.go | 11 +++- common/geodata/ip_matcher_test.go | 84 +++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/common/geodata/ip_matcher.go b/common/geodata/ip_matcher.go index 315ce040..abacf109 100644 --- a/common/geodata/ip_matcher.go +++ b/common/geodata/ip_matcher.go @@ -915,24 +915,31 @@ func (f *IPSetFactory) createFrom(yield func(func(*CIDR)) error) (*IPSet, error) return nil, errors.New("failed to build IPv6 set").Base(err) } + var has4, has6 bool var max4, max6 int for _, p := range ipv4.Prefixes() { + has4 = true if b := p.Bits(); b > max4 { max4 = b } } for _, p := range ipv6.Prefixes() { + has6 = true if b := p.Bits(); b > max6 { max6 = b } } - if max4 == 0 { + if !has4 { max4 = 0xff + } else if max4 == 0 { + max4 = 0xfe } - if max6 == 0 { + if !has6 { max6 = 0xff + } else if max6 == 0 { + max6 = 0xfe } return &IPSet{ipv4: ipv4, ipv6: ipv6, max4: uint8(max4), max6: uint8(max6)}, nil diff --git a/common/geodata/ip_matcher_test.go b/common/geodata/ip_matcher_test.go index d1dc2de2..829c455d 100644 --- a/common/geodata/ip_matcher_test.go +++ b/common/geodata/ip_matcher_test.go @@ -97,6 +97,90 @@ func TestIPMatcher(t *testing.T) { } } +func TestIPMatcherFullCIDR4(t *testing.T) { + matcher := buildIPMatcher( + "0.0.0.0/0", + ) + + testCases := []struct { + Input string + Output bool + }{ + { + Input: "192.168.1.1", + Output: true, + }, + { + Input: "0.0.0.0", + Output: true, + }, + { + Input: "255.255.255.255", + Output: true, + }, + { + Input: "2001:cdba::3257:9652", + Output: false, + }, + { + Input: "::0", + Output: false, + }, + { + Input: "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + Output: false, + }, + } + + for _, test := range testCases { + if v := matcher.Match(xnet.ParseAddress(test.Input).IP()); v != test.Output { + t.Error("unexpected output: ", v, " for test case ", test) + } + } +} + +func TestIPMatcherFullCIDR6(t *testing.T) { + matcher := buildIPMatcher( + "::0/0", + ) + + testCases := []struct { + Input string + Output bool + }{ + { + Input: "192.168.1.1", + Output: false, + }, + { + Input: "0.0.0.0", + Output: false, + }, + { + Input: "255.255.255.255", + Output: false, + }, + { + Input: "2001:cdba::3257:9652", + Output: true, + }, + { + Input: "::0", + Output: true, + }, + { + Input: "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + Output: true, + }, + } + + for _, test := range testCases { + if v := matcher.Match(xnet.ParseAddress(test.Input).IP()); v != test.Output { + t.Error("unexpected output: ", v, " for test case ", test) + } + } +} + func TestIPMatcherRegression(t *testing.T) { matcher := buildIPMatcher( "98.108.20.0/22",