Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: patch tcp.sock.connect to use our DNS resolver #4114

Merged
merged 3 commits into from
May 4, 2021
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
1 change: 1 addition & 0 deletions apisix/core.lua
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,6 @@ return {
dns_client = require("apisix.core.dns.client"),
etcd = require("apisix.core.etcd"),
tablepool = require("tablepool"),
resolver = require("apisix.core.resolver"),
empty_tab = {},
}
51 changes: 51 additions & 0 deletions apisix/core/resolver.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
--
-- 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.
--
local json = require("apisix.core.json")
local log = require("apisix.core.log")
local utils = require("apisix.core.utils")


local _M = {}


function _M.init_resolver(args)
local dns_resolver = args and args["dns_resolver"]
utils.set_resolver(dns_resolver)
log.info("dns resolver ", json.delay_encode(dns_resolver, true))
end


function _M.parse_domain(host)
local ip_info, err = utils.dns_parse(host)
if not ip_info then
log.error("failed to parse domain: ", host, ", error: ",err)
return nil, err
end

log.info("parse addr: ", json.delay_encode(ip_info))
log.info("resolver: ", json.delay_encode(utils.get_resolver()))
log.info("host: ", host)
if ip_info.address then
log.info("dns resolver domain: ", host, " to ", ip_info.address)
return ip_info.address
end

return nil, "failed to parse domain"
end


return _M
3 changes: 2 additions & 1 deletion apisix/core/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,10 @@ end
_M.dns_parse = dns_parse


function _M.set_resolver(resolvers)
local function set_resolver(resolvers)
dns_resolvers = resolvers
end
_M.set_resolver = set_resolver


function _M.get_resolver(resolvers)
Expand Down
30 changes: 2 additions & 28 deletions apisix/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,9 @@ if ngx.config.subsystem == "http" then
end
local load_balancer
local local_conf
local dns_resolver
local ver_header = "APISIX/" .. core.version.VERSION


local function parse_args(args)
dns_resolver = args and args["dns_resolver"]
core.utils.set_resolver(dns_resolver)
core.log.info("dns resolver", core.json.delay_encode(dns_resolver, true))
end


local _M = {version = 0.4}


Expand All @@ -71,7 +63,7 @@ function _M.http_init(args)
"maxrecord=8000", "sizemcode=64",
"maxmcode=4000", "maxirconst=1000")

parse_args(args)
core.resolver.init_resolver(args)
core.id.init()

local process = require("ngx.process")
Expand Down Expand Up @@ -154,24 +146,6 @@ function _M.http_ssl_phase()
end


local function parse_domain(host)
local ip_info, err = core.utils.dns_parse(host)
if not ip_info then
core.log.error("failed to parse domain: ", host, ", error: ",err)
return nil, err
end

core.log.info("parse addr: ", core.json.delay_encode(ip_info))
core.log.info("resolver: ", core.json.delay_encode(dns_resolver))
core.log.info("host: ", host)
if ip_info.address then
core.log.info("dns resolver domain: ", host, " to ", ip_info.address)
return ip_info.address
else
return nil, "failed to parse domain"
end
end
_M.parse_domain = parse_domain


local function parse_domain_for_nodes(nodes)
Expand All @@ -180,7 +154,7 @@ local function parse_domain_for_nodes(nodes)
local host = node.host
if not ipmatcher.parse_ipv4(host) and
not ipmatcher.parse_ipv6(host) then
local ip, err = parse_domain(host)
local ip, err = core.resolver.parse_domain(host)
if ip then
local new_node = core.table.clone(node)
new_node.host = ip
Expand Down
42 changes: 41 additions & 1 deletion apisix/patch.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
-- limitations under the License.
--
local require = require
local ipmatcher = require("resty.ipmatcher")
local socket = require("socket")
local unix_socket = require("socket.unix")
local ssl = require("ssl")
Expand Down Expand Up @@ -45,6 +46,45 @@ local function get_local_conf()
end


local patch_tcp_socket
do
local old_tcp_sock_connect

local function new_tcp_sock_connect(sock, host, port, opts)
local core_str = require("apisix.core.string")
local resolver = require("apisix.core.resolver")

if host then
if core_str.has_prefix(host, "unix:") then
if not opts then
-- workaround for https://github.com/openresty/lua-nginx-module/issues/860
return old_tcp_sock_connect(sock, host)
end

elseif not ipmatcher.parse_ipv4(host) and not ipmatcher.parse_ipv6(host) then
local err
host, err = resolver.parse_domain(host)
if not host then
return nil, "failed to parse domain: " .. err
end
end
end

return old_tcp_sock_connect(sock, host, port, opts)
end


function patch_tcp_socket(sock)
if not old_tcp_sock_connect then
old_tcp_sock_connect = sock.connect
end

sock.connect = new_tcp_sock_connect
return sock
end
end


local function flatten(args)
local buf = new_tab(#args, 0)
for i, v in ipairs(args) do
Expand Down Expand Up @@ -255,7 +295,7 @@ function _M.patch()
ngx_socket.tcp = function ()
local phase = get_phase()
if phase ~= "init" and phase ~= "init_worker" then
return original_tcp()
return patch_tcp_socket(original_tcp())
end

return luasocket_tcp()
Expand Down
3 changes: 1 addition & 2 deletions apisix/plugins/traffic-split.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
local core = require("apisix.core")
local upstream = require("apisix.upstream")
local schema_def = require("apisix.schema_def")
local init = require("apisix.init")
local roundrobin = require("resty.roundrobin")
local ipmatcher = require("resty.ipmatcher")
local expr = require("resty.expr.v1")
Expand Down Expand Up @@ -130,7 +129,7 @@ local function parse_domain_for_node(node)
if not ipmatcher.parse_ipv4(node)
and not ipmatcher.parse_ipv6(node)
then
local ip, err = init.parse_domain(node)
local ip, err = core.resolver.parse_domain(node)
if ip then
return ip
end
Expand Down
25 changes: 25 additions & 0 deletions t/misc/patch.t
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,28 @@ end
}
--- error_log
failed to read: timeout



=== TEST 4: resolve host by ourselves
--- yaml_config
apisix:
node_listen: 1984
enable_resolv_search_opt: true
--- config
location /t {
content_by_lua_block {
local http = require("resty.http")
local httpc = http.new()
local res, err = httpc:request_uri("http://apisix")
if not res then
ngx.log(ngx.ERR, err)
return
end
ngx.say(res.status)
}
}
--- request
GET /t
--- response_body
301
4 changes: 2 additions & 2 deletions t/node/route-domain-with-local-dns.t
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ GET /t
--- response_body
passed
--- error_log eval
qr/.*parse_args\(\): dns resolver\[.+\]/
qr/.*init_resolver\(\): dns resolver \[.+\]/
--- no_error_log
[error]

Expand All @@ -75,7 +75,7 @@ GET /not_found
--- response_body
{"error_msg":"404 Route Not Found"}
--- error_log eval
qr/.*parse_args\(\): dns resolver\[.+\]/
qr/.*init_resolver\(\): dns resolver \[.+\]/
--- no_error_log
[error]

Expand Down