Skip to content

Commit 961c352

Browse files
authored
DNS: Fix parse domain and geoip (#5499)
Fixes #5488 (comment)
1 parent c715154 commit 961c352

File tree

5 files changed

+117
-22
lines changed

5 files changed

+117
-22
lines changed

app/dns/dns.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,15 @@ import (
1212
"sync"
1313
"time"
1414

15+
router "github.com/xtls/xray-core/app/router"
1516
"github.com/xtls/xray-core/common"
1617
"github.com/xtls/xray-core/common/errors"
1718
"github.com/xtls/xray-core/common/net"
19+
"github.com/xtls/xray-core/common/platform/filesystem"
1820
"github.com/xtls/xray-core/common/session"
1921
"github.com/xtls/xray-core/common/strmatcher"
2022
"github.com/xtls/xray-core/features/dns"
23+
"google.golang.org/protobuf/proto"
2124
)
2225

2326
// DNS is a DNS rely server.
@@ -97,6 +100,25 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
97100
}
98101

99102
for _, ns := range config.NameServer {
103+
if runtime.GOOS != "windows" && runtime.GOOS != "wasm" {
104+
err := parseDomains(ns)
105+
if err != nil {
106+
return nil, errors.New("failed to parse dns domain rules: ").Base(err)
107+
}
108+
109+
expectedGeoip, err := router.GetGeoIPList(ns.ExpectedGeoip)
110+
if err != nil {
111+
return nil, errors.New("failed to parse dns expectIPs rules: ").Base(err)
112+
}
113+
ns.ExpectedGeoip = expectedGeoip
114+
115+
unexpectedGeoip, err := router.GetGeoIPList(ns.UnexpectedGeoip)
116+
if err != nil {
117+
return nil, errors.New("failed to parse dns unexpectedGeoip rules: ").Base(err)
118+
}
119+
ns.UnexpectedGeoip = unexpectedGeoip
120+
121+
}
100122
domainRuleCount += len(ns.PrioritizedDomain)
101123
}
102124

@@ -580,3 +602,76 @@ func detectGUIPlatform() bool {
580602
}
581603
return false
582604
}
605+
606+
func parseDomains(ns *NameServer) error {
607+
pureDomains := []*router.Domain{}
608+
609+
// convert to pure domain
610+
for _, pd := range ns.PrioritizedDomain {
611+
pureDomains = append(pureDomains, &router.Domain{
612+
Type: router.Domain_Type(pd.Type),
613+
Value: pd.Domain,
614+
})
615+
}
616+
617+
domainList := []*router.Domain{}
618+
for _, domain := range pureDomains {
619+
val := strings.Split(domain.Value, "_")
620+
if len(val) >= 2 {
621+
622+
fileName := val[0]
623+
code := val[1]
624+
625+
bs, err := filesystem.ReadAsset(fileName)
626+
if err != nil {
627+
return errors.New("failed to load file: ", fileName).Base(err)
628+
}
629+
bs = filesystem.Find(bs, []byte(code))
630+
var geosite router.GeoSite
631+
632+
if err := proto.Unmarshal(bs, &geosite); err != nil {
633+
return errors.New("failed Unmarshal :").Base(err)
634+
}
635+
636+
// parse attr
637+
if len(val) == 3 {
638+
siteWithAttr := strings.Split(val[2], ",")
639+
attrs := router.ParseAttrs(siteWithAttr)
640+
if !attrs.IsEmpty() {
641+
filteredDomains := make([]*router.Domain, 0, len(pureDomains))
642+
for _, domain := range geosite.Domain {
643+
if attrs.Match(domain) {
644+
filteredDomains = append(filteredDomains, domain)
645+
}
646+
}
647+
geosite.Domain = filteredDomains
648+
}
649+
650+
}
651+
652+
domainList = append(domainList, geosite.Domain...)
653+
654+
// update ns.OriginalRules Size
655+
ruleTag := strings.Join(val, ":")
656+
for i, oRule := range ns.OriginalRules {
657+
if oRule.Rule == strings.ToLower(ruleTag) {
658+
ns.OriginalRules[i].Size = uint32(len(geosite.Domain))
659+
}
660+
}
661+
662+
} else {
663+
domainList = append(domainList, domain)
664+
}
665+
}
666+
667+
// convert back to NameServer_PriorityDomain
668+
ns.PrioritizedDomain = []*NameServer_PriorityDomain{}
669+
for _, pd := range domainList {
670+
ns.PrioritizedDomain = append(ns.PrioritizedDomain, &NameServer_PriorityDomain{
671+
Type: ToDomainMatchingType(pd.Type),
672+
Domain: pd.Value,
673+
})
674+
}
675+
676+
return nil
677+
}

app/dns/dns_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ func TestIPMatch(t *testing.T) {
541541
},
542542
ExpectedGeoip: []*router.GeoIP{
543543
{
544-
CountryCode: "local",
544+
// local
545545
Cidr: []*router.CIDR{
546546
{
547547
// inner ip, will not match
@@ -565,7 +565,7 @@ func TestIPMatch(t *testing.T) {
565565
},
566566
ExpectedGeoip: []*router.GeoIP{
567567
{
568-
CountryCode: "test",
568+
// test
569569
Cidr: []*router.CIDR{
570570
{
571571
Ip: []byte{8, 8, 8, 8},
@@ -574,7 +574,7 @@ func TestIPMatch(t *testing.T) {
574574
},
575575
},
576576
{
577-
CountryCode: "test",
577+
// test
578578
Cidr: []*router.CIDR{
579579
{
580580
Ip: []byte{8, 8, 8, 4},
@@ -669,7 +669,7 @@ func TestLocalDomain(t *testing.T) {
669669
},
670670
ExpectedGeoip: []*router.GeoIP{
671671
{ // Will match localhost, localhost-a and localhost-b,
672-
CountryCode: "local",
672+
// local
673673
Cidr: []*router.CIDR{
674674
{Ip: []byte{127, 0, 0, 2}, Prefix: 32},
675675
{Ip: []byte{127, 0, 0, 3}, Prefix: 32},

app/dns/nameserver.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,3 +297,18 @@ func ResolveIpOptionOverride(queryStrategy QueryStrategy, ipOption dns.IPOption)
297297
return ipOption
298298
}
299299
}
300+
301+
func ToDomainMatchingType(t router.Domain_Type) DomainMatchingType {
302+
switch t {
303+
case router.Domain_Domain:
304+
return DomainMatchingType_Subdomain
305+
case router.Domain_Full:
306+
return DomainMatchingType_Full
307+
case router.Domain_Plain:
308+
return DomainMatchingType_Keyword
309+
case router.Domain_Regex:
310+
return DomainMatchingType_Regex
311+
default:
312+
panic("unknown domain type")
313+
}
314+
}

app/router/config.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
7979
geoip := rr.Geoip
8080
if runtime.GOOS != "windows" && runtime.GOOS != "wasm" {
8181
var err error
82-
geoip, err = getGeoIPList(rr.Geoip)
82+
geoip, err = GetGeoIPList(rr.Geoip)
8383
if err != nil {
8484
return nil, errors.New("failed to build geoip from mmap").Base(err)
8585
}
@@ -188,7 +188,7 @@ func (br *BalancingRule) Build(ohm outbound.Manager, dispatcher routing.Dispatch
188188
}
189189
}
190190

191-
func getGeoIPList(ips []*GeoIP) ([]*GeoIP, error) {
191+
func GetGeoIPList(ips []*GeoIP) ([]*GeoIP, error) {
192192
geoipList := []*GeoIP{}
193193
for _, ip := range ips {
194194
if ip.CountryCode != "" {

infra/conf/dns.go

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -80,21 +80,6 @@ func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
8080
return errors.New("failed to parse name server: ", string(data))
8181
}
8282

83-
func toDomainMatchingType(t router.Domain_Type) dns.DomainMatchingType {
84-
switch t {
85-
case router.Domain_Domain:
86-
return dns.DomainMatchingType_Subdomain
87-
case router.Domain_Full:
88-
return dns.DomainMatchingType_Full
89-
case router.Domain_Plain:
90-
return dns.DomainMatchingType_Keyword
91-
case router.Domain_Regex:
92-
return dns.DomainMatchingType_Regex
93-
default:
94-
panic("unknown domain type")
95-
}
96-
}
97-
9883
func (c *NameServerConfig) Build() (*dns.NameServer, error) {
9984
if c.Address == nil {
10085
return nil, errors.New("NameServer address is not specified.")
@@ -111,7 +96,7 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) {
11196

11297
for _, pd := range parsedDomain {
11398
domains = append(domains, &dns.NameServer_PriorityDomain{
114-
Type: toDomainMatchingType(pd.Type),
99+
Type: dns.ToDomainMatchingType(pd.Type),
115100
Domain: pd.Value,
116101
})
117102
}

0 commit comments

Comments
 (0)