From 5922caff89117ca229fb97319fc0de5ff047bb34 Mon Sep 17 00:00:00 2001
From: patterniha <71074308+patterniha@users.noreply.github.com>
Date: Wed, 26 Mar 2025 15:48:58 +0330
Subject: [PATCH] DNS: Add `expectedIPs` as an alias of `expectIPs` (#4551)

https://github.com/XTLS/Xray-core/discussions/1903#discussioncomment-5543921
---
 app/dns/dns_test.go   |  6 +++---
 app/dns/nameserver.go | 18 ++++++++----------
 infra/conf/dns.go     | 15 +++++++++++----
 3 files changed, 22 insertions(+), 17 deletions(-)

diff --git a/app/dns/dns_test.go b/app/dns/dns_test.go
index ab985384..4bdc9ae3 100644
--- a/app/dns/dns_test.go
+++ b/app/dns/dns_test.go
@@ -785,7 +785,7 @@ func TestLocalDomain(t *testing.T) {
 		}
 	}
 
-	{ // Will match dotless:localhost, but not expectIPs: 127.0.0.2, 127.0.0.3, then matches at dotless:
+	{ // Will match dotless:localhost, but not expectedIPs: 127.0.0.2, 127.0.0.3, then matches at dotless:
 		ips, _, err := client.LookupIP("localhost", feature_dns.IPOption{
 			IPv4Enable: true,
 			IPv6Enable: true,
@@ -800,7 +800,7 @@ func TestLocalDomain(t *testing.T) {
 		}
 	}
 
-	{ // Will match dotless:localhost, and expectIPs: 127.0.0.2, 127.0.0.3
+	{ // Will match dotless:localhost, and expectedIPs: 127.0.0.2, 127.0.0.3
 		ips, _, err := client.LookupIP("localhost-a", feature_dns.IPOption{
 			IPv4Enable: true,
 			IPv6Enable: true,
@@ -815,7 +815,7 @@ func TestLocalDomain(t *testing.T) {
 		}
 	}
 
-	{ // Will match dotless:localhost, and expectIPs: 127.0.0.2, 127.0.0.3
+	{ // Will match dotless:localhost, and expectedIPs: 127.0.0.2, 127.0.0.3
 		ips, _, err := client.LookupIP("localhost-b", feature_dns.IPOption{
 			IPv4Enable: true,
 			IPv6Enable: true,
diff --git a/app/dns/nameserver.go b/app/dns/nameserver.go
index 774d87c3..1a5ab3b6 100644
--- a/app/dns/nameserver.go
+++ b/app/dns/nameserver.go
@@ -30,13 +30,13 @@ type Client struct {
 	clientIP           net.IP
 	skipFallback       bool
 	domains            []string
-	expectIPs          []*router.GeoIPMatcher
+	expectedIPs        []*router.GeoIPMatcher
 	allowUnexpectedIPs bool
 	tag                string
 	timeoutMs          time.Duration
 }
 
-var errExpectedIPNonMatch = errors.New("expectIPs not match")
+var errExpectedIPNonMatch = errors.New("expectedIPs not match")
 
 // NewServer creates a name server object according to the network destination url.
 func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dispatcher, queryStrategy QueryStrategy) (Server, error) {
@@ -165,18 +165,16 @@ func NewClient(
 			}
 		}
 
-		var timeoutMs time.Duration
+		var timeoutMs = 4000 * time.Millisecond
 		if ns.TimeoutMs > 0 {
 			timeoutMs = time.Duration(ns.TimeoutMs) * time.Millisecond
-		} else {
-			timeoutMs = 4000 * time.Millisecond
 		}
-
+		
 		client.server = server
 		client.clientIP = clientIP
 		client.skipFallback = ns.SkipFallback
 		client.domains = rules
-		client.expectIPs = matchers
+		client.expectedIPs = matchers
 		client.allowUnexpectedIPs = ns.AllowUnexpectedIPs
 		client.tag = ns.Tag
 		client.timeoutMs = timeoutMs
@@ -212,12 +210,12 @@ func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption
 
 // MatchExpectedIPs matches queried domain IPs with expected IPs and returns matched ones.
 func (c *Client) MatchExpectedIPs(domain string, ips []net.IP) ([]net.IP, error) {
-	if len(c.expectIPs) == 0 {
+	if len(c.expectedIPs) == 0 {
 		return ips, nil
 	}
 	newIps := []net.IP{}
 	for _, ip := range ips {
-		for _, matcher := range c.expectIPs {
+		for _, matcher := range c.expectedIPs {
 			if matcher.Match(ip) {
 				newIps = append(newIps, ip)
 				break
@@ -230,7 +228,7 @@ func (c *Client) MatchExpectedIPs(domain string, ips []net.IP) ([]net.IP, error)
 		}
 		return nil, errExpectedIPNonMatch
 	}
-	errors.LogDebug(context.Background(), "domain ", domain, " expectIPs ", newIps, " matched at server ", c.Name())
+	errors.LogDebug(context.Background(), "domain ", domain, " expectedIPs ", newIps, " matched at server ", c.Name())
 	return newIps, nil
 }
 
diff --git a/infra/conf/dns.go b/infra/conf/dns.go
index 20051447..607cbf07 100644
--- a/infra/conf/dns.go
+++ b/infra/conf/dns.go
@@ -17,7 +17,8 @@ type NameServerConfig struct {
 	Port               uint16     `json:"port"`
 	SkipFallback       bool       `json:"skipFallback"`
 	Domains            []string   `json:"domains"`
-	ExpectIPs          StringList `json:"expectIps"`
+	ExpectedIPs        StringList `json:"expectedIPs"`
+	ExpectIPs          StringList `json:"expectIPs"`
 	QueryStrategy      string     `json:"queryStrategy"`
 	AllowUnexpectedIPs bool       `json:"allowUnexpectedIps"`
 	Tag                string     `json:"tag"`
@@ -37,7 +38,8 @@ func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
 		Port               uint16     `json:"port"`
 		SkipFallback       bool       `json:"skipFallback"`
 		Domains            []string   `json:"domains"`
-		ExpectIPs          StringList `json:"expectIps"`
+		ExpectedIPs        StringList `json:"expectedIPs"`
+		ExpectIPs          StringList `json:"expectIPs"`
 		QueryStrategy      string     `json:"queryStrategy"`
 		AllowUnexpectedIPs bool       `json:"allowUnexpectedIps"`
 		Tag                string     `json:"tag"`
@@ -49,6 +51,7 @@ func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
 		c.Port = advanced.Port
 		c.SkipFallback = advanced.SkipFallback
 		c.Domains = advanced.Domains
+		c.ExpectedIPs = advanced.ExpectedIPs
 		c.ExpectIPs = advanced.ExpectIPs
 		c.QueryStrategy = advanced.QueryStrategy
 		c.AllowUnexpectedIPs = advanced.AllowUnexpectedIPs
@@ -101,9 +104,13 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) {
 		})
 	}
 
-	geoipList, err := ToCidrList(c.ExpectIPs)
+	var expectedIPs = c.ExpectedIPs
+	if len(expectedIPs) == 0 {
+		expectedIPs = c.ExpectIPs
+	}
+	geoipList, err := ToCidrList(expectedIPs)
 	if err != nil {
-		return nil, errors.New("invalid IP rule: ", c.ExpectIPs).Base(err)
+		return nil, errors.New("invalid IP rule: ", expectedIPs).Base(err)
 	}
 
 	var myClientIP []byte