You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by sp...@apache.org on 2022/11/22 06:29:56 UTC

[apisix] branch master updated: feat: add method that parse ip from /etc/hosts in high priority (#8270)

This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new 6dbf9761e feat: add method that parse ip from /etc/hosts in high priority (#8270)
6dbf9761e is described below

commit 6dbf9761e5d8851fef8b2fd8262d6d7cf3000f78
Author: MaChao <10...@qq.com>
AuthorDate: Tue Nov 22 14:29:49 2022 +0800

    feat: add method that parse ip from /etc/hosts in high priority (#8270)
    
    Co-authored-by: MaChao <ch...@transwarp.io>
    Fixes https://github.com/apache/apisix/issues/5233
---
 apisix/core/resolver.lua   |  39 +++++++++++-
 t/core/resolver.t          | 151 +++++++++++++++++++++++++++++++++++++++++++++
 t/node/upstream-node-dns.t |  52 ++++++++--------
 3 files changed, 213 insertions(+), 29 deletions(-)

diff --git a/apisix/core/resolver.lua b/apisix/core/resolver.lua
index 056fbf806..3568a9762 100644
--- a/apisix/core/resolver.lua
+++ b/apisix/core/resolver.lua
@@ -19,15 +19,32 @@
 --
 -- @module core.resolver
 
-local json = require("apisix.core.json")
-local log = require("apisix.core.log")
-local utils = require("apisix.core.utils")
+local json           = require("apisix.core.json")
+local log            = require("apisix.core.log")
+local utils          = require("apisix.core.utils")
+local dns_utils      = require("resty.dns.utils")
+local config_local   = require("apisix.core.config_local")
+
+
+local HOSTS_IP_MATCH_CACHE = {}
 
 
 local _M = {}
 
 
+local function init_hosts_ip()
+    local hosts, err = dns_utils.parseHosts()
+    if not hosts then
+        return hosts, err
+    end
+    HOSTS_IP_MATCH_CACHE = hosts
+end
+
+
 function _M.init_resolver(args)
+    --  initialize /etc/hosts
+    init_hosts_ip()
+
     local dns_resolver = args and args["dns_resolver"]
     utils.set_resolver(dns_resolver)
     log.info("dns resolver ", json.delay_encode(dns_resolver, true))
@@ -42,6 +59,22 @@ end
 -- @usage
 -- local ip, err = core.resolver.parse_domain("apache.org") -- "198.18.10.114"
 function _M.parse_domain(host)
+    local rev = HOSTS_IP_MATCH_CACHE[host]
+    local enable_ipv6 = config_local.local_conf().apisix.enable_ipv6
+    if rev then
+        -- use ipv4 in high priority
+        local ip = rev["ipv4"]
+        if enable_ipv6 and not ip then
+            ip = rev["ipv6"]
+        end
+        if ip then
+            -- meet test case
+            log.info("dns resolve ", host, ", result: ", json.delay_encode(ip))
+            log.info("dns resolver domain: ", host, " to ", ip)
+            return ip
+        end
+    end
+
     local ip_info, err = utils.dns_parse(host)
     if not ip_info then
         log.error("failed to parse domain: ", host, ", error: ",err)
diff --git a/t/core/resolver.t b/t/core/resolver.t
new file mode 100644
index 000000000..06d2470b3
--- /dev/null
+++ b/t/core/resolver.t
@@ -0,0 +1,151 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+use t::APISIX 'no_plan';
+
+repeat_each(1);
+no_long_string();
+no_root_location();
+log_level("info");
+
+add_block_preprocessor(sub {
+    my ($block) = @_;
+
+    if (!$block->request) {
+        $block->set_value("request", "GET /t");
+    }
+
+    if (!$block->no_error_log && !$block->error_log) {
+        $block->set_value("no_error_log", "[error]");
+    }
+});
+
+run_tests;
+
+__DATA__
+
+=== TEST 1: resolve host from /etc/hosts
+--- config
+    location /t {
+        content_by_lua_block {
+            local core = require("apisix.core")
+            local resolver = require("apisix.core.resolver")
+            local domain = "localhost"
+            local ip_info, err = resolver.parse_domain(domain)
+            if not ip_info then
+                core.log.error("failed to parse domain: ", domain, ", error: ",err)
+                return
+            end
+            ngx.say("ip_info: ", require("toolkit.json").encode(ip_info))
+        }
+    }
+--- response_body
+ip_info: "127.0.0.1"
+
+
+
+=== TEST 2: resolve host from dns
+--- config
+    location /t {
+        content_by_lua_block {
+            local core = require("apisix.core")
+            local resolver = require("apisix.core.resolver")
+            local domain = "apisix.apache.org"
+            resolver.parse_domain = function(domain) -- mock: resolver parser
+
+                if domain == "apisix.apache.org" then
+                    return {address = "127.0.0.2" }
+                end
+                error("unknown domain: " .. domain)
+            end
+            local ip_info, err = resolver.parse_domain(domain)
+            if not ip_info then
+                core.log.error("failed to parse domain: ", domain, ", error: ",err)
+                return
+            end
+            ngx.say("ip_info: ", require("toolkit.json").encode(ip_info))
+        }
+    }
+--- response_body
+ip_info: {"address":"127.0.0.2"}
+
+
+
+=== TEST 3: there is no mapping in /etc/hosts and dns
+--- config
+    location /t {
+        content_by_lua_block {
+            local core = require("apisix.core")
+            local resolver = require("apisix.core.resolver")
+            local domain = "abc1.test"
+            resolver.parse_domain(domain)
+        }
+    }
+--- error_log
+failed to parse domain
+
+
+
+=== TEST 4: test dns config with ipv6 enable
+--- yaml_config
+apisix:
+  enable_ipv6: true
+--- config
+    location /t {
+        content_by_lua_block {
+            local core = require("apisix.core")
+            local resolver = require("apisix.core.resolver")
+            local domain = "localhost6"
+            resolver.parse_domain = function(domain)  -- mock: resolver parse_domain
+                 if domain == "localhost6" then
+                    return {address = "::1" }
+                 end
+                 error("unknown domain: " .. domain)
+
+            end
+            local ip_info, err = resolver.parse_domain(domain)
+            if not ip_info then
+                core.log.error("failed to parse domain: ", domain, ", error: ",err)
+                return
+            end
+            ngx.say("ip_info: ", require("toolkit.json").encode(ip_info))
+        }
+    }
+--- response_body
+ip_info: {"address":"::1"}
+
+
+
+=== TEST 5: test dns config with ipv6 disable
+--- yaml_config
+apisix:
+  enable_ipv6: false
+--- config
+    location /t {
+        content_by_lua_block {
+            local core = require("apisix.core")
+            local resolver = require("apisix.core.resolver")
+            local domain = "localhost6"
+            local ip_info, err = resolver.parse_domain(domain)
+            if not ip_info then
+                core.log.error("failed to parse domain: ", domain, ", error: ",err)
+                return
+            end
+            ngx.say("ip_info: ", require("toolkit.json").encode(ip_info))
+        }
+    }
+--- error_log
+failed to parse domain
diff --git a/t/node/upstream-node-dns.t b/t/node/upstream-node-dns.t
index f6f8560f1..b8dbb0bce 100644
--- a/t/node/upstream-node-dns.t
+++ b/t/node/upstream-node-dns.t
@@ -35,7 +35,7 @@ __DATA__
                 [[{
                     "upstream": {
                         "nodes": {
-                            "test.com:1980": 1
+                            "test1.com:1980": 1
                         },
                         "type": "roundrobin"
                     },
@@ -65,7 +65,7 @@ passed
 
     local utils = require("apisix.core.utils")
     utils.dns_parse = function (domain)  -- mock: DNS parser
-        if domain == "test.com" then
+        if domain == "test1.com" then
             return {address = "127.0.0.2"}
         end
 
@@ -90,7 +90,7 @@ hello world
     utils.dns_parse = function (domain)  -- mock: DNS parser
         count = count + 1
 
-        if domain == "test.com" then
+        if domain == "test1.com" then
             return {address = "127.0.0." .. count}
         end
 
@@ -109,10 +109,10 @@ location /t {
 --- request
 GET /t
 --- grep_error_log eval
-qr/dns resolver domain: test.com to 127.0.0.\d|call \/hello|proxy request to 127.0.0.\d:1980/
+qr/dns resolver domain: test1.com to 127.0.0.\d|call \/hello|proxy request to 127.0.0.\d:1980/
 --- grep_error_log_out
 call /hello
-dns resolver domain: test.com to 127.0.0.1
+dns resolver domain: test1.com to 127.0.0.1
 proxy request to 127.0.0.1:1980
 
 
@@ -127,7 +127,7 @@ proxy request to 127.0.0.1:1980
                 [[{
                     "upstream": {
                         "nodes": {
-                            "test.com:1980": 1,
+                            "test1.com:1980": 1,
                             "test2.com:1980": 1
                         },
                         "type": "roundrobin"
@@ -158,7 +158,7 @@ passed
 
     local utils = require("apisix.core.utils")
     utils.dns_parse = function (domain)  -- mock: DNS parser
-        if domain == "test.com" or domain == "test2.com" then
+        if domain == "test1.com" or domain == "test2.com" then
             return {address = "127.0.0.2"}
         end
 
@@ -183,7 +183,7 @@ hello world
     utils.dns_parse = function (domain)  -- mock: DNS parser
         count = count + 1
 
-        if domain == "test.com" or domain == "test2.com" then
+        if domain == "test1.com" or domain == "test2.com" then
             return {address = "127.0.0." .. count}
         end
 
@@ -206,10 +206,10 @@ GET /t
 qr/dns resolver domain: \w+.com to 127.0.0.\d|call \/hello|proxy request to 127.0.0.\d:1980/
 --- grep_error_log_out eval
 qr/call \/hello(
-dns resolver domain: test.com to 127.0.0.1
+dns resolver domain: test1.com to 127.0.0.1
 dns resolver domain: test2.com to 127.0.0.2|
 dns resolver domain: test2.com to 127.0.0.1
-dns resolver domain: test.com to 127.0.0.2)
+dns resolver domain: test1.com to 127.0.0.2)
 proxy request to 127.0.0.[12]:1980
 /
 
@@ -224,7 +224,7 @@ proxy request to 127.0.0.[12]:1980
                  ngx.HTTP_PUT,
                  [[{
                     "nodes": {
-                        "test.com:1980": 1
+                        "test1.com:1980": 1
                     },
                     "type": "roundrobin",
                     "desc": "new upstream"
@@ -282,7 +282,7 @@ passed
     utils.dns_parse = function (domain)  -- mock: DNS parser
         count = count + 1
 
-        if domain == "test.com" then
+        if domain == "test1.com" then
             return {address = "127.0.0." .. count}
         end
 
@@ -301,10 +301,10 @@ location /t {
 --- request
 GET /t
 --- grep_error_log eval
-qr/dns resolver domain: test.com to 127.0.0.\d|call \/hello|proxy request to 127.0.0.\d:1980/
+qr/dns resolver domain: test1.com to 127.0.0.\d|call \/hello|proxy request to 127.0.0.\d:1980/
 --- grep_error_log_out
 call /hello
-dns resolver domain: test.com to 127.0.0.1
+dns resolver domain: test1.com to 127.0.0.1
 proxy request to 127.0.0.1:1980
 
 
@@ -318,7 +318,7 @@ proxy request to 127.0.0.1:1980
                  ngx.HTTP_PUT,
                  [[{
                     "nodes": {
-                        "test.com:1980": 1,
+                        "test1.com:1980": 1,
                         "test2.com:1980": 1
                     },
                     "type": "roundrobin",
@@ -351,7 +351,7 @@ passed
     utils.dns_parse = function (domain)  -- mock: DNS parser
         count = count + 1
 
-        if domain == "test.com" or domain == "test2.com" then
+        if domain == "test1.com" or domain == "test2.com" then
             return {address = "127.0.0." .. count}
         end
 
@@ -373,10 +373,10 @@ GET /t
 qr/dns resolver domain: \w+.com to 127.0.0.\d|call \/hello|proxy request to 127.0.0.\d:1980/
 --- grep_error_log_out eval
 qr/call \/hello(
-dns resolver domain: test.com to 127.0.0.1
+dns resolver domain: test1.com to 127.0.0.1
 dns resolver domain: test2.com to 127.0.0.2|
 dns resolver domain: test2.com to 127.0.0.1
-dns resolver domain: test.com to 127.0.0.2)
+dns resolver domain: test1.com to 127.0.0.2)
 proxy request to 127.0.0.[12]:1980
 /
 
@@ -392,7 +392,7 @@ proxy request to 127.0.0.[12]:1980
     local utils = require("apisix.core.utils")
     local count = 1
     utils.dns_parse = function (domain)  -- mock: DNS parser
-        if domain == "test.com" or domain == "test2.com" then
+        if domain == "test1.com" or domain == "test2.com" then
             return {address = "127.0.0.1"}
         end
 
@@ -414,10 +414,10 @@ GET /t
 qr/dns resolver domain: \w+.com to 127.0.0.\d|call \/hello|proxy request to 127.0.0.\d:1980/
 --- grep_error_log_out eval
 qr/call \/hello(
-dns resolver domain: test.com to 127.0.0.1
+dns resolver domain: test1.com to 127.0.0.1
 dns resolver domain: test2.com to 127.0.0.1|
 dns resolver domain: test2.com to 127.0.0.1
-dns resolver domain: test.com to 127.0.0.1)
+dns resolver domain: test1.com to 127.0.0.1)
 proxy request to 127.0.0.1:1980
 /
 
@@ -432,7 +432,7 @@ proxy request to 127.0.0.1:1980
                  ngx.HTTP_PUT,
                  [[{
                     "nodes": {
-                        "test.com:1980": 1,
+                        "test1.com:1980": 1,
                         "127.0.0.5:1981": 1
                     },
                     "type": "roundrobin",
@@ -464,7 +464,7 @@ passed
     local count = 0
     utils.dns_parse = function (domain)  -- mock: DNS parser
         count = count + 1
-        if domain == "test.com" or domain == "test2.com" then
+        if domain == "test1.com" or domain == "test2.com" then
             return {address = "127.0.0." .. count}
         end
 
@@ -486,7 +486,7 @@ GET /t
 qr/dns resolver domain: \w+.com to 127.0.0.\d|call \/hello|proxy request to 127.0.0.\d:198\d/
 --- grep_error_log_out eval
 qr/call \/hello
-dns resolver domain: test.com to 127.0.0.1
+dns resolver domain: test1.com to 127.0.0.1
 proxy request to 127.0.0.(1:1980|5:1981)
 /
 
@@ -502,7 +502,7 @@ proxy request to 127.0.0.(1:1980|5:1981)
                 [[{
                     "upstream": {
                         "nodes": {
-                            "test.com:1980": 1
+                            "test1.com:1980": 1
                         },
                         "type": "roundrobin"
                     },
@@ -534,7 +534,7 @@ passed
     local count = 0
     utils.dns_parse = function (domain)  -- mock: DNS parser
         count = count + 1
-        if domain == "test.com" then
+        if domain == "test1.com" then
             return {address = "127.0.0." .. count}
         end